From 3b146fa41277b05876ed0ba4c29071533a0cbb59 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Sep 2024 05:08:22 +0800 Subject: [PATCH 001/425] toolchain: GCC 15-20240901 Snapshot * This snapshot has been generated from the GCC 15 git branch with the following options: git://gcc.gnu.org/git/gcc.git branch master revision 592a335de563a3a9e36d362c5b9f3fb0a990c1d8 Signed-off-by: sbwml --- .../generic/202-toolchain-gcc-add-support-for-GCC-15.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch index f3c4f555e..8779b1f84 100644 --- a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -55,7 +55,7 @@ index f5db99f..24c6535 100644 endif +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=1be70eb828b6a0e8e6292e4a0ba27a5e8b5c920c5d5aa5ec88d7c3a53a2e398f ++ PKG_HASH:=4633621d7edc84b5e13c02c0d5f78a098e612321581b098319486b768055c7d9 +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x From e8f48de7c4a989ca5b0ec0797b7dbecedfd7a562 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Sep 2024 12:45:44 +0800 Subject: [PATCH 002/425] luci-app-firewall: refresh patches Signed-off-by: sbwml --- ...-add-nft-fullcone-and-bcm-fullcone-.patch} | 16 ++++- ...-app-firewall-add-shortcut-fe-option.patch | 65 +++++++++++++++++++ ...ci-app-firewall-add-ipv6-nat-option.patch} | 15 +++++ ...irewall-add-custom-nft-rule-support.patch} | 21 ++++++ ...02-luci-app-firewall_add_shortcut-fe.patch | 34 ---------- openwrt/scripts/00-prepare_base.sh | 8 +-- 6 files changed, 120 insertions(+), 39 deletions(-) rename openwrt/patch/firewall4/{01-luci-app-firewall_add_nft-fullcone-bcm-fullcone_option.patch => 0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch} (69%) create mode 100644 openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch rename openwrt/patch/firewall4/{03-luci-app-firewall_add_ipv6-nat.patch => 0003-luci-app-firewall-add-ipv6-nat-option.patch} (52%) rename openwrt/patch/firewall4/{04-luci-add-firewall4-nft-rules-file.patch => 0004-luci-add-firewall-add-custom-nft-rule-support.patch} (68%) delete mode 100644 openwrt/patch/firewall4/02-luci-app-firewall_add_shortcut-fe.patch diff --git a/openwrt/patch/firewall4/01-luci-app-firewall_add_nft-fullcone-bcm-fullcone_option.patch b/openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch similarity index 69% rename from openwrt/patch/firewall4/01-luci-app-firewall_add_nft-fullcone-bcm-fullcone_option.patch rename to openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch index 71452b080..1bfa53370 100644 --- a/openwrt/patch/firewall4/01-luci-app-firewall_add_nft-fullcone-bcm-fullcone_option.patch +++ b/openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch @@ -1,5 +1,16 @@ +From 9bb3e0985634cd5bf7551d5f21a0ebc081af2599 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 4 Sep 2024 12:22:05 +0800 +Subject: [PATCH 1/4] luci-app-firewall: add nft-fullcone and bcm-fullcone + option + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/zones.js | 9 +++++++++ + 1 file changed, 9 insertions(+) + diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 1de98c2..ac72083 100644 +index 1de98c2045..ac720831ef 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -58,6 +58,15 @@ return view.extend({ @@ -18,3 +29,6 @@ index 1de98c2..ac72083 100644 var p = [ s.option(form.ListValue, 'input', _('Input')), s.option(form.ListValue, 'output', _('Output')), +-- +2.43.5 + diff --git a/openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch new file mode 100644 index 000000000..91e49bcbc --- /dev/null +++ b/openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch @@ -0,0 +1,65 @@ +From e62768ea9de7fcf554bce7ba8ed2e1f301863006 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 4 Sep 2024 12:34:17 +0800 +Subject: [PATCH 2/4] luci-app-firewall: add shortcut-fe option + +Signed-off-by: sbwml +--- + .../resources/view/firewall/zones.js | 34 +++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index ac720831ef..f7c64e4379 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -100,6 +100,21 @@ return view.extend({ + o.depends('flow_offloading', '1'); + } + ++ /* Shortcut-FE flow offload support */ ++ if (L.hasSystemFeature('shortcutfe')) { ++ o = s.option(form.Flag, 'shortcut_fe', ++ _('Shortcut-FE flow offloading'), ++ _('Shortcut-FE based offloading for routing/NAT')); ++ o.optional = true; ++ ++ o = s.option(form.ListValue, 'shortcut_fe_module', ++ _('Connection Manager'), ++ _('Set up the Shortcut-FE engine connection manager')); ++ o.value('shortcut-fe-cm', _('shortcut-fe-cm')); ++ o.value('fast-classifier', _('fast-classifier')); ++ o.default = 'shortcut-fe-cm'; ++ o.depends('shortcut_fe', '1'); ++ } + + s = m.section(form.GridSection, 'zone', _('Zones')); + s.addremove = true; +@@ -393,6 +408,25 @@ return view.extend({ + o.filter = out.filter; + o.cfgvalue = out.cfgvalue; + ++ setTimeout(function() { ++ const checkboxes = document.querySelectorAll('.cbi-checkbox input[type="checkbox"]'); ++ checkboxes.forEach((checkbox) => { ++ const widgetId = checkbox.getAttribute('data-widget-id'); ++ if ((widgetId.includes('flow_offloading') && !widgetId.includes('flow_offloading_hw')) || widgetId.includes('shortcut_fe')) { ++ checkbox.addEventListener('change', function() { ++ if (this.checked) { ++ checkboxes.forEach((cb) => { ++ if (cb !== this && (cb.getAttribute('data-widget-id').includes('flow_offloading') || ++ cb.getAttribute('data-widget-id').includes('shortcut_fe'))) { ++ cb.checked = false; ++ } ++ }); ++ } ++ }); ++ } ++ }); ++ }, 500); ++ + return m.render(); + } + }); +-- +2.43.5 + diff --git a/openwrt/patch/firewall4/03-luci-app-firewall_add_ipv6-nat.patch b/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch similarity index 52% rename from openwrt/patch/firewall4/03-luci-app-firewall_add_ipv6-nat.patch rename to openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch index 5579cbca3..d9263c6e9 100644 --- a/openwrt/patch/firewall4/03-luci-app-firewall_add_ipv6-nat.patch +++ b/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch @@ -1,3 +1,15 @@ +From 6379d22fb3c4dba52078dfbf44c0f2b8315c0ccf Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 4 Sep 2024 12:35:13 +0800 +Subject: [PATCH 3/4] luci-app-firewall: add ipv6 nat option + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/zones.js | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index f7c64e4379..1bedd2ce52 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -67,6 +67,12 @@ return view.extend({ @@ -13,3 +25,6 @@ var p = [ s.option(form.ListValue, 'input', _('Input')), s.option(form.ListValue, 'output', _('Output')), +-- +2.43.5 + diff --git a/openwrt/patch/firewall4/04-luci-add-firewall4-nft-rules-file.patch b/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch similarity index 68% rename from openwrt/patch/firewall4/04-luci-add-firewall4-nft-rules-file.patch rename to openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch index ebbbd05bd..b20e70ce0 100644 --- a/openwrt/patch/firewall4/04-luci-add-firewall4-nft-rules-file.patch +++ b/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch @@ -1,3 +1,17 @@ +From 0a71614b1690e60048b2f5c5ff672a68f5fd7478 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 4 Sep 2024 12:36:11 +0800 +Subject: [PATCH 4/4] luci-add-firewall: add custom nft rule support + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/custom.js | 6 +++--- + .../root/usr/share/luci/menu.d/luci-app-firewall.json | 3 --- + .../root/usr/share/rpcd/acl.d/luci-app-firewall.json | 6 ++++-- + 3 files changed, 7 insertions(+), 8 deletions(-) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js +index 1997a720c6..b3183d67d6 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js @@ -5,13 +5,13 @@ @@ -25,6 +39,8 @@ E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 25 }, [ fwuser != null ? fwuser : '' ])) ]); }, +diff --git a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json +index f024dcfe25..8aea702c53 100644 --- a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json +++ b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json @@ -64,9 +64,6 @@ @@ -37,6 +53,8 @@ } } } +diff --git a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json +index 17d1fbab12..7e06de7022 100644 --- a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json +++ b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json @@ -3,7 +3,8 @@ @@ -59,3 +77,6 @@ }, "ubus": { "file": [ "write" ] +-- +2.43.5 + diff --git a/openwrt/patch/firewall4/02-luci-app-firewall_add_shortcut-fe.patch b/openwrt/patch/firewall4/02-luci-app-firewall_add_shortcut-fe.patch deleted file mode 100644 index 759e37c3d..000000000 --- a/openwrt/patch/firewall4/02-luci-app-firewall_add_shortcut-fe.patch +++ /dev/null @@ -1,34 +0,0 @@ ---- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -+++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -91,7 +91,7 @@ return view.extend({ - o = s.option(form.Flag, 'flow_offloading', - _('Software flow offloading'), - _('Software based offloading for routing/NAT')); -- o.optional = true; -+ o.optional = false; - - o = s.option(form.Flag, 'flow_offloading_hw', - _('Hardware flow offloading'), -@@ -100,6 +100,22 @@ return view.extend({ - o.depends('flow_offloading', '1'); - } - -+ /* Shortcut-FE flow offload support */ -+ if (L.hasSystemFeature('shortcutfe')) { -+ o = s.option(form.Flag, 'shortcut_fe', -+ _('Shortcut-FE flow offloading'), -+ _('Shortcut-FE based offloading for routing/NAT')); -+ o.optional = true; -+ o.depends('flow_offloading', '0'); -+ -+ o = s.option(form.ListValue, 'shortcut_fe_module', -+ _('Connection Manager'), -+ _('Set up the Shortcut-FE engine connection manager')); -+ o.value('shortcut-fe-cm', _('shortcut-fe-cm')); -+ o.value('fast-classifier', _('fast-classifier')); -+ o.modalonly = true; -+ o.depends('shortcut_fe', '1'); -+ } - - s = m.section(form.GridSection, 'zone', _('Zones')); - s.addremove = true; diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 2685bdf23..844043456 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -200,10 +200,10 @@ git clone https://$github/sbwml/packages_new_nat6 package/new/nat6 # Patch Luci add nft_fullcone/bcm_fullcone & shortcut-fe & ipv6-nat & custom nft command option pushd feeds/luci - curl -s https://$mirror/openwrt/patch/firewall4/01-luci-app-firewall_add_nft-fullcone-bcm-fullcone_option.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/02-luci-app-firewall_add_shortcut-fe.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/03-luci-app-firewall_add_ipv6-nat.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/04-luci-add-firewall4-nft-rules-file.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 popd # openssl - quictls From 303a0dda8bfebfa63349615f62a3b472b65018c8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Sep 2024 12:51:24 +0800 Subject: [PATCH 003/425] openssl: quic: refresh patches Signed-off-by: sbwml --- .../openssl/quic/0044-QUIC-Update-metadata-version.patch | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch b/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch index c2528104d..33aaf0d00 100644 --- a/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch +++ b/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch @@ -1,10 +1,5 @@ --- a/VERSION.dat +++ b/VERSION.dat -@@ -2,6 +2,6 @@ MAJOR=3 - MINOR=0 - PATCH=14 - PRE_RELEASE_TAG= +@@ -5,1 +5,1 @@ -BUILD_METADATA= +BUILD_METADATA=quic - RELEASE_DATE="4 Jun 2024" - SHLIB_VERSION=3 From e03c030890950a2308f504c85deb563037260021 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 7 Sep 2024 22:35:29 +0800 Subject: [PATCH 004/425] r8500: hotplug.d: add usb-reset action Signed-off-by: sbwml --- openwrt/files/etc/hotplug.d/block/20-usbreset | 18 ++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 4 ++++ 2 files changed, 22 insertions(+) create mode 100644 openwrt/files/etc/hotplug.d/block/20-usbreset diff --git a/openwrt/files/etc/hotplug.d/block/20-usbreset b/openwrt/files/etc/hotplug.d/block/20-usbreset new file mode 100644 index 000000000..9bdfc3666 --- /dev/null +++ b/openwrt/files/etc/hotplug.d/block/20-usbreset @@ -0,0 +1,18 @@ +#!/bin/sh + +device=`basename $DEVPATH` +point=$device + +case "$ACTION" in + add) + mkdir -p /usb/$point + mount -o rw,noatime,discard /dev/$device /usb/$point + if [ -f "/usb/$point/recovery.txt" ]; then + echo y | firstboot + sleep 2 + reboot + else + umount -l /usb/$point + fi + ;; +esac diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 844043456..ea39acf80 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -442,6 +442,10 @@ curl -so files/root/.bashrc https://$mirror/openwrt/files/root/.bashrc mkdir -p files/etc/sysctl.d curl -so files/etc/sysctl.d/15-vm-swappiness.conf https://$mirror/openwrt/files/etc/sysctl.d/15-vm-swappiness.conf curl -so files/etc/sysctl.d/16-udp-buffer-size.conf https://$mirror/openwrt/files/etc/sysctl.d/16-udp-buffer-size.conf +if [ "$platform" = "bcm53xx" ]; then + mkdir -p files/etc/hotplug.d/block + curl -so files/etc/hotplug.d/block/20-usbreset https://$mirror/openwrt/files/etc/hotplug.d/block/20-usbreset +fi # NTP sed -i 's/0.openwrt.pool.ntp.org/ntp1.aliyun.com/g' package/base-files/files/bin/config_generate From d0752acb5da56a06e49b966c41f952b98afa8cf4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Sep 2024 03:56:49 +0800 Subject: [PATCH 005/425] linux-6.6: bump to 6.6.49 Signed-off-by: sbwml --- tags/kernel-6.6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index 5fbb10e05..511218f43 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .48 -LINUX_KERNEL_HASH-6.6.48 = 6b16df7b2aba3116b78fdfd8aea0b6cd7abe8f0cb699b04a66d3169141772029 +LINUX_VERSION-6.6 = .49 +LINUX_KERNEL_HASH-6.6.49 = 2c56dac2b70859c16b4ef651befb0d28c227498bd3eee08e8a45a357f22dd3b7 From ddfa1536fecac0bb5bcd7a7798cea85464d4f91c Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Sep 2024 03:57:21 +0800 Subject: [PATCH 006/425] build: add natflow based offloading for routing/NAT Signed-off-by: sbwml --- openwrt/23-config-common | 3 + openwrt/23-config-musl-r8500 | 3 + openwrt/build.sh | 4 ++ ...firewall-add-natflow-offload-support.patch | 55 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 6 +- 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 76fda3a5a..0838918ee 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -21,6 +21,9 @@ CONFIG_PACKAGE_iptables-nft=y CONFIG_PACKAGE_xtables-nft=y # CONFIG_PACKAGE_iptables-legacy is not set +# Natflow +CONFIG_PACKAGE_natflow=m + # SFE CONFIG_PACKAGE_kmod-fast-classifier=y CONFIG_PACKAGE_kmod-shortcut-fe-cm=y diff --git a/openwrt/23-config-musl-r8500 b/openwrt/23-config-musl-r8500 index e36ad1fd9..6838fc991 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/23-config-musl-r8500 @@ -37,6 +37,9 @@ CONFIG_PACKAGE_iptables-nft=y CONFIG_PACKAGE_xtables-nft=y # CONFIG_PACKAGE_iptables-legacy is not set +# Natflow +CONFIG_PACKAGE_natflow=m + # SFE CONFIG_PACKAGE_kmod-fast-classifier=y CONFIG_PACKAGE_kmod-shortcut-fe-cm=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 31054a08f..ba771bfd8 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -458,6 +458,7 @@ if [ "$platform" = "x86_64" ]; then rm -f $kmodpkg_name/Packages* # driver firmware cp -a bin/packages/x86_64/base/*firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/*natflow*.ipk $kmodpkg_name/ bash kmod-sign $kmodpkg_name tar zcf x86_64-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -496,6 +497,7 @@ elif [ "$platform" = "armv8" ]; then rm -f $kmodpkg_name/Packages* # driver firmware cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ bash kmod-sign $kmodpkg_name tar zcf armv8-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -524,6 +526,7 @@ elif [ "$platform" = "bcm53xx" ]; then rm -f $kmodpkg_name/Packages* # driver firmware cp -a bin/packages/arm_cortex-a9/base/*firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/*natflow*.ipk $kmodpkg_name/ bash kmod-sign $kmodpkg_name tar zcf bcm53xx-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -557,6 +560,7 @@ else rm -f $kmodpkg_name/Packages* # driver firmware cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ bash kmod-sign $kmodpkg_name tar zcf aarch64-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name diff --git a/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch new file mode 100644 index 000000000..c1bda2323 --- /dev/null +++ b/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch @@ -0,0 +1,55 @@ +From 518eadc602c8e61621c8c1091585a134d978d596 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 8 Sep 2024 03:40:30 +0800 +Subject: [PATCH] luci-app-firewall: add natflow offload support + +Signed-off-by: sbwml +--- + .../resources/view/firewall/zones.js | 20 +++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index 1bedd2c..522d001 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -122,6 +122,21 @@ return view.extend({ + o.depends('shortcut_fe', '1'); + } + ++ /* Natflow offload support */ ++ if (L.hasSystemFeature('natflow')) { ++ o = s.option(form.Flag, 'natflow', ++ _('Natflow offloading'), ++ _('Natflow based offloading for routing/NAT')); ++ o.optional = true; ++ ++ o = s.option(form.Value, 'natflow_delay_pkts', ++ _('Natflow delay packet'), ++ _('Set up the natflow delay packet')); ++ o.datatype = 'and(uinteger,min(0))'; ++ o.default = 0; ++ o.depends('natflow', '1'); ++ } ++ + s = m.section(form.GridSection, 'zone', _('Zones')); + s.addremove = true; + s.anonymous = true; +@@ -418,12 +433,13 @@ return view.extend({ + const checkboxes = document.querySelectorAll('.cbi-checkbox input[type="checkbox"]'); + checkboxes.forEach((checkbox) => { + const widgetId = checkbox.getAttribute('data-widget-id'); +- if ((widgetId.includes('flow_offloading') && !widgetId.includes('flow_offloading_hw')) || widgetId.includes('shortcut_fe')) { ++ if ((widgetId.includes('flow_offloading') && !widgetId.includes('flow_offloading_hw')) || widgetId.includes('shortcut_fe') || widgetId.includes('natflow')) { + checkbox.addEventListener('change', function() { + if (this.checked) { + checkboxes.forEach((cb) => { + if (cb !== this && (cb.getAttribute('data-widget-id').includes('flow_offloading') || +- cb.getAttribute('data-widget-id').includes('shortcut_fe'))) { ++ cb.getAttribute('data-widget-id').includes('shortcut_fe') || ++ cb.getAttribute('data-widget-id').includes('natflow'))) { + cb.checked = false; + } + }); +-- +2.42.0 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index ea39acf80..aa8f53e26 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -198,12 +198,16 @@ git clone https://$gitea/sbwml/nft-fullcone package/new/nft-fullcone # IPv6 NAT git clone https://$github/sbwml/packages_new_nat6 package/new/nat6 -# Patch Luci add nft_fullcone/bcm_fullcone & shortcut-fe & ipv6-nat & custom nft command option +# natflow +git clone https://$github/sbwml/package_new_natflow package/new/natflow + +# Patch Luci add nft_fullcone/bcm_fullcone & shortcut-fe & natflow & ipv6-nat & custom nft command option pushd feeds/luci curl -s https://$mirror/openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 popd # openssl - quictls From faa8956f8a5bae18fdf34d937680d37bdfc49dc4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 9 Sep 2024 07:03:12 +0800 Subject: [PATCH 007/425] linux-6.6: bump to 6.6.50 Signed-off-by: sbwml --- tags/kernel-6.6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index 511218f43..1f0bd75a0 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .49 -LINUX_KERNEL_HASH-6.6.49 = 2c56dac2b70859c16b4ef651befb0d28c227498bd3eee08e8a45a357f22dd3b7 +LINUX_VERSION-6.6 = .50 +LINUX_KERNEL_HASH-6.6.50 = c065e36daf28210060c91a37ef3e92ac5814784e634577e04e406297ead2e86e From a6339a39b164978fd24929a6da7752e9a2229a8f Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 9 Sep 2024 07:03:50 +0800 Subject: [PATCH 008/425] samba4: update to 4.21.0 Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index e78a0cf92..be5178bd1 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -52,6 +52,9 @@ curl -s https://$mirror/openwrt/patch/luci/applications/002-luci-app-frpc-add-en # samba4 - bump version rm -rf feeds/packages/net/samba4 git clone https://$github/sbwml/feeds_packages_net_samba4 feeds/packages/net/samba4 +# liburing - 2.7 (samba-4.21.0) +rm -rf feeds/packages/libs/liburing +git clone https://$github/sbwml/feeds_packages_libs_liburing feeds/packages/libs/liburing # enable multi-channel sed -i '/workgroup/a \\n\t## enable multi-channel' feeds/packages/net/samba4/files/smb.conf.template sed -i '/enable multi-channel/a \\tserver multi channel support = yes' feeds/packages/net/samba4/files/smb.conf.template From c80d20c401be88780a099aa58d5baa23aa2d8150 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 11 Sep 2024 03:14:30 +0800 Subject: [PATCH 009/425] lrzsz: stop hack build for gcc14 Signed-off-by: sbwml --- .../gcc-14/lrzsz/900-lrzsz-fix-gcc14.patch | 11 ----------- openwrt/scripts/05-fix-source.sh | 3 --- 2 files changed, 14 deletions(-) delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/lrzsz/900-lrzsz-fix-gcc14.patch diff --git a/openwrt/patch/openwrt-6.x/gcc-14/lrzsz/900-lrzsz-fix-gcc14.patch b/openwrt/patch/openwrt-6.x/gcc-14/lrzsz/900-lrzsz-fix-gcc14.patch deleted file mode 100644 index b8a1646ca..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/lrzsz/900-lrzsz-fix-gcc14.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/configure -+++ b/configure -@@ -1026,7 +1026,7 @@ fi - rm -fr conftest* - - echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 --if test $ac_cv_prog_cc_works = no; then -+if test $ac_cv_prog_cc_works = null; then - { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } - fi - echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index efc68b51f..b36134b71 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -30,9 +30,6 @@ if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then # libunwind rm -rf package/libs/libunwind git clone https://$github/sbwml/package_libs_libunwind package/libs/libunwind - # lrzsz - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/lrzsz/900-lrzsz-fix-gcc14.patch > package/new/lrzsz/patches/900-lrzsz-fix-gcc14.patch - sed -i '/lrzsz\/install/iTARGET_CFLAGS += -Wno-implicit-function-declaration -Wno-builtin-declaration-mismatch -Wno-incompatible-pointer-types' package/new/lrzsz/Makefile # mbedtls curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch > package/libs/mbedtls/patches/900-tests-fix-calloc-argument-list-gcc-14-fix.patch # linux-atm From cd4eab510acbce0e71fa10aa0d1d96dfa9039703 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 06:37:01 +0800 Subject: [PATCH 010/425] linux-6.6: bump to 6.6.51 Signed-off-by: sbwml --- ...net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch | 2 +- tags/kernel-6.6 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 1398222ab..949a1d99f 100644 --- a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -43,7 +43,7 @@ Signed-off-by: Alexandre Frade /* Clean up fastopen related fields */ --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c -@@ -241,6 +241,7 @@ void tcp_init_congestion_control(struct +@@ -240,6 +240,7 @@ void tcp_init_congestion_control(struct struct inet_connection_sock *icsk = inet_csk(sk); tcp_sk(sk)->prior_ssthresh = 0; diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index 1f0bd75a0..485ec8eef 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .50 -LINUX_KERNEL_HASH-6.6.50 = c065e36daf28210060c91a37ef3e92ac5814784e634577e04e406297ead2e86e +LINUX_VERSION-6.6 = .51 +LINUX_KERNEL_HASH-6.6.51 = 1c0c9a14650879c4913efdbac428ba31a540c3d987155ddf34d33e11eca008b3 From db40830210c327ad59e8f67d67d1af50db20856f Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 06:37:50 +0800 Subject: [PATCH 011/425] build.sh: update ghproxy for CN Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index ba771bfd8..51c40b712 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -45,7 +45,7 @@ export gitea=git.cooluc.com # github mirror if [ "$isCN" = "CN" ]; then - export github="github.com" + export github="ghp.ci/github.com" else export github="github.com" fi From 6a1c311e613122bb69c2da182eb073ca2766703f Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 06:38:36 +0800 Subject: [PATCH 012/425] patch/scripts: update for snapshot build Signed-off-by: sbwml --- .../generic/202-toolchain-gcc-add-support-for-GCC-15.patch | 6 +++--- openwrt/scripts/00-prepare_base.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch index 8779b1f84..5325af227 100644 --- a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -13,7 +13,7 @@ index ca89051..510c813 100644 config GCC_USE_GRAPHITE diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version -index 200a356..5675b9a 100644 +index 7ff5bc0..7d8ee09 100644 --- a/toolchain/gcc/Config.version +++ b/toolchain/gcc/Config.version @@ -10,11 +10,16 @@ config GCC_VERSION_14 @@ -34,7 +34,7 @@ index 200a356..5675b9a 100644 config GCC_USE_DEFAULT_VERSION diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index f5db99f..24c6535 100644 +index a1a5108..7ec50ad 100644 --- a/toolchain/gcc/common.mk +++ b/toolchain/gcc/common.mk @@ -26,7 +26,11 @@ PKG_VERSION:=$(firstword $(subst +, ,$(GCC_VERSION))) @@ -51,7 +51,7 @@ index f5db99f..24c6535 100644 PKG_CPE_ID:=cpe:/a:gnu:gcc @@ -46,6 +50,10 @@ ifeq ($(PKG_VERSION),14.2.0) - PKG_HASH:=e283c654987afe3de9d8080bc0bd79534b5ca0d681a73a11ff2b5d3767426840 + PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 endif +ifeq ($(PKG_VERSION),15.0.0) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index aa8f53e26..bf042b1f6 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -67,6 +67,7 @@ if [ "$ENABLE_UHTTPD" != "y" ]; then fi # Realtek driver - R8168 & R8125 & R8126 & R8152 & R8101 +rm -rf package/kernel/r8168 package/kernel/r8101 package/kernel/r8125 package/kernel/r8126 git clone https://$github/sbwml/package_kernel_r8168 package/kernel/r8168 git clone https://$github/sbwml/package_kernel_r8152 package/kernel/r8152 git clone https://$github/sbwml/package_kernel_r8101 package/kernel/r8101 From 366b770ccadd1359fcd55a546eed8c5fbcd1983f Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 06:39:52 +0800 Subject: [PATCH 013/425] config: add some necessary packages Signed-off-by: sbwml --- openwrt/23-config-common | 1 + openwrt/23-config-minimal-common | 1 + openwrt/23-config-musl-r8500 | 2 ++ openwrt/23-config-musl-r8500-minimal | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 0838918ee..56b4f2015 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -183,6 +183,7 @@ CONFIG_PACKAGE_kmod-usb-net-rndis=y CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules +CONFIG_PACKAGE_kmod-br-netfilter=y CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y diff --git a/openwrt/23-config-minimal-common b/openwrt/23-config-minimal-common index 1141a46e1..120362d95 100644 --- a/openwrt/23-config-minimal-common +++ b/openwrt/23-config-minimal-common @@ -93,6 +93,7 @@ CONFIG_PACKAGE_kmod-usb-net-rndis=y CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules +CONFIG_PACKAGE_kmod-br-netfilter=y CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y diff --git a/openwrt/23-config-musl-r8500 b/openwrt/23-config-musl-r8500 index 6838fc991..2595ac5dc 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/23-config-musl-r8500 @@ -153,6 +153,7 @@ CONFIG_PACKAGE_kmod-usb-net-rndis=y CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules +CONFIG_PACKAGE_kmod-br-netfilter=y CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y @@ -179,6 +180,7 @@ CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-usb-audio=y CONFIG_PACKAGE_kmod-usb-storage=y +CONFIG_PACKAGE_kmod-usb-storage-uas=y ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/23-config-musl-r8500-minimal b/openwrt/23-config-musl-r8500-minimal index 3b438ea2b..d67704d79 100644 --- a/openwrt/23-config-musl-r8500-minimal +++ b/openwrt/23-config-musl-r8500-minimal @@ -102,6 +102,7 @@ CONFIG_PACKAGE_kmod-usb-net-rndis=y CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules +CONFIG_PACKAGE_kmod-br-netfilter=y CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y @@ -127,12 +128,15 @@ CONFIG_PACKAGE_kmod-tcp-bbr=y CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-usb-storage=y +CONFIG_PACKAGE_kmod-usb-storage-uas=y ### Utilities CONFIG_PACKAGE_bash=y CONFIG_PACKAGE_dmesg=y CONFIG_PACKAGE_ftp=y +CONFIG_PACKAGE_openssh-sftp-server=y CONFIG_PACKAGE_telnet-bsd=y +CONFIG_PACKAGE_usbutils=y CONFIG_PACKAGE_wget-ssl=y CONFIG_PACKAGE_wpad-openssl=y From a803b9e8a7b762d489f4ab0ad996259c77c172df Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 15:53:57 +0800 Subject: [PATCH 014/425] r8500: usbreset: filter mtd and ubi partitions Signed-off-by: sbwml --- openwrt/files/etc/hotplug.d/block/20-usbreset | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/openwrt/files/etc/hotplug.d/block/20-usbreset b/openwrt/files/etc/hotplug.d/block/20-usbreset index 9bdfc3666..f7a051dfa 100644 --- a/openwrt/files/etc/hotplug.d/block/20-usbreset +++ b/openwrt/files/etc/hotplug.d/block/20-usbreset @@ -1,18 +1,24 @@ #!/bin/sh device=`basename $DEVPATH` -point=$device + +case $device in + mtdblock*|ubiblock*|zram*) + exit 0 + ;; +esac case "$ACTION" in add) - mkdir -p /usb/$point - mount -o rw,noatime,discard /dev/$device /usb/$point - if [ -f "/usb/$point/recovery.txt" ]; then + mkdir -p /usb/$device + mount -o rw,noatime,discard /dev/$device /usb/$device + if [ -f "/usb/$device/recovery.txt" ]; then echo y | firstboot sleep 2 reboot else - umount -l /usb/$point + umount -l /usb/$device + rm -rf /usb fi ;; esac From 49dddd88784152d4e26c7a15ce65b852b4c16587 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 20:04:10 +0800 Subject: [PATCH 015/425] luci-mod-system: add modal overlay dialog to reboot Signed-off-by: sbwml --- README.md | 5 ++- ...m-add-modal-overlay-dialog-to-reboot.patch | 45 +++++++++++++++++++ ...isplays-actual-process-memory-usage.patch} | 13 ++++++ ...torage-index-applicable-only-to-val.patch} | 8 +++- ...irewall-disable-legacy-firewall-rul.patch} | 17 ++++++- ...system-add-refresh-interval-setting.patch} | 13 ++++++ openwrt/scripts/00-prepare_base.sh | 11 ++--- 7 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch rename openwrt/patch/luci/{20_memory.js.patch => 0002-luci-mod-status-displays-actual-process-memory-usage.patch} (72%) rename openwrt/patch/luci/{luci-mod-status-storage-index-applicable-only-to-val.patch => 0003-luci-mod-status-storage-index-applicable-only-to-val.patch} (73%) rename openwrt/patch/luci/{luci-nftables.patch => 0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch} (81%) rename openwrt/patch/luci/{luci-refresh-interval.patch => 0005-luci-mod-system-add-refresh-interval-setting.patch} (68%) diff --git a/README.md b/README.md index 2f447b4c0..834294a5c 100644 --- a/README.md +++ b/README.md @@ -241,10 +241,11 @@ bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_scri ### 一、Fork 本仓库到自己 GitHub 存储库 ### 二、构建固件 -- 在存储库名称下,单击(Actions Actions)。 + +- 在存储库名称下,单击(Actions Actions)。 - 在左侧边栏中,单击要运行的工作流的名称:**Build releases**。 - 在工作流运行的列表上方,单击“**Run workflow**”按钮,选择要构建的设备固件并运行工作流。 - ![image](https://github.com/sbwml/r4s_build_script/assets/16485166/136abcd1-ecf3-4e6d-aa1a-5393a75a25cc) + ![image](https://github.com/user-attachments/assets/0c2eb064-a130-47b3-a5a3-1e9a9bb6f50d) diff --git a/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch b/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch new file mode 100644 index 000000000..d6e1bba53 --- /dev/null +++ b/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch @@ -0,0 +1,45 @@ +From 0c1f0e62e72e4c89b0db25aa6f6baa19c7e91e75 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 13 Sep 2024 19:36:44 +0800 +Subject: [PATCH 1/5] luci-mod-system: add modal overlay dialog to reboot + +Signed-off-by: sbwml +--- + .../resources/view/system/reboot.js | 21 ++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js +index 92e1dd4..c106f78 100644 +--- a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js ++++ b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js +@@ -30,7 +30,26 @@ return view.extend({ + body.appendChild(E('hr')); + body.appendChild(E('button', { + 'class': 'cbi-button cbi-button-action important', +- 'click': ui.createHandlerFn(this, 'handleReboot') ++ 'click': function () { ++ ui.showModal(_('Confirm Reboot'), [ ++ E('p', {}, _('Are you sure you want to reboot the system?')), ++ E('button', { ++ 'class': 'cbi-button cbi-button-action important', ++ 'style': 'margin-left: 0px; background: red!important; border-color: red!important', ++ 'click': function () { ++ ui.hideModal(); ++ this.handleReboot(); ++ }.bind(this) ++ }, _('Confirm')), ++ E('button', { ++ 'class': 'btn cbi-button cbi-button-apply', ++ 'style': 'margin-left: 20px', ++ 'click': function () { ++ ui.hideModal(); ++ } ++ }, _('Cancel')) ++ ]); ++ }.bind(this) + }, _('Perform reboot'))); + + return body; +-- +2.42.0 + diff --git a/openwrt/patch/luci/20_memory.js.patch b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch similarity index 72% rename from openwrt/patch/luci/20_memory.js.patch rename to openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch index ce161da8e..776455541 100644 --- a/openwrt/patch/luci/20_memory.js.patch +++ b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch @@ -1,3 +1,13 @@ +From fb9d1a301136922a624e1eb2927ad60260ee11f8 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 13 Sep 2024 19:43:19 +0800 +Subject: [PATCH 2/5] luci-mod-status: displays actual process memory usage + +Signed-off-by: sbwml +--- + .../luci-static/resources/view/status/include/20_memory.js | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js index 0a885c0..d3302ff 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js @@ -13,3 +23,6 @@ index 0a885c0..d3302ff 100644 ]; if (mem.buffered) +-- +2.42.0 + diff --git a/openwrt/patch/luci/luci-mod-status-storage-index-applicable-only-to-val.patch b/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch similarity index 73% rename from openwrt/patch/luci/luci-mod-status-storage-index-applicable-only-to-val.patch rename to openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch index 25f29413f..915aa8512 100644 --- a/openwrt/patch/luci/luci-mod-status-storage-index-applicable-only-to-val.patch +++ b/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch @@ -1,7 +1,7 @@ -From 8a052b2e2ffd2e6a46fe361a946b1acd42998402 Mon Sep 17 00:00:00 2001 +From 2543713322fa4f7b404a673429ce36f4319c4749 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 24 Mar 2024 00:12:45 +0800 -Subject: [PATCH] luci-mod-status: storage index applicable only to valid +Subject: [PATCH 3/5] luci-mod-status: storage index applicable only to valid devices Signed-off-by: sbwml @@ -9,6 +9,8 @@ Signed-off-by: sbwml .../luci-static/resources/view/status/include/25_storage.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) +diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js +index 60661f6..aac6711 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js @@ -13,12 +13,14 @@ var callMountPoints = rpc.declare({ @@ -36,4 +38,6 @@ Signed-off-by: sbwml continue; var name = entry.device + ' (' + entry.mount +')', +-- +2.42.0 diff --git a/openwrt/patch/luci/luci-nftables.patch b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch similarity index 81% rename from openwrt/patch/luci/luci-nftables.patch rename to openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch index 694151a8f..18b40b8ff 100644 --- a/openwrt/patch/luci/luci-nftables.patch +++ b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch @@ -1,5 +1,17 @@ +From 44cb42a004b8334d784814c5f616c8d8ceda6b22 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 13 Sep 2024 19:44:52 +0800 +Subject: [PATCH 4/5] luci-mod-status: firewall: disable legacy firewall rule + warning + +Signed-off-by: sbwml +--- + .../resources/view/status/nftables.js | 14 -------------- + .../share/luci/menu.d/luci-mod-status.json | 19 ++++++++++++++++--- + 2 files changed, 16 insertions(+), 17 deletions(-) + diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -index d891526..04fd5af 100644 +index be62d91..1718494 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js @@ -672,26 +672,12 @@ return view.extend({ @@ -70,3 +82,6 @@ index 190eef0..e9cf485 100644 "action": { "type": "view", "path": "status/iptables" +-- +2.42.0 + diff --git a/openwrt/patch/luci/luci-refresh-interval.patch b/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch similarity index 68% rename from openwrt/patch/luci/luci-refresh-interval.patch rename to openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch index 32ef96cf8..fec459d9c 100644 --- a/openwrt/patch/luci/luci-refresh-interval.patch +++ b/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch @@ -1,3 +1,13 @@ +From 8596f6d48c24c063fd75f007b8e24cd011ac93fb Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 13 Sep 2024 19:47:13 +0800 +Subject: [PATCH 5/5] luci-mod-system: add refresh interval setting + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/system/system.js | 8 ++++++++ + 1 file changed, 8 insertions(+) + diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js index 767bc8c..c8969ac 100644 --- a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js @@ -17,3 +27,6 @@ index 767bc8c..c8969ac 100644 /* * NTP */ +-- +2.42.0 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index bf042b1f6..6f21baf62 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -391,12 +391,13 @@ sed -i 's/cheaper = 1/cheaper = 2/g' feeds/packages/net/uwsgi/files-luci-support sed -i 's/option timeout 30/option timeout 60/g' package/system/rpcd/files/rpcd.config sed -i 's#20) \* 1000#60) \* 1000#g' feeds/luci/modules/luci-base/htdocs/luci-static/resources/rpc.js -# luci - 20_memory & 25_storage & refresh interval +# luci-mod extra pushd feeds/luci - curl -s https://$mirror/openwrt/patch/luci/20_memory.js.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/luci/luci-refresh-interval.patch | patch -p1 - # luci-mod-status: storage index applicable only to valid - curl -s https://$mirror/openwrt/patch/luci/luci-mod-status-storage-index-applicable-only-to-val.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch | patch -p1 popd # Luci diagnostics.js From bb00044b4d7210776ab784dcec00c3b1bbcc10fd Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 15 Sep 2024 03:31:23 +0800 Subject: [PATCH 016/425] openssl: quic: refresh patches for 3.0.15 Signed-off-by: sbwml --- ...-Add-support-for-BoringSSL-QUIC-APIs.patch | 35 +++++++++---------- ...-quic_transport-constructors-parsers.patch | 6 ++-- ...ndle-EndOfEarlyData-and-MaxEarlyData.patch | 4 +-- ...me-cleanup-for-the-main-QUIC-changes.patch | 14 ++++---- ...0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch | 4 +-- .../0022-QUIC-Test-KeyUpdate-rejection.patch | 2 +- ...UIC-add-v1-quic_transport_parameters.patch | 24 ++++++------- .../0031-QUIC-Add-early-data-support.patch | 10 +++--- ...tiple-post-handshake-messages-in-a-s.patch | 4 +-- .../patch/openssl/quic/0034-QUIC-Fix-CI.patch | 6 ++-- .../0037-QUIC-Update-RFC-references.patch | 4 +-- ...-QUIC-use-SSL_IS_QUIC-in-more-places.patch | 2 +- ...-Update-SSL_clear-to-clear-quic-data.patch | 10 +++--- .../quic/0042-QUIC-Better-SSL_clear.patch | 10 +++--- 14 files changed, 67 insertions(+), 68 deletions(-) diff --git a/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch b/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch index 8d54fabc7..9c197f286 100644 --- a/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch +++ b/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch @@ -42,7 +42,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 ssl/statem/statem_quic.c | 106 ++++++++++++ ssl/tls13_enc.c | 59 +++++++ test/helpers/ssltestlib.c | 5 + - test/sslapitest.c | 132 ++++++++++++++ + test/sslapitest.c | 131 ++++++++++++++ test/tls13secretstest.c | 7 + util/libssl.num | 11 ++ util/other.syms | 2 + @@ -53,7 +53,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 --- a/Configure +++ b/Configure -@@ -468,6 +468,7 @@ my @disablables = ( +@@ -467,6 +467,7 @@ my @disablables = ( "poly1305", "posix-io", "psk", @@ -61,7 +61,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 "rc2", "rc4", "rc5", -@@ -636,6 +637,7 @@ my @disable_cascades = ( +@@ -635,6 +636,7 @@ my @disable_cascades = ( "legacy" => [ "md2" ], "cmp" => [ "crmf" ], @@ -645,7 +645,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 if (s->handshake_func == NULL) { ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); return -1; -@@ -3858,6 +3892,11 @@ int SSL_get_error(const SSL *s, int i) +@@ -3875,6 +3909,11 @@ int SSL_get_error(const SSL *s, int i) } if (SSL_want_read(s)) { @@ -657,7 +657,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 bio = SSL_get_rbio(s); if (BIO_should_read(bio)) return SSL_ERROR_WANT_READ; -@@ -4225,7 +4264,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const +@@ -4242,7 +4281,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) { @@ -1023,7 +1023,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 { /* Must be immediately before pre_shared_key */ TLSEXT_TYPE_padding, -@@ -1728,3 +1745,15 @@ static int final_psk(SSL *s, unsigned in +@@ -1722,3 +1739,15 @@ static int final_psk(SSL *s, unsigned in return 1; } @@ -1071,7 +1071,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 /* * Parse the server's renegotiation binding and abort if it's not right */ -@@ -1981,3 +2003,29 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p +@@ -2006,3 +2028,29 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p return 1; } @@ -1103,7 +1103,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 +#endif --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1232,6 +1232,33 @@ int tls_parse_ctos_post_handshake_auth(S +@@ -1237,6 +1237,33 @@ int tls_parse_ctos_post_handshake_auth(S return 1; } @@ -1137,7 +1137,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 /* * Add the server's renegotiation binding */ -@@ -1914,3 +1941,27 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s +@@ -1920,3 +1947,27 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s return EXT_RETURN_SENT; } @@ -1243,7 +1243,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 if (ret <= 0) return -1; if (type == SSL3_RT_HANDSHAKE) -@@ -1169,6 +1183,7 @@ int tls_get_message_header(SSL *s, int * +@@ -1173,6 +1187,7 @@ int tls_get_message_header(SSL *s, int * do { while (s->init_num < SSL3_HM_HEADER_LENGTH) { @@ -1554,10 +1554,10 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 * This will ensure we have received the NewSessionTicket in TLSv1.3 where --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10765,6 +10765,135 @@ static int test_multi_resume(int idx) +@@ -10764,6 +10764,134 @@ static int test_multi_resume(int idx) + SSL_SESSION_free(sess); return testresult; } - +#ifndef OPENSSL_NO_QUIC +static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, @@ -1686,14 +1686,13 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 + return testresult; +} +#endif /* OPENSSL_NO_QUIC */ -+ - OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") - int setup_tests(void) -@@ -11041,6 +11170,9 @@ int setup_tests(void) + static struct next_proto_st { + int serverlen; +@@ -11407,6 +11535,9 @@ int setup_tests(void) + ADD_ALL_TESTS(test_npn, 5); #endif - ADD_ALL_TESTS(test_handshake_retry, 16); - ADD_ALL_TESTS(test_multi_resume, 5); + ADD_ALL_TESTS(test_alpn, 4); +#ifndef OPENSSL_NO_QUIC + ADD_TEST(test_quic_api); +#endif diff --git a/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch b/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch index 667ff9c81..7cccda434 100644 --- a/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch +++ b/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch @@ -23,7 +23,7 @@ Subject: [PATCH 07/43] QUIC: Fix quic_transport constructors/parsers SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } -@@ -2008,19 +2006,11 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p +@@ -2033,19 +2031,11 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -46,7 +46,7 @@ Subject: [PATCH 07/43] QUIC: Fix quic_transport constructors/parsers SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1237,19 +1237,11 @@ int tls_parse_ctos_post_handshake_auth(S +@@ -1242,19 +1242,11 @@ int tls_parse_ctos_post_handshake_auth(S int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -67,7 +67,7 @@ Subject: [PATCH 07/43] QUIC: Fix quic_transport constructors/parsers &s->ext.peer_quic_transport_params, &s->ext.peer_quic_transport_params_len)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -@@ -1954,10 +1946,8 @@ EXT_RETURN tls_construct_stoc_quic_trans +@@ -1960,10 +1952,8 @@ EXT_RETURN tls_construct_stoc_quic_trans } if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) diff --git a/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch b/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch index 9943ad8d1..1c33b23d0 100644 --- a/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch +++ b/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch @@ -12,7 +12,7 @@ Subject: [PATCH 18/43] QUIC: Handle EndOfEarlyData and MaxEarlyData --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c -@@ -1919,6 +1919,17 @@ int tls_parse_stoc_early_data(SSL *s, PA +@@ -1944,6 +1944,17 @@ int tls_parse_stoc_early_data(SSL *s, PA return 0; } @@ -32,7 +32,7 @@ Subject: [PATCH 18/43] QUIC: Handle EndOfEarlyData and MaxEarlyData return 1; --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1890,12 +1890,20 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1896,12 +1896,20 @@ EXT_RETURN tls_construct_stoc_early_data size_t chainidx) { if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) { diff --git a/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch b/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch index fe82fd5cf..ff12006d2 100644 --- a/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch +++ b/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch @@ -179,7 +179,7 @@ Update referenced I-D versions. +#endif --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c -@@ -4264,7 +4264,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const +@@ -4281,7 +4281,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) { @@ -304,7 +304,7 @@ Update referenced I-D versions. -#endif --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c -@@ -1922,7 +1922,7 @@ int tls_parse_stoc_early_data(SSL *s, PA +@@ -1947,7 +1947,7 @@ int tls_parse_stoc_early_data(SSL *s, PA #ifndef OPENSSL_NO_QUIC /* * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION @@ -315,7 +315,7 @@ Update referenced I-D versions. SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1896,7 +1896,7 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1902,7 +1902,7 @@ EXT_RETURN tls_construct_stoc_early_data return EXT_RETURN_NOT_SENT; #ifndef OPENSSL_NO_QUIC @@ -378,7 +378,7 @@ Update referenced I-D versions. } } else #endif -@@ -1183,7 +1190,6 @@ int tls_get_message_header(SSL *s, int * +@@ -1187,7 +1194,6 @@ int tls_get_message_header(SSL *s, int * do { while (s->init_num < SSL3_HM_HEADER_LENGTH) { @@ -598,9 +598,9 @@ Update referenced I-D versions. unsigned char *iv; --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10766,9 +10766,11 @@ static int test_multi_resume(int idx) +@@ -10765,9 +10765,11 @@ static int test_multi_resume(int idx) + return testresult; } - #ifndef OPENSSL_NO_QUIC -static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, +static int test_quic_set_encryption_secrets(SSL *ssl, @@ -612,7 +612,7 @@ Update referenced I-D versions. { test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n", ssl->server ? "server" : "client", level, secret_len); -@@ -10780,11 +10782,12 @@ static int test_quic_add_handshake_data( +@@ -10779,11 +10781,12 @@ static int test_quic_add_handshake_data( { SSL *peer = (SSL*)SSL_get_app_data(ssl); diff --git a/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch b/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch index 37bfbbe0c..931608807 100644 --- a/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch +++ b/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch @@ -40,7 +40,7 @@ input to the TLS layer for a QUIC connection). if (qd == NULL) { --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c -@@ -662,6 +662,13 @@ int tls_construct_finished(SSL *s, WPACK +@@ -666,6 +666,13 @@ int tls_construct_finished(SSL *s, WPACK int tls_construct_key_update(SSL *s, WPACKET *pkt) { @@ -54,7 +54,7 @@ input to the TLS layer for a QUIC connection). if (!WPACKET_put_bytes_u8(pkt, s->key_update)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return 0; -@@ -684,6 +691,13 @@ MSG_PROCESS_RETURN tls_process_key_updat +@@ -688,6 +695,13 @@ MSG_PROCESS_RETURN tls_process_key_updat return MSG_PROCESS_ERROR; } diff --git a/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch b/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch index 8d252fca0..03f5ef565 100644 --- a/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch +++ b/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch @@ -12,7 +12,7 @@ integrated into the TLSProxy setup. --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10890,6 +10890,17 @@ static int test_quic_api(void) +@@ -10889,6 +10889,17 @@ static int test_quic_api(void) || !TEST_true(SSL_process_quic_post_handshake(clientssl))) goto end; diff --git a/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch b/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch index fbfa77603..44ff85d70 100644 --- a/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch +++ b/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch @@ -255,7 +255,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters TLSEXT_TYPE_quic_transport_parameters, SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, -@@ -1752,8 +1762,37 @@ static int init_quic_transport_params(SS +@@ -1746,8 +1756,37 @@ static int init_quic_transport_params(SS return 1; } @@ -332,7 +332,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters return EXT_RETURN_NOT_SENT; } -@@ -2013,7 +2033,23 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p +@@ -2038,7 +2058,23 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p return 1; } #ifndef OPENSSL_NO_QUIC @@ -359,7 +359,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters { --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1233,7 +1233,22 @@ int tls_parse_ctos_post_handshake_auth(S +@@ -1238,7 +1238,22 @@ int tls_parse_ctos_post_handshake_auth(S } #ifndef OPENSSL_NO_QUIC @@ -383,7 +383,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { -@@ -1943,13 +1958,36 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s +@@ -1949,13 +1964,36 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s } #ifndef OPENSSL_NO_QUIC @@ -472,7 +472,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters #endif --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10816,7 +10816,13 @@ static SSL_QUIC_METHOD quic_method = { +@@ -10815,7 +10815,13 @@ static SSL_QUIC_METHOD quic_method = { test_quic_send_alert, }; @@ -487,7 +487,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; -@@ -10827,29 +10833,7 @@ static int test_quic_api(void) +@@ -10826,29 +10832,7 @@ static int test_quic_api(void) const uint8_t *peer_str; size_t peer_str_len; @@ -518,7 +518,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -10868,6 +10852,8 @@ static int test_quic_api(void) +@@ -10867,6 +10851,8 @@ static int test_quic_api(void) sizeof(client_str))) || !TEST_true(SSL_set_app_data(serverssl, clientssl)) || !TEST_true(SSL_set_app_data(clientssl, serverssl)) @@ -527,7 +527,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) -@@ -10901,11 +10887,85 @@ static int test_quic_api(void) +@@ -10900,11 +10886,85 @@ static int test_quic_api(void) || !TEST_int_le(SSL_do_handshake(serverssl), 0)) goto end; @@ -612,10 +612,10 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters +} #endif /* OPENSSL_NO_QUIC */ - OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") -@@ -11185,7 +11245,7 @@ int setup_tests(void) - ADD_ALL_TESTS(test_handshake_retry, 16); - ADD_ALL_TESTS(test_multi_resume, 5); + static struct next_proto_st { +@@ -11550,7 +11610,7 @@ int setup_tests(void) + #endif + ADD_ALL_TESTS(test_alpn, 4); #ifndef OPENSSL_NO_QUIC - ADD_TEST(test_quic_api); + ADD_ALL_TESTS(test_quic_api, 9); diff --git a/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch b/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch index 9681c281e..818f4ca76 100644 --- a/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch +++ b/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch @@ -64,7 +64,7 @@ support to QUIC. # ifdef __cplusplus --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c -@@ -3998,6 +3998,21 @@ int SSL_do_handshake(SSL *s) +@@ -4015,6 +4015,21 @@ int SSL_do_handshake(SSL *s) ret = s->handshake_func(s); } } @@ -306,7 +306,7 @@ support to QUIC. ret = 1; --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10966,6 +10966,159 @@ end: +@@ -10965,6 +10965,159 @@ end: serverssl = NULL; return testresult; } @@ -465,9 +465,9 @@ support to QUIC. +# endif /* OSSL_NO_USABLE_TLS1_3 */ #endif /* OPENSSL_NO_QUIC */ - OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") -@@ -11246,6 +11399,9 @@ int setup_tests(void) - ADD_ALL_TESTS(test_multi_resume, 5); + static struct next_proto_st { +@@ -11611,6 +11764,9 @@ int setup_tests(void) + ADD_ALL_TESTS(test_alpn, 4); #ifndef OPENSSL_NO_QUIC ADD_ALL_TESTS(test_quic_api, 9); +# ifndef OSSL_NO_USABLE_TLS1_3 diff --git a/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch b/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch index 10654746c..84d7ff731 100644 --- a/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch +++ b/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch @@ -46,7 +46,7 @@ Subject: [PATCH 33/43] QUIC: Process multiple post-handshake messages in a --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10872,8 +10872,7 @@ static int test_quic_api_version(int cln +@@ -10871,8 +10871,7 @@ static int test_quic_api_version(int cln goto end; /* Deal with two NewSessionTickets */ @@ -56,7 +56,7 @@ Subject: [PATCH 33/43] QUIC: Process multiple post-handshake messages in a goto end; /* Dummy handshake call should succeed */ -@@ -11060,8 +11059,7 @@ static int quic_setupearly_data_test(SSL +@@ -11059,8 +11058,7 @@ static int quic_setupearly_data_test(SSL return 0; /* Deal with two NewSessionTickets */ diff --git a/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch b/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch index a5a6893ab..3675b0605 100644 --- a/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch +++ b/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch @@ -15,7 +15,7 @@ Fixes an issue with extension defintions and `no-quic` --- a/Configure +++ b/Configure -@@ -579,6 +579,7 @@ my @disable_cascades = ( +@@ -578,6 +578,7 @@ my @disable_cascades = ( "sm3", "sm4", "srp", "srtp", "ssl3-method", "ssl-trace", "ts", "ui-console", "whirlpool", @@ -23,7 +23,7 @@ Fixes an issue with extension defintions and `no-quic` "fips-securitychecks" ], sub { $config{processor} eq "386" } => [ "sse2" ], -@@ -586,7 +587,7 @@ my @disable_cascades = ( +@@ -585,7 +586,7 @@ my @disable_cascades = ( "ssl3-method" => [ "ssl3" ], "zlib" => [ "zlib-dynamic" ], "des" => [ "mdc2" ], @@ -73,7 +73,7 @@ Fixes an issue with extension defintions and `no-quic` /* Must be immediately before pre_shared_key */ --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1912,7 +1912,7 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1918,7 +1918,7 @@ EXT_RETURN tls_construct_stoc_early_data #ifndef OPENSSL_NO_QUIC /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ diff --git a/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch b/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch index f5d109555..272b2c0aa 100644 --- a/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch +++ b/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch @@ -66,7 +66,7 @@ Subject: [PATCH 37/43] QUIC: Update RFC references --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c -@@ -1942,7 +1942,7 @@ int tls_parse_stoc_early_data(SSL *s, PA +@@ -1967,7 +1967,7 @@ int tls_parse_stoc_early_data(SSL *s, PA #ifndef OPENSSL_NO_QUIC /* * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION @@ -77,7 +77,7 @@ Subject: [PATCH 37/43] QUIC: Update RFC references SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1911,7 +1911,7 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1917,7 +1917,7 @@ EXT_RETURN tls_construct_stoc_early_data return EXT_RETURN_NOT_SENT; #ifndef OPENSSL_NO_QUIC diff --git a/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch b/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch index 73312bd6c..f1842d866 100644 --- a/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch +++ b/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch @@ -22,7 +22,7 @@ Subject: [PATCH 39/43] QUIC: use SSL_IS_QUIC() in more places SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c -@@ -1944,7 +1944,7 @@ int tls_parse_stoc_early_data(SSL *s, PA +@@ -1969,7 +1969,7 @@ int tls_parse_stoc_early_data(SSL *s, PA * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION * per RFC9001 S4.6.1 */ diff --git a/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch b/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch index 8d764eae5..6d130e634 100644 --- a/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch +++ b/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch @@ -69,7 +69,7 @@ from the server SSL. * This will ensure we have received the NewSessionTicket in TLSv1.3 where --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10832,6 +10832,7 @@ static int test_quic_api_version(int cln +@@ -10831,6 +10831,7 @@ static int test_quic_api_version(int cln static const char *client_str = "CLIENT"; const uint8_t *peer_str; size_t peer_str_len; @@ -77,7 +77,7 @@ from the server SSL. TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); -@@ -10854,8 +10855,10 @@ static int test_quic_api_version(int cln +@@ -10853,8 +10854,10 @@ static int test_quic_api_version(int cln || !TEST_true(SSL_set_app_data(clientssl, serverssl)) || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) @@ -90,7 +90,7 @@ from the server SSL. || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) -@@ -10977,6 +10980,7 @@ static int quic_setupearly_data_test(SSL +@@ -10976,6 +10979,7 @@ static int quic_setupearly_data_test(SSL { static const char *server_str = "SERVER"; static const char *client_str = "CLIENT"; @@ -98,7 +98,7 @@ from the server SSL. if (*sctx == NULL && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -11054,8 +11058,10 @@ static int quic_setupearly_data_test(SSL +@@ -11053,8 +11057,10 @@ static int quic_setupearly_data_test(SSL if (sess == NULL) return 1; @@ -111,7 +111,7 @@ from the server SSL. return 0; /* Deal with two NewSessionTickets */ -@@ -11094,12 +11100,15 @@ static int test_quic_early_data(int tst) +@@ -11093,12 +11099,15 @@ static int test_quic_early_data(int tst) SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; SSL_SESSION *sess = NULL; diff --git a/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch b/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch index 885ec470e..a60075336 100644 --- a/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch +++ b/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch @@ -146,7 +146,7 @@ Don't make the new functions public. if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) { --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10832,7 +10832,6 @@ static int test_quic_api_version(int cln +@@ -10831,7 +10831,6 @@ static int test_quic_api_version(int cln static const char *client_str = "CLIENT"; const uint8_t *peer_str; size_t peer_str_len; @@ -154,7 +154,7 @@ Don't make the new functions public. TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); -@@ -10855,10 +10854,8 @@ static int test_quic_api_version(int cln +@@ -10854,10 +10853,8 @@ static int test_quic_api_version(int cln || !TEST_true(SSL_set_app_data(clientssl, serverssl)) || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) @@ -166,7 +166,7 @@ Don't make the new functions public. || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) -@@ -10980,7 +10977,6 @@ static int quic_setupearly_data_test(SSL +@@ -10979,7 +10976,6 @@ static int quic_setupearly_data_test(SSL { static const char *server_str = "SERVER"; static const char *client_str = "CLIENT"; @@ -174,7 +174,7 @@ Don't make the new functions public. if (*sctx == NULL && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -11058,10 +11054,8 @@ static int quic_setupearly_data_test(SSL +@@ -11057,10 +11053,8 @@ static int quic_setupearly_data_test(SSL if (sess == NULL) return 1; @@ -187,7 +187,7 @@ Don't make the new functions public. return 0; /* Deal with two NewSessionTickets */ -@@ -11100,15 +11094,12 @@ static int test_quic_early_data(int tst) +@@ -11099,15 +11093,12 @@ static int test_quic_early_data(int tst) SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; SSL_SESSION *sess = NULL; From b2032b33358ceed24657bc28a8e698a9c0b36cd7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 16 Sep 2024 07:08:02 +0800 Subject: [PATCH 017/425] minimal: add natflow config * cp: cannot stat 'bin/packages/x86_64/base/*natflow*.ipk': No such file or directory Signed-off-by: sbwml --- openwrt/23-config-minimal-common | 3 +++ openwrt/23-config-musl-r8500-minimal | 3 +++ 2 files changed, 6 insertions(+) diff --git a/openwrt/23-config-minimal-common b/openwrt/23-config-minimal-common index 120362d95..8f37e65ea 100644 --- a/openwrt/23-config-minimal-common +++ b/openwrt/23-config-minimal-common @@ -22,6 +22,9 @@ CONFIG_PACKAGE_iptables-nft=y CONFIG_PACKAGE_xtables-nft=y # CONFIG_PACKAGE_iptables-legacy is not set +# Natflow +CONFIG_PACKAGE_natflow=m + # SFE CONFIG_PACKAGE_kmod-fast-classifier=y CONFIG_PACKAGE_kmod-shortcut-fe-cm=y diff --git a/openwrt/23-config-musl-r8500-minimal b/openwrt/23-config-musl-r8500-minimal index d67704d79..a1e6e15a7 100644 --- a/openwrt/23-config-musl-r8500-minimal +++ b/openwrt/23-config-musl-r8500-minimal @@ -37,6 +37,9 @@ CONFIG_PACKAGE_iptables-nft=y CONFIG_PACKAGE_xtables-nft=y # CONFIG_PACKAGE_iptables-legacy is not set +# Natflow +CONFIG_PACKAGE_natflow=m + # SFE CONFIG_PACKAGE_kmod-fast-classifier=y CONFIG_PACKAGE_kmod-shortcut-fe-cm=y From d925ae37899dba0bb025d7094c9416993e1364fb Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 21 Sep 2024 01:36:04 +0800 Subject: [PATCH 018/425] linux-6.6: bump to 6.6.52 Signed-off-by: sbwml --- openwrt/build.sh | 3 --- openwrt/scripts/05-fix-source.sh | 1 + tags/kernel-6.6 | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 51c40b712..3edd07377 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -368,9 +368,6 @@ elif [ ! "$ENABLE_GLIBC" = "y" ]; then fi [ "$(whoami)" = "runner" ] && endgroup -# clean directory - github actions -[ "$(whoami)" = "runner" ] && echo 'CONFIG_AUTOREMOVE=y' >> .config - # uhttpd [ "$ENABLE_UHTTPD" = "y" ] && sed -i '/nginx/d' .config && echo 'CONFIG_PACKAGE_ariang=y' >> .config diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index b36134b71..99a7bfd65 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -119,6 +119,7 @@ if [ "$KERNEL_CLANG_LTO" = "y" ]; then else curl -s https://$mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Makefile fi +[ "$ENABLE_MOLD" != y ] && sed -i 's/no-mold//g' package/devel/perf/Makefile # kselftests-bpf curl -s https://$mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package/devel/kselftests-bpf/Makefile diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index 485ec8eef..094066fe7 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .51 -LINUX_KERNEL_HASH-6.6.51 = 1c0c9a14650879c4913efdbac428ba31a540c3d987155ddf34d33e11eca008b3 +LINUX_VERSION-6.6 = .52 +LINUX_KERNEL_HASH-6.6.52 = 1591ab348399d4aa53121158525056a69c8cf0fe0e90935b0095e9a58e37b4b8 From aa185a88258ce3d56bdf5132f07b39cba41c0b59 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Sep 2024 07:57:20 +0800 Subject: [PATCH 019/425] ci: update clang version to 19 Signed-off-by: sbwml --- .github/workflows/build-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index e40580cf8..880dd4dc2 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -59,7 +59,7 @@ jobs: uses: sbwml/actions@openwrt-build-setup - name: Install LLVM - uses: sbwml/actions@install-llvm + uses: sbwml/actions@install-llvm-19 - name: Compile OpenWrt working-directory: /builder @@ -121,7 +121,7 @@ jobs: - name: Create release continue-on-error: true - uses: sbwml/release-action@main + uses: ncipollo/release-action@v1 with: name: OpenWrt-${{ env.latest_release }} allowUpdates: true From 246b8f2cdc05415cbee19e993b26c7fb76ead273 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Sep 2024 16:53:13 +0800 Subject: [PATCH 020/425] linux-6.11: init (preparing for Linux 6.12 LTS) Signed-off-by: sbwml --- openwrt/23-config-musl-r8500 | 2 +- openwrt/23-config-musl-r8500-minimal | 2 +- openwrt/23-config-musl-x86 | 6 +- openwrt/build.sh | 13 +- ...ernel-add-miss-config-for-linux-6.11.patch | 25 + ...el-name-in-proc-cpuinfo-for-64bit-ta.patch | 32 + ...den-app-limited-rate-sample-detectio.patch | 52 + ...hrink-delivered_mstamp-first_tx_msta.patch | 74 + ...napshot-packets-in-flight-at-transmi.patch | 109 + ...ount-packets-lost-over-TCP-rate-samp.patch | 70 + ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 38 + ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 57 + ...djust-skb-tx.in_flight-upon-merge-in.patch | 59 + ...djust-skb-tx.in_flight-upon-split-in.patch | 97 + ...ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 73 + ...alize-TSO-sizing-in-TCP-CC-module-AP.patch | 118 + ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 72 + ...ecord-app-limited-status-of-TLP-repa.patch | 45 + ...nform-CC-module-of-losses-repaired-b.patch | 45 + ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 73 + ...r-route-feature-RTAX_FEATURE_ECN_LOW.patch | 112 + ...pdate-TCP-bbr-congestion-control-mod.patch | 2821 +++++++++++ ...nsure-ECN-enabled-BBR-flows-set-ECT-.patch | 59 + ...OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 38 + ...tso_segs-and-skb_marked_lost-to-bpf_.patch | 39 + ...-silence-btf-module-warning-messages.patch | 21 + ...LRNG-Entropy-Source-and-DRNG-Manager.patch | 4336 +++++++++++++++++ ...cate-one-DRNG-instance-per-NUMA-node.patch | 194 + .../011-LRNG-0003-LRNG-proc-interface.patch | 135 + ...004-LRNG-add-switchable-DRNG-support.patch | 363 ++ ...LRNG-add-common-generic-hash-support.patch | 221 + ...-externalize-DRBG-functions-for-LRNG.patch | 114 + ...07-LRNG-add-SP800-90A-DRBG-extension.patch | 363 ++ ...add-kernel-crypto-API-PRNG-extension.patch | 305 ++ ...-LRNG-add-atomic-DRNG-implementation.patch | 159 + ...mmon-timer-based-entropy-source-code.patch | 197 + ...11-LRNG-add-interrupt-entropy-source.patch | 1218 +++++ ...-scheduler-add-entropy-sampling-hook.patch | 35 + ...G-add-scheduler-based-entropy-source.patch | 914 ++++ ...add-SP800-90B-compliant-health-tests.patch | 731 +++ ...-add-random.c-entropy-source-support.patch | 207 + ...11-LRNG-0016-LRNG-CPU-entropy-source.patch | 401 ++ ...RNG-add-Jitter-RNG-fast-noise-source.patch | 571 +++ ...to-enable-runtime-entropy-rate-confi.patch | 60 + ...terface-for-gathering-of-raw-entropy.patch | 1533 ++++++ ...-add-power-on-and-runtime-self-tests.patch | 523 ++ ...0021-LRNG-sysctls-and-proc-interface.patch | 174 + ...add-drop-in-replacement-random-4-API.patch | 938 ++++ ...LRNG-add-kernel-crypto-API-interface.patch | 199 + ...RNG-add-dev-lrng-device-file-support.patch | 88 + ...-LRNG-add-hwrand-framework-interface.patch | 125 + ...ter-export-udp_get_timeouts-function.patch | 38 + ...k-events-support-multiple-registrant.patch | 352 ++ ...-linux-kernel-to-support-shortcut-fe.patch | 206 + .../net/982-add-bcm-fullcone-support.patch | 235 + ...83-add-bcm-fullcone-nft_masq-support.patch | 114 + openwrt/patch/kernel-6.11/net/README.md | 15 + ...den-app-limited-rate-sample-detectio.patch | 0 ...hrink-delivered_mstamp-first_tx_msta.patch | 0 ...napshot-packets-in-flight-at-transmi.patch | 0 ...ount-packets-lost-over-TCP-rate-samp.patch | 0 ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 0 ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 0 ...djust-skb-tx.in_flight-upon-merge-in.patch | 0 ...djust-skb-tx.in_flight-upon-split-in.patch | 0 ...ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 0 ...alize-TSO-sizing-in-TCP-CC-module-AP.patch | 0 ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 0 ...ecord-app-limited-status-of-TLP-repa.patch | 0 ...nform-CC-module-of-losses-repaired-b.patch | 0 ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 0 ...r-route-feature-RTAX_FEATURE_ECN_LOW.patch | 0 ...pdate-TCP-bbr-congestion-control-mod.patch | 2 +- ...nsure-ECN-enabled-BBR-flows-set-ECT-.patch | 0 ...OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 0 openwrt/patch/mt76/Makefile | 6 +- ...ix-build-with-mac80211-6.11-backport.patch | 298 ++ openwrt/patch/openwrt-6.x/modules/crypto.mk | 10 +- openwrt/patch/openwrt-6.x/modules/fs.mk | 9 +- openwrt/patch/openwrt-6.x/modules/hwmon.mk | 5 +- openwrt/patch/openwrt-6.x/modules/i2c.mk | 4 +- openwrt/patch/openwrt-6.x/modules/iio.mk | 2 +- openwrt/patch/openwrt-6.x/modules/input.mk | 2 +- openwrt/patch/openwrt-6.x/modules/lib.mk | 2 +- .../patch/openwrt-6.x/modules/netdevices.mk | 47 +- .../patch/openwrt-6.x/modules/netsupport.mk | 4 +- openwrt/patch/openwrt-6.x/modules/nls.mk | 1 - openwrt/patch/openwrt-6.x/modules/other.mk | 2 +- openwrt/patch/openwrt-6.x/modules/sound.mk | 3 +- openwrt/patch/openwrt-6.x/modules/usb.mk | 5 +- openwrt/patch/openwrt-6.x/modules/video.mk | 24 +- openwrt/patch/openwrt-6.x/x86/64/config-6.11 | 664 +++ openwrt/patch/openwrt-6.x/x86/config-6.11 | 515 ++ .../100-fix_cs5535_clockevt.patch | 13 + .../103-pcengines_apu6_platform.patch | 275 ++ .../002-fix-build-for-linux-6.7-rc1.patch | 33 + .../gpio-button-hotplug/fix-linux-6.11.patch | 26 + .../fix-build-for-linux-6.11.patch | 41 + .../nat46/100-fix-build-with-kernel-6.9.patch | 74 + .../ovpn-dco/901-fix-linux-6.11.patch | 9 + .../100-fix-build-with-linux-6.11.patch | 50 + .../301-fix-build-with-linux-6.11.patch | 15 + openwrt/scripts/00-prepare_base.sh | 4 + openwrt/scripts/01-prepare_base-mainline.sh | 176 +- openwrt/scripts/04-fix_kmod.sh | 18 + tags/kernel-6.11 | 2 + tags/kernel-tag.sh | 10 + 107 files changed, 21437 insertions(+), 130 deletions(-) create mode 100644 openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch create mode 100644 openwrt/patch/kernel-6.11/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch create mode 100644 openwrt/patch/kernel-6.11/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch create mode 100644 openwrt/patch/kernel-6.11/btf/990-btf-silence-btf-module-warning-messages.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0003-LRNG-proc-interface.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch create mode 100644 openwrt/patch/kernel-6.11/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch create mode 100644 openwrt/patch/kernel-6.11/net/601-netfilter-export-udp_get_timeouts-function.patch create mode 100644 openwrt/patch/kernel-6.11/net/952-net-conntrack-events-support-multiple-registrant.patch create mode 100644 openwrt/patch/kernel-6.11/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch create mode 100644 openwrt/patch/kernel-6.11/net/982-add-bcm-fullcone-support.patch create mode 100644 openwrt/patch/kernel-6.11/net/983-add-bcm-fullcone-nft_masq-support.patch create mode 100644 openwrt/patch/kernel-6.11/net/README.md rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch (99%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch (100%) rename openwrt/patch/kernel-6.6/{bbr3_6.6 => bbr3}/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch (100%) create mode 100644 openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch create mode 100644 openwrt/patch/openwrt-6.x/x86/64/config-6.11 create mode 100644 openwrt/patch/openwrt-6.x/x86/config-6.11 create mode 100644 openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch create mode 100644 openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch create mode 100644 openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch create mode 100644 openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch create mode 100644 openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch create mode 100644 openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch create mode 100644 openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch create mode 100644 openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch create mode 100644 openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch create mode 100644 tags/kernel-6.11 diff --git a/openwrt/23-config-musl-r8500 b/openwrt/23-config-musl-r8500 index 2595ac5dc..027a6dff4 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/23-config-musl-r8500 @@ -175,7 +175,7 @@ CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y CONFIG_PACKAGE_kmod-sched=y -CONFIG_PACKAGE_kmod-tcp-bbr=y +CONFIG_PACKAGE_kmod-tcp-bbr3=y CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-usb-audio=y diff --git a/openwrt/23-config-musl-r8500-minimal b/openwrt/23-config-musl-r8500-minimal index a1e6e15a7..cfbbc0b5b 100644 --- a/openwrt/23-config-musl-r8500-minimal +++ b/openwrt/23-config-musl-r8500-minimal @@ -127,7 +127,7 @@ CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y CONFIG_PACKAGE_kmod-sched=y -CONFIG_PACKAGE_kmod-tcp-bbr=y +CONFIG_PACKAGE_kmod-tcp-bbr3=y CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-usb-storage=y diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 7d55f8367..41c71c6d9 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -2,8 +2,7 @@ CONFIG_TARGET_x86=y CONFIG_TARGET_x86_64=y CONFIG_TARGET_x86_64_DEVICE_generic=y -CONFIG_GRUB_TIMEOUT="1" -CONFIG_TESTING_KERNEL=y +CONFIG_GRUB_TIMEOUT="3" ### Basic CONFIG_ALL_KMODS=y @@ -58,9 +57,6 @@ CONFIG_PACKAGE_kmod-video-pwc=y CONFIG_PACKAGE_kmod-video-uvc=y CONFIG_PACKAGE_kmod-video-videobuf2=y -### Utilities -CONFIG_PACKAGE_qemu-ga=y - ### Virtualization CONFIG_PACKAGE_kmod-kvm-intel=y CONFIG_PACKAGE_kmod-kvm-x86=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 3edd07377..bc0ec3fa0 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -128,6 +128,10 @@ export \ ENABLE_GLIBC=$ENABLE_GLIBC \ ENABLE_LRNG=$ENABLE_LRNG \ KERNEL_CLANG_LTO=$KERNEL_CLANG_LTO \ + TESTING_KERNEL=$TESTING_KERNEL \ + +# kernel version +[ "$TESTING_KERNEL" = "y" ] && export kernel_version=6.11 || export kernel_version=6.6 # print version echo -e "\r\n${GREEN_COLOR}Building $branch${RES}\r\n" @@ -146,7 +150,7 @@ else echo -e "${GREEN_COLOR}Model: nanopi-r4s${RES}" [ "$1" = "rc2" ] && model="nanopi-r4s" fi -curl -s https://$mirror/tags/kernel-6.6 > kernel.txt +curl -s https://$mirror/tags/kernel-$kernel_version > kernel.txt kmod_hash=$(grep HASH kernel.txt | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}') kmodpkg_name=$(echo $(grep HASH kernel.txt | awk -F'HASH-' '{print $2}' | awk '{print $1}')-1-$(echo $kmod_hash)) echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" @@ -374,6 +378,13 @@ fi # bcm53xx: upx_list.txt # [ "$platform" = "bcm53xx" ] && curl -s https://$mirror/openwrt/generic/upx_list.txt > upx_list.txt +# test kernel +[ "$TESTING_KERNEL" = "y" ] && [ "$platform" = "bcm53xx" ] && sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config +[ "$TESTING_KERNEL" = "y" ] && sed -i '1i\# Test kernel\nCONFIG_TESTING_KERNEL=y\n' .config + +# not all kmod +[ "$NO_KMOD" = "y" ] && sed -i '/CONFIG_ALL_KMODS=y/d; /CONFIG_ALL_NONSHARED=y/d' .config + # Toolchain Cache if [ "$BUILD_FAST" = "y" ]; then [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl diff --git a/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch new file mode 100644 index 000000000..4797de0a6 --- /dev/null +++ b/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch @@ -0,0 +1,25 @@ +From dfd7696d643a76cf94ba267f888c2f3dc59fd626 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sat, 21 Sep 2024 04:08:14 +0800 +Subject: [PATCH] include: kernel: add miss config for linux-6.11 + +Signed-off-by: sbwml +--- + include/kernel-defaults.mk | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk +index 408bf2f..8422004 100644 +--- a/include/kernel-defaults.mk ++++ b/include/kernel-defaults.mk +@@ -110,6 +110,7 @@ define Kernel/SetNoInitramfs + grep -v INITRAMFS $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set + echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set + echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_FSCACHE is not set' >> $(LINUX_DIR)/.config.set + # CLANG + mv $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.old + grep -v CONFIG_LTO $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set +-- +2.42.0 + diff --git a/openwrt/patch/kernel-6.11/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch b/openwrt/patch/kernel-6.11/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch new file mode 100644 index 000000000..67467025b --- /dev/null +++ b/openwrt/patch/kernel-6.11/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch @@ -0,0 +1,32 @@ +From b2277680a6fbb06e7af2b1583d72a587ca4c637a Mon Sep 17 00:00:00 2001 +From: Sumit Gupta +Date: Mon, 29 Aug 2016 14:32:25 +0530 +Subject: [PATCH 1/2] arm64: cpuinfo: Add "model name" in /proc/cpuinfo for + 64bit tasks also + +Removed restriction of displaying model name for 32 bit tasks only. +Because of this Processor details were not displayed in +"System setting -> Details" in Ubuntu model name display is generic +and can be printed for 64 bit also. + +model name : ARMv8 Processor rev X (v8l) + +Signed-off-by: Sumit Gupta +--- + arch/arm64/kernel/cpuinfo.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/arch/arm64/kernel/cpuinfo.c ++++ b/arch/arm64/kernel/cpuinfo.c +@@ -205,9 +205,8 @@ static int c_show(struct seq_file *m, vo + * "processor". Give glibc what it expects. + */ + seq_printf(m, "processor\t: %d\n", i); +- if (compat) +- seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", +- MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); ++ seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", ++ MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); + + seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", + loops_per_jiffy / (500000UL/HZ), diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch new file mode 100644 index 000000000..4eaa0840b --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -0,0 +1,52 @@ +From 2343b8617207cb536de6a7165188c681263f3407 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Tue, 11 Jun 2019 12:26:55 -0400 +Subject: [PATCH 01/19] net-tcp_bbr: broaden app-limited rate sample detection + +This commit is a bug fix for the Linux TCP app-limited +(application-limited) logic that is used for collecting rate +(bandwidth) samples. + +Previously the app-limited logic only looked for "bubbles" of +silence in between application writes, by checking at the start +of each sendmsg. But "bubbles" of silence can also happen before +retransmits: e.g. bubbles can happen between an application write +and a retransmit, or between two retransmits. + +Retransmits are triggered by ACKs or timers. So this commit checks +for bubbles of app-limited silence upon ACKs or timers. + +Why does this commit check for app-limited state at the start of +ACKs and timer handling? Because at that point we know whether +inflight was fully using the cwnd. During processing the ACK or +timer event we often change the cwnd; after changing the cwnd we +can't know whether inflight was fully using the old cwnd. + +Origin-9xx-SHA1: 3fe9b53291e018407780fb8c356adb5666722cbc +Change-Id: I37221506f5166877c2b110753d39bb0757985e68 +Signed-off-by: Alexandre Frade +--- + net/ipv4/tcp_input.c | 1 + + net/ipv4/tcp_timer.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3934,6 +3934,7 @@ static int tcp_ack(struct sock *sk, cons + + prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; + rs.prior_in_flight = tcp_packets_in_flight(tp); ++ tcp_rate_check_app_limited(sk); + + /* ts_recent update must be made after we are sure that the packet + * is in window. +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -689,6 +689,7 @@ void tcp_write_timer_handler(struct sock + return; + } + ++ tcp_rate_check_app_limited(sk); + tcp_mstamp_refresh(tcp_sk(sk)); + event = icsk->icsk_pending; + diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch new file mode 100644 index 000000000..3ebe1d642 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch @@ -0,0 +1,74 @@ +From c7683b8a74098c5f48c61d8d578dd15929c24843 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Sun, 24 Jun 2018 21:55:59 -0400 +Subject: [PATCH 02/19] net-tcp_bbr: v2: shrink delivered_mstamp, + first_tx_mstamp to u32 to free up 8 bytes + +Free up some space for tracking inflight and losses for each +bw sample, in upcoming commits. + +These timestamps are in microseconds, and are now stored in 32 +bits. So they can only hold time intervals up to roughly 2^12 = 4096 +seconds. But Linux TCP RTT and RTO tracking has the same 32-bit +microsecond implementation approach and resulting deployment +limitations. So this is not introducing a new limit. And these should +not be a limitation for the foreseeable future. + +Effort: net-tcp_bbr +Origin-9xx-SHA1: 238a7e6b5d51625fef1ce7769826a7b21b02ae55 +Change-Id: I3b779603797263b52a61ad57c565eb91fe42680c +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 9 +++++++-- + net/ipv4/tcp_rate.c | 7 ++++--- + 2 files changed, 11 insertions(+), 5 deletions(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -884,6 +884,11 @@ static inline u32 tcp_stamp_us_delta(u64 + return max_t(s64, t1 - t0, 0); + } + ++static inline u32 tcp_stamp32_us_delta(u32 t1, u32 t0) ++{ ++ return max_t(s32, t1 - t0, 0); ++} ++ + /* provide the departure time in us unit */ + static inline u64 tcp_skb_timestamp_us(const struct sk_buff *skb) + { +@@ -973,9 +978,9 @@ struct tcp_skb_cb { + /* pkts S/ACKed so far upon tx of skb, incl retrans: */ + __u32 delivered; + /* start of send pipeline phase */ +- u64 first_tx_mstamp; ++ u32 first_tx_mstamp; + /* when we reached the "delivered" count */ +- u64 delivered_mstamp; ++ u32 delivered_mstamp; + } tx; /* only used for outgoing skbs */ + union { + struct inet_skb_parm h4; +--- a/net/ipv4/tcp_rate.c ++++ b/net/ipv4/tcp_rate.c +@@ -101,8 +101,9 @@ void tcp_rate_skb_delivered(struct sock + /* Record send time of most recently ACKed packet: */ + tp->first_tx_mstamp = tx_tstamp; + /* Find the duration of the "send phase" of this window: */ +- rs->interval_us = tcp_stamp_us_delta(tp->first_tx_mstamp, +- scb->tx.first_tx_mstamp); ++ rs->interval_us = tcp_stamp32_us_delta( ++ tp->first_tx_mstamp, ++ scb->tx.first_tx_mstamp); + + } + /* Mark off the skb delivered once it's sacked to avoid being +@@ -155,7 +156,7 @@ void tcp_rate_gen(struct sock *sk, u32 d + * longer phase. + */ + snd_us = rs->interval_us; /* send phase */ +- ack_us = tcp_stamp_us_delta(tp->tcp_mstamp, ++ ack_us = tcp_stamp32_us_delta(tp->tcp_mstamp, + rs->prior_mstamp); /* ack phase */ + rs->interval_us = max(snd_us, ack_us); + diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch new file mode 100644 index 000000000..a5d56b08c --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -0,0 +1,109 @@ +From a128e1c2f3d98794c7341f357628d1e7f737da23 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Sat, 5 Aug 2017 11:49:50 -0400 +Subject: [PATCH 03/19] net-tcp_bbr: v2: snapshot packets in flight at transmit + time and pass in rate_sample + +CC algorithms may want to snapshot the number of packets in flight at +transmit time and pass in rate_sample, to understand the relationship +between inflight and losses or ECN signals, to try to find the highest +inflight value that has acceptable levels of loss/ECN marking. + +We split out the code to set an skb's tx.in_flight field into its own +function, so that this code can be used for the TCP_REPAIR "fake send" +code path that inserts skbs into the rtx queue without sending them. + +Effort: net-tcp_bbr +Origin-9xx-SHA1: b3eb4f2d20efab4ca001f32c9294739036c493ea +Origin-9xx-SHA1: e880fc907d06ea7354333f60f712748ebce9497b +Origin-9xx-SHA1: 330f825a08a6fe92cef74d799cc468864c479f63 +Change-Id: I7314047d0ff14dd261a04b1969a46dc658c8836a +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 6 ++++++ + net/ipv4/tcp_output.c | 1 + + net/ipv4/tcp_rate.c | 20 ++++++++++++++++++++ + 3 files changed, 27 insertions(+) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -981,6 +981,10 @@ struct tcp_skb_cb { + u32 first_tx_mstamp; + /* when we reached the "delivered" count */ + u32 delivered_mstamp; ++#define TCPCB_IN_FLIGHT_BITS 20 ++#define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) ++ u32 in_flight:20, /* packets in flight at transmit */ ++ unused2:12; + } tx; /* only used for outgoing skbs */ + union { + struct inet_skb_parm h4; +@@ -1136,6 +1140,7 @@ struct rate_sample { + u64 prior_mstamp; /* starting timestamp for interval */ + u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ + u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ ++ u32 tx_in_flight; /* packets in flight at starting timestamp */ + s32 delivered; /* number of packets delivered over interval */ + s32 delivered_ce; /* number of packets delivered w/ CE marks*/ + long interval_us; /* time for tp->delivered to incr "delivered" */ +@@ -1258,6 +1263,7 @@ static inline void tcp_ca_event(struct s + void tcp_set_ca_state(struct sock *sk, const u8 ca_state); + + /* From tcp_rate.c */ ++void tcp_set_tx_in_flight(struct sock *sk, struct sk_buff *skb); + void tcp_rate_skb_sent(struct sock *sk, struct sk_buff *skb); + void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb, + struct rate_sample *rs); +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -2767,6 +2767,7 @@ static bool tcp_write_xmit(struct sock * + skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); + list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); + tcp_init_tso_segs(skb, mss_now); ++ tcp_set_tx_in_flight(sk, skb); + goto repair; /* Skip network transmission */ + } + +--- a/net/ipv4/tcp_rate.c ++++ b/net/ipv4/tcp_rate.c +@@ -34,6 +34,24 @@ + * ready to send in the write queue. + */ + ++void tcp_set_tx_in_flight(struct sock *sk, struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ u32 in_flight; ++ ++ /* Check, sanitize, and record packets in flight after skb was sent. */ ++ in_flight = tcp_packets_in_flight(tp) + tcp_skb_pcount(skb); ++ if (WARN_ONCE(in_flight > TCPCB_IN_FLIGHT_MAX, ++ "insane in_flight %u cc %s mss %u " ++ "cwnd %u pif %u %u %u %u\n", ++ in_flight, inet_csk(sk)->icsk_ca_ops->name, ++ tp->mss_cache, tp->snd_cwnd, ++ tp->packets_out, tp->retrans_out, ++ tp->sacked_out, tp->lost_out)) ++ in_flight = TCPCB_IN_FLIGHT_MAX; ++ TCP_SKB_CB(skb)->tx.in_flight = in_flight; ++} ++ + /* Snapshot the current delivery information in the skb, to generate + * a rate sample later when the skb is (s)acked in tcp_rate_skb_delivered(). + */ +@@ -67,6 +85,7 @@ void tcp_rate_skb_sent(struct sock *sk, + TCP_SKB_CB(skb)->tx.delivered = tp->delivered; + TCP_SKB_CB(skb)->tx.delivered_ce = tp->delivered_ce; + TCP_SKB_CB(skb)->tx.is_app_limited = tp->app_limited ? 1 : 0; ++ tcp_set_tx_in_flight(sk, skb); + } + + /* When an skb is sacked or acked, we fill in the rate sample with the (prior) +@@ -96,6 +115,7 @@ void tcp_rate_skb_delivered(struct sock + rs->prior_mstamp = scb->tx.delivered_mstamp; + rs->is_app_limited = scb->tx.is_app_limited; + rs->is_retrans = scb->sacked & TCPCB_RETRANS; ++ rs->tx_in_flight = scb->tx.in_flight; + rs->last_end_seq = scb->end_seq; + + /* Record send time of most recently ACKed packet: */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch new file mode 100644 index 000000000..69e9f35d9 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch @@ -0,0 +1,70 @@ +From 4a30ce7df55db785e1002dbd9d87f807fe14568a Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Thu, 12 Oct 2017 23:44:27 -0400 +Subject: [PATCH 04/19] net-tcp_bbr: v2: count packets lost over TCP rate + sampling interval + +For understanding the relationship between inflight and packet loss +signals, to try to find the highest inflight value that has acceptable +levels of packet losses. + +Effort: net-tcp_bbr +Origin-9xx-SHA1: 4527e26b2bd7756a88b5b9ef1ada3da33dd609ab +Change-Id: I594c2500868d9c530770e7ddd68ffc87c57f4fd5 +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 5 ++++- + net/ipv4/tcp_rate.c | 3 +++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -985,6 +985,7 @@ struct tcp_skb_cb { + #define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) + u32 in_flight:20, /* packets in flight at transmit */ + unused2:12; ++ u32 lost; /* packets lost so far upon tx of skb */ + } tx; /* only used for outgoing skbs */ + union { + struct inet_skb_parm h4; +@@ -1138,11 +1139,13 @@ struct ack_sample { + */ + struct rate_sample { + u64 prior_mstamp; /* starting timestamp for interval */ ++ u32 prior_lost; /* tp->lost at "prior_mstamp" */ + u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ + u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ + u32 tx_in_flight; /* packets in flight at starting timestamp */ ++ s32 lost; /* number of packets lost over interval */ + s32 delivered; /* number of packets delivered over interval */ +- s32 delivered_ce; /* number of packets delivered w/ CE marks*/ ++ s32 delivered_ce; /* packets delivered w/ CE mark over interval */ + long interval_us; /* time for tp->delivered to incr "delivered" */ + u32 snd_interval_us; /* snd interval for delivered packets */ + u32 rcv_interval_us; /* rcv interval for delivered packets */ +--- a/net/ipv4/tcp_rate.c ++++ b/net/ipv4/tcp_rate.c +@@ -84,6 +84,7 @@ void tcp_rate_skb_sent(struct sock *sk, + TCP_SKB_CB(skb)->tx.delivered_mstamp = tp->delivered_mstamp; + TCP_SKB_CB(skb)->tx.delivered = tp->delivered; + TCP_SKB_CB(skb)->tx.delivered_ce = tp->delivered_ce; ++ TCP_SKB_CB(skb)->tx.lost = tp->lost; + TCP_SKB_CB(skb)->tx.is_app_limited = tp->app_limited ? 1 : 0; + tcp_set_tx_in_flight(sk, skb); + } +@@ -110,6 +111,7 @@ void tcp_rate_skb_delivered(struct sock + if (!rs->prior_delivered || + tcp_skb_sent_after(tx_tstamp, tp->first_tx_mstamp, + scb->end_seq, rs->last_end_seq)) { ++ rs->prior_lost = scb->tx.lost; + rs->prior_delivered_ce = scb->tx.delivered_ce; + rs->prior_delivered = scb->tx.delivered; + rs->prior_mstamp = scb->tx.delivered_mstamp; +@@ -165,6 +167,7 @@ void tcp_rate_gen(struct sock *sk, u32 d + return; + } + rs->delivered = tp->delivered - rs->prior_delivered; ++ rs->lost = tp->lost - rs->prior_lost; + + rs->delivered_ce = tp->delivered_ce - rs->prior_delivered_ce; + /* delivered_ce occupies less than 32 bits in the skb control block */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch new file mode 100644 index 000000000..3aff3d52e --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -0,0 +1,38 @@ +From 27fa5566204ef20bb34b2e5b68a7f6807afce447 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Mon, 19 Nov 2018 13:48:36 -0500 +Subject: [PATCH 05/19] net-tcp_bbr: v2: export FLAG_ECE in rate_sample.is_ece + +For understanding the relationship between inflight and ECN signals, +to try to find the highest inflight value that has acceptable levels +ECN marking. + +Effort: net-tcp_bbr +Origin-9xx-SHA1: 3eba998f2898541406c2666781182200934965a8 +Change-Id: I3a964e04cee83e11649a54507043d2dfe769a3b3 +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 1 + + net/ipv4/tcp_input.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1157,6 +1157,7 @@ struct rate_sample { + bool is_app_limited; /* is sample from packet with bubble in pipe? */ + bool is_retrans; /* is sample from retransmission? */ + bool is_ack_delayed; /* is this (likely) a delayed ACK? */ ++ bool is_ece; /* did this ACK have ECN marked? */ + }; + + struct tcp_congestion_ops { +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -4033,6 +4033,7 @@ static int tcp_ack(struct sock *sk, cons + delivered = tcp_newly_delivered(sk, delivered, flag); + lost = tp->lost - lost; /* freshly marked lost */ + rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); ++ rs.is_ece = !!(flag & FLAG_ECE); + tcp_rate_gen(sk, delivered, lost, is_sack_reneg, sack_state.rate); + tcp_cong_control(sk, ack, delivered, flag, sack_state.rate); + tcp_xmit_recovery(sk, rexmit); diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch new file mode 100644 index 000000000..c6916bb2d --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -0,0 +1,57 @@ +From c083bc8abfefbee48922f6ff7976020abc71253f Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Tue, 7 Aug 2018 21:52:06 -0400 +Subject: [PATCH 06/19] net-tcp_bbr: v2: introduce ca_ops->skb_marked_lost() CC + module callback API + +For connections experiencing reordering, RACK can mark packets lost +long after we receive the SACKs/ACKs hinting that the packets were +actually lost. + +This means that CC modules cannot easily learn the volume of inflight +data at which packet loss happens by looking at the current inflight +or even the packets in flight when the most recently SACKed packet was +sent. To learn this, CC modules need to know how many packets were in +flight at the time lost packets were sent. This new callback, combined +with TCP_SKB_CB(skb)->tx.in_flight, allows them to learn this. + +This also provides a consistent callback that is invoked whether +packets are marked lost upon ACK processing, using the RACK reordering +timer, or at RTO time. + +Effort: net-tcp_bbr +Origin-9xx-SHA1: afcbebe3374e4632ac6714d39e4dc8a8455956f4 +Change-Id: I54826ab53df636be537e5d3c618a46145d12d51a +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 3 +++ + net/ipv4/tcp_input.c | 5 +++++ + 2 files changed, 8 insertions(+) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1184,6 +1184,9 @@ struct tcp_congestion_ops { + /* override sysctl_tcp_min_tso_segs */ + u32 (*min_tso_segs)(struct sock *sk); + ++ /* react to a specific lost skb (optional) */ ++ void (*skb_marked_lost)(struct sock *sk, const struct sk_buff *skb); ++ + /* call when packets are delivered to update cwnd and pacing rate, + * after all the ca_state processing. (optional) + */ +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1120,7 +1120,12 @@ static void tcp_verify_retransmit_hint(s + */ + static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) + { ++ struct sock *sk = (struct sock *)tp; ++ const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; ++ + tp->lost += tcp_skb_pcount(skb); ++ if (ca_ops->skb_marked_lost) ++ ca_ops->skb_marked_lost(sk, skb); + } + + void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb) diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch new file mode 100644 index 000000000..85508458a --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch @@ -0,0 +1,59 @@ +From 74522518932db459e21108dede9f1354cc2bb6b8 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Wed, 1 May 2019 20:16:33 -0400 +Subject: [PATCH 07/19] net-tcp_bbr: v2: adjust skb tx.in_flight upon merge in + tcp_shifted_skb() + +When tcp_shifted_skb() updates state as adjacent SACKed skbs are +coalesced, previously the tx.in_flight was not adjusted, so we could +get contradictory state where the skb's recorded pcount was bigger +than the tx.in_flight (the number of segments that were in_flight +after sending the skb). + +Normally have a SACKed skb with contradictory pcount/tx.in_flight +would not matter. However, with SACK reneging, the SACKed bit is +removed, and an skb once again becomes eligible for retransmitting, +fragmenting, SACKing, etc. Packetdrill testing verified the following +sequence is possible in a kernel that does not have this commit: + + - skb N is SACKed + - skb N+1 is SACKed and combined with skb N using tcp_shifted_skb() + - tcp_shifted_skb() will increase the pcount of prev, + but leave tx.in_flight as-is + - so prev skb can have pcount > tx.in_flight + - RTO, tcp_timeout_mark_lost(), detect reneg, + remove "SACKed" bit, mark skb N as lost + - find pcount of skb N is greater than its tx.in_flight + +I suspect this issue iw what caused the bbr2_inflight_hi_from_lost_skb(): + WARN_ON_ONCE(inflight_prev < 0) +to fire in production machines using bbr2. + +Effort: net-tcp_bbr +Origin-9xx-SHA1: 1a3e997e613d2dcf32b947992882854ebe873715 +Change-Id: I1b0b75c27519953430c7db51c6f358f104c7af55 +Signed-off-by: Alexandre Frade +--- + net/ipv4/tcp_input.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1506,6 +1506,17 @@ static bool tcp_shifted_skb(struct sock + WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); + tcp_skb_pcount_add(skb, -pcount); + ++ /* Adjust tx.in_flight as pcount is shifted from skb to prev. */ ++ if (WARN_ONCE(TCP_SKB_CB(skb)->tx.in_flight < pcount, ++ "prev in_flight: %u skb in_flight: %u pcount: %u", ++ TCP_SKB_CB(prev)->tx.in_flight, ++ TCP_SKB_CB(skb)->tx.in_flight, ++ pcount)) ++ TCP_SKB_CB(skb)->tx.in_flight = 0; ++ else ++ TCP_SKB_CB(skb)->tx.in_flight -= pcount; ++ TCP_SKB_CB(prev)->tx.in_flight += pcount; ++ + /* When we're adding to gso_segs == 1, gso_size will be zero, + * in theory this shouldn't be necessary but as long as DSACK + * code can come after this skb later on it's better to keep diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch new file mode 100644 index 000000000..5bd2fe09f --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -0,0 +1,97 @@ +From f64cb2d65d9412d32ae5e5261d2bd1ca650f8e8c Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Wed, 1 May 2019 20:16:25 -0400 +Subject: [PATCH 08/19] net-tcp_bbr: v2: adjust skb tx.in_flight upon split in + tcp_fragment() + +When we fragment an skb that has already been sent, we need to update +the tx.in_flight for the first skb in the resulting pair ("buff"). + +Because we were not updating the tx.in_flight, the tx.in_flight value +was inconsistent with the pcount of the "buff" skb (tx.in_flight would +be too high). That meant that if the "buff" skb was lost, then +bbr2_inflight_hi_from_lost_skb() would calculate an inflight_hi value +that is too high. This could result in longer queues and higher packet +loss. + +Packetdrill testing verified that without this commit, when the second +half of an skb is SACKed and then later the first half of that skb is +marked lost, the calculated inflight_hi was incorrect. + +Effort: net-tcp_bbr +Origin-9xx-SHA1: 385f1ddc610798fab2837f9f372857438b25f874 +Origin-9xx-SHA1: a0eb099690af net-tcp_bbr: v2: fix tcp_fragment() tx.in_flight recomputation [prod feb 8 2021; use as a fixup] +Origin-9xx-SHA1: 885503228153ff0c9114e net-tcp_bbr: v2: introduce tcp_skb_tx_in_flight_is_suspicious() helper for warnings +Change-Id: I617f8cab4e9be7a0b8e8d30b047bf8645393354d +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 15 +++++++++++++++ + net/ipv4/tcp_output.c | 26 +++++++++++++++++++++++++- + 2 files changed, 40 insertions(+), 1 deletion(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1283,6 +1283,21 @@ static inline bool tcp_skb_sent_after(u6 + return t1 > t2 || (t1 == t2 && after(seq1, seq2)); + } + ++/* If a retransmit failed due to local qdisc congestion or other local issues, ++ * then we may have called tcp_set_skb_tso_segs() to increase the number of ++ * segments in the skb without increasing the tx.in_flight. In all other cases, ++ * the tx.in_flight should be at least as big as the pcount of the sk_buff. We ++ * do not have the state to know whether a retransmit failed due to local qdisc ++ * congestion or other local issues, so to avoid spurious warnings we consider ++ * that any skb marked lost may have suffered that fate. ++ */ ++static inline bool tcp_skb_tx_in_flight_is_suspicious(u32 skb_pcount, ++ u32 skb_sacked_flags, ++ u32 tx_in_flight) ++{ ++ return (skb_pcount > tx_in_flight) && !(skb_sacked_flags & TCPCB_LOST); ++} ++ + /* These functions determine how the current flow behaves in respect of SACK + * handling. SACK is negotiated with the peer, and therefore it can vary + * between different flows. +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1601,7 +1601,7 @@ int tcp_fragment(struct sock *sk, enum t + { + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *buff; +- int old_factor; ++ int old_factor, inflight_prev; + long limit; + int nlen; + u8 flags; +@@ -1676,6 +1676,30 @@ int tcp_fragment(struct sock *sk, enum t + + if (diff) + tcp_adjust_pcount(sk, skb, diff); ++ ++ inflight_prev = TCP_SKB_CB(skb)->tx.in_flight - old_factor; ++ if (inflight_prev < 0) { ++ WARN_ONCE(tcp_skb_tx_in_flight_is_suspicious( ++ old_factor, ++ TCP_SKB_CB(skb)->sacked, ++ TCP_SKB_CB(skb)->tx.in_flight), ++ "inconsistent: tx.in_flight: %u " ++ "old_factor: %d mss: %u sacked: %u " ++ "1st pcount: %d 2nd pcount: %d " ++ "1st len: %u 2nd len: %u ", ++ TCP_SKB_CB(skb)->tx.in_flight, old_factor, ++ mss_now, TCP_SKB_CB(skb)->sacked, ++ tcp_skb_pcount(skb), tcp_skb_pcount(buff), ++ skb->len, buff->len); ++ inflight_prev = 0; ++ } ++ /* Set 1st tx.in_flight as if 1st were sent by itself: */ ++ TCP_SKB_CB(skb)->tx.in_flight = inflight_prev + ++ tcp_skb_pcount(skb); ++ /* Set 2nd tx.in_flight with new 1st and 2nd pcounts: */ ++ TCP_SKB_CB(buff)->tx.in_flight = inflight_prev + ++ tcp_skb_pcount(skb) + ++ tcp_skb_pcount(buff); + } + + /* Link BUFF into the send queue. */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch new file mode 100644 index 000000000..36eb1a373 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch @@ -0,0 +1,73 @@ +From d39a6429c0ec67f51478737f7a13f6295ca8b3c0 Mon Sep 17 00:00:00 2001 +From: Yousuk Seung +Date: Wed, 23 May 2018 17:55:54 -0700 +Subject: [PATCH 09/19] net-tcp: add new ca opts flag TCP_CONG_WANTS_CE_EVENTS + +Add a a new ca opts flag TCP_CONG_WANTS_CE_EVENTS that allows a +congestion control module to receive CE events. + +Currently congestion control modules have to set the TCP_CONG_NEEDS_ECN +bit in opts flag to receive CE events but this may incur changes in ECN +behavior elsewhere. This patch adds a new bit TCP_CONG_WANTS_CE_EVENTS +that allows congestion control modules to receive CE events +independently of TCP_CONG_NEEDS_ECN. + +Effort: net-tcp +Origin-9xx-SHA1: 9f7e14716cde760bc6c67ef8ef7e1ee48501d95b +Change-Id: I2255506985242f376d910c6fd37daabaf4744f24 +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 14 +++++++++++++- + net/ipv4/tcp_input.c | 4 ++-- + 2 files changed, 15 insertions(+), 3 deletions(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1119,7 +1119,11 @@ enum tcp_ca_ack_event_flags { + #define TCP_CONG_NON_RESTRICTED 0x1 + /* Requires ECN/ECT set on all packets */ + #define TCP_CONG_NEEDS_ECN 0x2 +-#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN) ++/* Wants notification of CE events (CA_EVENT_ECN_IS_CE, CA_EVENT_ECN_NO_CE). */ ++#define TCP_CONG_WANTS_CE_EVENTS 0x4 ++#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | \ ++ TCP_CONG_NEEDS_ECN | \ ++ TCP_CONG_WANTS_CE_EVENTS) + + union tcp_cc_info; + +@@ -1251,6 +1255,14 @@ static inline char *tcp_ca_get_name_by_k + } + #endif + ++static inline bool tcp_ca_wants_ce_events(const struct sock *sk) ++{ ++ const struct inet_connection_sock *icsk = inet_csk(sk); ++ ++ return icsk->icsk_ca_ops->flags & (TCP_CONG_NEEDS_ECN | ++ TCP_CONG_WANTS_CE_EVENTS); ++} ++ + static inline bool tcp_ca_needs_ecn(const struct sock *sk) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -370,7 +370,7 @@ static void __tcp_ecn_check_ce(struct so + tcp_enter_quickack_mode(sk, 2); + break; + case INET_ECN_CE: +- if (tcp_ca_needs_ecn(sk)) ++ if (tcp_ca_wants_ce_events(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_IS_CE); + + if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { +@@ -381,7 +381,7 @@ static void __tcp_ecn_check_ce(struct so + tp->ecn_flags |= TCP_ECN_SEEN; + break; + default: +- if (tcp_ca_needs_ecn(sk)) ++ if (tcp_ca_wants_ce_events(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_NO_CE); + tp->ecn_flags |= TCP_ECN_SEEN; + break; diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch new file mode 100644 index 000000000..07ad69959 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -0,0 +1,118 @@ +From 8b64cdb009d7624b4a233a89e510e3a92fee9e71 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Fri, 27 Sep 2019 17:10:26 -0400 +Subject: [PATCH 10/19] net-tcp: re-generalize TSO sizing in TCP CC module API + +Reorganize the API for CC modules so that the CC module once again +gets complete control of the TSO sizing decision. This is how the API +was set up around 2016 and the initial BBRv1 upstreaming. Later Eric +Dumazet simplified it. But with wider testing it now seems that to +avoid CPU regressions BBR needs to have a different TSO sizing +function. + +This is necessary to handle cases where there are many flows +bottlenecked on the sender host's NIC, in which case BBR's pacing rate +is much lower than CUBIC/Reno/DCTCP's. Why does this happen? Because +BBR's pacing rate adapts to the low bandwidth share each flow sees. By +contrast, CUBIC/Reno/DCTCP see no loss or ECN, so they grow a very +large cwnd, and thus large pacing rate and large TSO burst size. + +Change-Id: Ic8ccfdbe4010ee8d4bf6a6334c48a2fceb2171ea +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 4 ++-- + net/ipv4/tcp_bbr.c | 37 ++++++++++++++++++++++++++----------- + net/ipv4/tcp_output.c | 11 +++++------ + 3 files changed, 33 insertions(+), 19 deletions(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1185,8 +1185,8 @@ struct tcp_congestion_ops { + /* hook for packet ack accounting (optional) */ + void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); + +- /* override sysctl_tcp_min_tso_segs */ +- u32 (*min_tso_segs)(struct sock *sk); ++ /* pick target number of segments per TSO/GSO skb (optional): */ ++ u32 (*tso_segs)(struct sock *sk, unsigned int mss_now); + + /* react to a specific lost skb (optional) */ + void (*skb_marked_lost)(struct sock *sk, const struct sk_buff *skb); +--- a/net/ipv4/tcp_bbr.c ++++ b/net/ipv4/tcp_bbr.c +@@ -301,20 +301,35 @@ __bpf_kfunc static u32 bbr_min_tso_segs( + return READ_ONCE(sk->sk_pacing_rate) < (bbr_min_tso_rate >> 3) ? 1 : 2; + } + ++/* Return the number of segments BBR would like in a TSO/GSO skb, given ++ * a particular max gso size as a constraint. ++ */ ++static u32 bbr_tso_segs_generic(struct sock *sk, unsigned int mss_now, ++ u32 gso_max_size) ++{ ++ u32 segs; ++ u64 bytes; ++ ++ /* Budget a TSO/GSO burst size allowance based on bw (pacing_rate). */ ++ bytes = READ_ONCE(sk->sk_pacing_rate) >> READ_ONCE(sk->sk_pacing_shift); ++ ++ bytes = min_t(u32, bytes, gso_max_size - 1 - MAX_TCP_HEADER); ++ segs = max_t(u32, bytes / mss_now, bbr_min_tso_segs(sk)); ++ return segs; ++} ++ ++/* Custom tcp_tso_autosize() for BBR, used at transmit time to cap skb size. */ ++static u32 bbr_tso_segs(struct sock *sk, unsigned int mss_now) ++{ ++ return bbr_tso_segs_generic(sk, mss_now, sk->sk_gso_max_size); ++} ++ ++/* Like bbr_tso_segs(), using mss_cache, ignoring driver's sk_gso_max_size. */ + static u32 bbr_tso_segs_goal(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); +- u32 segs, bytes; +- +- /* Sort of tcp_tso_autosize() but ignoring +- * driver provided sk_gso_max_size. +- */ +- bytes = min_t(unsigned long, +- READ_ONCE(sk->sk_pacing_rate) >> READ_ONCE(sk->sk_pacing_shift), +- GSO_LEGACY_MAX_SIZE - 1 - MAX_TCP_HEADER); +- segs = max_t(u32, bytes / tp->mss_cache, bbr_min_tso_segs(sk)); + +- return min(segs, 0x7FU); ++ return bbr_tso_segs_generic(sk, tp->mss_cache, GSO_MAX_SIZE); + } + + /* Save "last known good" cwnd so we can restore it after losses or PROBE_RTT */ +@@ -1150,7 +1165,7 @@ static struct tcp_congestion_ops tcp_bbr + .undo_cwnd = bbr_undo_cwnd, + .cwnd_event = bbr_cwnd_event, + .ssthresh = bbr_ssthresh, +- .min_tso_segs = bbr_min_tso_segs, ++ .tso_segs = bbr_tso_segs, + .get_info = bbr_get_info, + .set_state = bbr_set_state, + }; +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -2057,13 +2057,12 @@ static u32 tcp_tso_autosize(const struct + static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) + { + const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; +- u32 min_tso, tso_segs; ++ u32 tso_segs; + +- min_tso = ca_ops->min_tso_segs ? +- ca_ops->min_tso_segs(sk) : +- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); +- +- tso_segs = tcp_tso_autosize(sk, mss_now, min_tso); ++ tso_segs = ca_ops->tso_segs ? ++ ca_ops->tso_segs(sk, mss_now) : ++ tcp_tso_autosize(sk, mss_now, ++ sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); + return min_t(u32, tso_segs, sk->sk_gso_max_segs); + } + diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch new file mode 100644 index 000000000..f2a9f15fa --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -0,0 +1,72 @@ +From 0ff8136eeca5fb038fdef3d8342838785df28685 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Sun, 7 Jan 2024 21:11:26 -0300 +Subject: [PATCH 11/19] net-tcp: add fast_ack_mode=1: skip rwin check in + tcp_fast_ack_mode__tcp_ack_snd_check() + +Add logic for an experimental TCP connection behavior, enabled with +tp->fast_ack_mode = 1, which disables checking the receive window +before sending an ack in __tcp_ack_snd_check(). If this behavior is +enabled, the data receiver sends an ACK if the amount of data is > +RCV.MSS. + +Change-Id: Iaa0a0fd7108221f883137a79d5bfa724f1b096d4 +Signed-off-by: Alexandre Frade +--- + include/linux/tcp.h | 3 ++- + net/ipv4/tcp.c | 1 + + net/ipv4/tcp_cong.c | 1 + + net/ipv4/tcp_input.c | 5 +++-- + 4 files changed, 7 insertions(+), 3 deletions(-) + +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -369,7 +369,8 @@ struct tcp_sock { + u8 compressed_ack; + u8 dup_ack_counter:2, + tlp_retrans:1, /* TLP is a retransmission */ +- unused:5; ++ fast_ack_mode:2, /* which fast ack mode ? */ ++ unused:3; + u8 thin_lto : 1,/* Use linear timeouts for thin streams */ + fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ + fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3123,6 +3123,7 @@ int tcp_disconnect(struct sock *sk, int + tp->rx_opt.dsack = 0; + tp->rx_opt.num_sacks = 0; + tp->rcv_ooopack = 0; ++ tp->fast_ack_mode = 0; + + + /* Clean up fastopen related fields */ +--- a/net/ipv4/tcp_cong.c ++++ b/net/ipv4/tcp_cong.c +@@ -237,6 +237,7 @@ void tcp_init_congestion_control(struct + struct inet_connection_sock *icsk = inet_csk(sk); + + tcp_sk(sk)->prior_ssthresh = 0; ++ tcp_sk(sk)->fast_ack_mode = 0; + if (icsk->icsk_ca_ops->init) + icsk->icsk_ca_ops->init(sk); + if (tcp_ca_needs_ecn(sk)) +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -5736,13 +5736,14 @@ static void __tcp_ack_snd_check(struct s + + /* More than one full frame received... */ + if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && ++ (tp->fast_ack_mode == 1 || + /* ... and right edge of window advances far enough. + * (tcp_recvmsg() will send ACK otherwise). + * If application uses SO_RCVLOWAT, we want send ack now if + * we have not received enough bytes to satisfy the condition. + */ +- (tp->rcv_nxt - tp->copied_seq < sk->sk_rcvlowat || +- __tcp_select_window(sk) >= tp->rcv_wnd)) || ++ (tp->rcv_nxt - tp->copied_seq < sk->sk_rcvlowat || ++ __tcp_select_window(sk) >= tp->rcv_wnd))) || + /* We ACK each frame or... */ + tcp_in_quickack_mode(sk) || + /* Protocol state mandates a one-time immediate ACK */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch new file mode 100644 index 000000000..1a2b75f6b --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -0,0 +1,45 @@ +From 399c324888acd78cd0cac5407e2dc27bb2225ba0 Mon Sep 17 00:00:00 2001 +From: Jianfeng Wang +Date: Fri, 19 Jun 2020 17:33:45 +0000 +Subject: [PATCH 12/19] net-tcp_bbr: v2: record app-limited status of + TLP-repaired flight + +When sending a TLP retransmit, record whether the outstanding flight +of data is application limited. This is important for congestion +control modules that want to respond to losses repaired by TLP +retransmits. This is important because the following scenarios convey +very different information: + (1) a packet loss with a small number of packets in flight; + (2) a packet loss with the maximum amount of data in flight allowed + by the CC module; + +Effort: net-tcp_bbr +Change-Id: Ic8ae567caa4e4bfd5fd82c3d4be12a5d9171655e +Signed-off-by: Alexandre Frade +--- + include/linux/tcp.h | 3 ++- + net/ipv4/tcp_output.c | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -370,7 +370,8 @@ struct tcp_sock { + u8 dup_ack_counter:2, + tlp_retrans:1, /* TLP is a retransmission */ + fast_ack_mode:2, /* which fast ack mode ? */ +- unused:3; ++ tlp_orig_data_app_limited:1, /* app-limited before TLP rtx? */ ++ unused:2; + u8 thin_lto : 1,/* Use linear timeouts for thin streams */ + fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ + fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -3005,6 +3005,7 @@ void tcp_send_loss_probe(struct sock *sk + if (WARN_ON(!skb || !tcp_skb_pcount(skb))) + goto rearm_timer; + ++ tp->tlp_orig_data_app_limited = TCP_SKB_CB(skb)->tx.is_app_limited; + if (__tcp_retransmit_skb(sk, skb, 1)) + goto rearm_timer; + diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch new file mode 100644 index 000000000..07a81e053 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -0,0 +1,45 @@ +From 43e59a05c78564807876ae8529c71b261e8cceff Mon Sep 17 00:00:00 2001 +From: Jianfeng Wang +Date: Tue, 16 Jun 2020 17:41:19 +0000 +Subject: [PATCH 13/19] net-tcp_bbr: v2: inform CC module of losses repaired by + TLP probe + +Before this commit, when there is a packet loss that creates a sequence +hole that is filled by a TLP loss probe, then tcp_process_tlp_ack() +only informs the congestion control (CC) module via a back-to-back entry +and exit of CWR. But some congestion control modules (e.g. BBR) do not +respond to CWR events. + +This commit adds a new CA event with which the core TCP stack notifies +the CC module when a loss is repaired by a TLP. This will allow CC +modules that do not use the CWR mechanism to have a custom handler for +such TLP recoveries. + +Effort: net-tcp_bbr +Change-Id: Ieba72332b401b329bff5a641d2b2043a3fb8f632 +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 1 + + net/ipv4/tcp_input.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1097,6 +1097,7 @@ enum tcp_ca_event { + CA_EVENT_LOSS, /* loss timeout */ + CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ + CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ ++ CA_EVENT_TLP_RECOVERY, /* a lost segment was repaired by TLP probe */ + }; + + /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3832,6 +3832,7 @@ static void tcp_process_tlp_ack(struct s + /* ACK advances: there was a loss, so reduce cwnd. Reset + * tlp_high_seq in tcp_init_cwnd_reduction() + */ ++ tcp_ca_event(sk, CA_EVENT_TLP_RECOVERY); + tcp_init_cwnd_reduction(sk); + tcp_set_ca_state(sk, TCP_CA_CWR); + tcp_end_cwnd_reduction(sk); diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch new file mode 100644 index 000000000..51dd16b51 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -0,0 +1,73 @@ +From e8c17561fd4afb5966cb8e434375c26dd80e876b Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Mon, 21 Sep 2020 14:46:26 -0400 +Subject: [PATCH 14/19] net-tcp_bbr: v2: introduce is_acking_tlp_retrans_seq + into rate_sample + +Introduce is_acking_tlp_retrans_seq into rate_sample. This bool will +export to the CC module the knowledge of whether the current ACK +matched a TLP retransmit. + +Note that when this bool is true, we cannot yet tell (in general) whether +this ACK is for the original or the TLP retransmit. + +Effort: net-tcp_bbr +Change-Id: I2e6494332167e75efcbdc99bd5c119034e9c39b4 +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 1 + + net/ipv4/tcp_input.c | 12 +++++++++--- + 2 files changed, 10 insertions(+), 3 deletions(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1161,6 +1161,7 @@ struct rate_sample { + u32 last_end_seq; /* end_seq of most recently ACKed packet */ + bool is_app_limited; /* is sample from packet with bubble in pipe? */ + bool is_retrans; /* is sample from retransmission? */ ++ bool is_acking_tlp_retrans_seq; /* ACKed a TLP retransmit sequence? */ + bool is_ack_delayed; /* is this (likely) a delayed ACK? */ + bool is_ece; /* did this ACK have ECN marked? */ + }; +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3815,7 +3815,8 @@ static void tcp_replace_ts_recent(struct + /* This routine deals with acks during a TLP episode and ends an episode by + * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack + */ +-static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) ++static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag, ++ struct rate_sample *rs) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -3843,6 +3844,11 @@ static void tcp_process_tlp_ack(struct s + FLAG_NOT_DUP | FLAG_DATA_SACKED))) { + /* Pure dupack: original and TLP probe arrived; no loss */ + tp->tlp_high_seq = 0; ++ } else { ++ /* This ACK matches a TLP retransmit. We cannot yet tell if ++ * this ACK is for the original or the TLP retransmit. ++ */ ++ rs->is_acking_tlp_retrans_seq = 1; + } + } + +@@ -4026,7 +4032,7 @@ static int tcp_ack(struct sock *sk, cons + tcp_rack_update_reo_wnd(sk, &rs); + + if (tp->tlp_high_seq) +- tcp_process_tlp_ack(sk, ack, flag); ++ tcp_process_tlp_ack(sk, ack, flag, &rs); + + if (tcp_ack_is_dubious(sk, flag)) { + if (!(flag & (FLAG_SND_UNA_ADVANCED | +@@ -4070,7 +4076,7 @@ no_queue: + tcp_ack_probe(sk); + + if (tp->tlp_high_seq) +- tcp_process_tlp_ack(sk, ack, flag); ++ tcp_process_tlp_ack(sk, ack, flag, &rs); + return 1; + + old_ack: diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch new file mode 100644 index 000000000..06249605f --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch @@ -0,0 +1,112 @@ +From 55d8a135e42feec3aa24d2aac411fb658374532f Mon Sep 17 00:00:00 2001 +From: David Morley +Date: Fri, 14 Jul 2023 11:07:56 -0400 +Subject: [PATCH 15/19] tcp: introduce per-route feature RTAX_FEATURE_ECN_LOW + +Define and implement a new per-route feature, RTAX_FEATURE_ECN_LOW. + +This feature indicates that the given destination network is a +low-latency ECN environment, meaning both that ECN CE marks are +applied by the network using a low-latency marking threshold and also +that TCP endpoints provide precise per-data-segment ECN feedback in +ACKs (where the ACK ECE flag echoes the received CE status of all +newly-acknowledged data segments). This feature indication can be used +by congestion control algorithms to decide how to interpret ECN +signals over the given destination network. + +This feature is appropriate for datacenter-style ECN marking, such as +the ECN marking approach expected by DCTCP or BBR congestion control +modules. + +Signed-off-by: David Morley +Signed-off-by: Neal Cardwell +Signed-off-by: Yuchung Cheng +Tested-by: David Morley +Change-Id: I6bc06e9c6cb426fbae7243fc71c9a8c18175f5d3 +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 10 ++++++++++ + include/uapi/linux/rtnetlink.h | 4 +++- + net/ipv4/tcp_minisocks.c | 2 ++ + net/ipv4/tcp_output.c | 6 ++++-- + 4 files changed, 19 insertions(+), 3 deletions(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -375,6 +375,7 @@ static inline void tcp_dec_quickack_mode + #define TCP_ECN_QUEUE_CWR 2 + #define TCP_ECN_DEMAND_CWR 4 + #define TCP_ECN_SEEN 8 ++#define TCP_ECN_LOW 16 + + enum tcp_tw_status { + TCP_TW_SUCCESS = 0, +@@ -777,6 +778,15 @@ static inline void tcp_fast_path_check(s + tcp_fast_path_on(tp); + } + ++static inline void tcp_set_ecn_low_from_dst(struct sock *sk, ++ const struct dst_entry *dst) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ if (dst_feature(dst, RTAX_FEATURE_ECN_LOW)) ++ tp->ecn_flags |= TCP_ECN_LOW; ++} ++ + u32 tcp_delack_max(const struct sock *sk); + + /* Compute the actual rto_min value */ +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -507,12 +507,14 @@ enum { + #define RTAX_FEATURE_TIMESTAMP (1 << 2) /* unused */ + #define RTAX_FEATURE_ALLFRAG (1 << 3) /* unused */ + #define RTAX_FEATURE_TCP_USEC_TS (1 << 4) ++#define RTAX_FEATURE_ECN_LOW (1 << 5) + + #define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | \ + RTAX_FEATURE_SACK | \ + RTAX_FEATURE_TIMESTAMP | \ + RTAX_FEATURE_ALLFRAG | \ +- RTAX_FEATURE_TCP_USEC_TS) ++ RTAX_FEATURE_TCP_USEC_TS | \ ++ RTAX_FEATURE_ECN_LOW) + + struct rta_session { + __u8 proto; +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -459,6 +459,8 @@ void tcp_ca_openreq_child(struct sock *s + u32 ca_key = dst_metric(dst, RTAX_CC_ALGO); + bool ca_got_dst = false; + ++ tcp_set_ecn_low_from_dst(sk, dst); ++ + if (ca_key != TCP_CA_UNSPEC) { + const struct tcp_congestion_ops *ca; + +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -336,10 +336,9 @@ static void tcp_ecn_send_syn(struct sock + bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk); + bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 || + tcp_ca_needs_ecn(sk) || bpf_needs_ecn; ++ const struct dst_entry *dst = __sk_dst_get(sk); + + if (!use_ecn) { +- const struct dst_entry *dst = __sk_dst_get(sk); +- + if (dst && dst_feature(dst, RTAX_FEATURE_ECN)) + use_ecn = true; + } +@@ -351,6 +350,9 @@ static void tcp_ecn_send_syn(struct sock + tp->ecn_flags = TCP_ECN_OK; + if (tcp_ca_needs_ecn(sk) || bpf_needs_ecn) + INET_ECN_xmit(sk); ++ ++ if (dst) ++ tcp_set_ecn_low_from_dst(sk, dst); + } + } + diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch new file mode 100644 index 000000000..4c71cb850 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -0,0 +1,2821 @@ +From c0643f854de456c761c18b009af7537a74506724 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Tue, 11 Jun 2019 12:54:22 -0400 +Subject: [PATCH 16/19] net-tcp_bbr: v3: update TCP "bbr" congestion control + module to BBRv3 + +BBR v3 is an enhacement to the BBR v1 algorithm. It's designed to aim for lower +queues, lower loss, and better Reno/CUBIC coexistence than BBR v1. + +BBR v3 maintains the core of BBR v1: an explicit model of the network +path that is two-dimensional, adapting to estimate the (a) maximum +available bandwidth and (b) maximum safe volume of data a flow can +keep in-flight in the network. It maintains the estimated BDP as a +core guide for estimating an appropriate level of in-flight data. + +BBR v3 makes several key enhancements: + +o Its bandwidth-probing time scale is adapted, within bounds, to allow improved +coexistence with Reno and CUBIC. The bandwidth-probing time scale is (a) +extended dynamically based on estimated BDP to improve coexistence with +Reno/CUBIC; (b) bounded by an interactive wall-clock time-scale to be more +scalable and responsive than Reno and CUBIC. + +o Rather than being largely agnostic to loss and ECN marks, it explicitly uses +loss and (DCTCP-style) ECN signals to maintain its model. + +o It aims for lower losses than v1 by adjusting its model to attempt to stay +within loss rate and ECN mark rate bounds (loss_thresh and ecn_thresh, +respectively). + +o It adapts to loss/ECN signals even when the application is running out of +data ("application-limited"), in case the "application-limited" flow is also +"network-limited" (the bw and/or inflight available to this flow is lower than +previously estimated when the flow ran out of data). + +o It has a three-part model: the model explicit three tracks operating points, +where an operating point is a tuple: (bandwidth, inflight). The three operating +points are: + + o latest: the latest measurement from the current round trip + o upper bound: robust, optimistic, long-term upper bound + o lower bound: robust, conservative, short-term lower bound + +These are stored in the following state variables: + + o latest: bw_latest, inflight_latest + o lo: bw_lo, inflight_lo + o hi: bw_hi[2], inflight_hi + +To gain intuition about the meaning of the three operating points, it +may help to consider the analogs in CUBIC, which has a somewhat +analogous three-part model used by its probing state machine: + + BBR param CUBIC param + ----------- ------------- + latest ~ cwnd + lo ~ ssthresh + hi ~ last_max_cwnd + +The analogy is only a loose one, though, since the BBR operating +points are calculated differently, and are 2-dimensional (bw,inflight) +rather than CUBIC's one-dimensional notion of operating point +(inflight). + +o It uses the three-part model to adapt the magnitude of its bandwidth +to match the estimated space available in the buffer, rather than (as +in BBR v1) assuming that it was always acceptable to place 0.25*BDP in +the bottleneck buffer when probing (commodity datacenter switches +commonly do not have that much buffer for WAN flows). When BBR v3 +estimates it hit a buffer limit during probing, its bandwidth probing +then starts gently in case little space is still available in the +buffer, and the accelerates, slowly at first and then rapidly if it +can grow inflight without seeing congestion signals. In such cases, +probing is bounded by inflight_hi + inflight_probe, where +inflight_probe grows as: [0, 1, 2, 4, 8, 16,...]. This allows BBR to +keep losses low and bounded if a bottleneck remains congested, while +rapidly/scalably utilizing free bandwidth when it becomes available. + +o It has a slightly revised state machine, to achieve the goals above. + BBR_BW_PROBE_UP: pushes up inflight to probe for bw/vol + BBR_BW_PROBE_DOWN: drain excess inflight from the queue + BBR_BW_PROBE_CRUISE: use pipe, w/ headroom in queue/pipe + BBR_BW_PROBE_REFILL: try refill the pipe again to 100%, leaving queue empty + +o The estimated BDP: BBR v3 continues to maintain an estimate of the +path's two-way propagation delay, by tracking a windowed min_rtt, and +coordinating (on an as-ndeeded basis) to try to expose the two-way +propagation delay by draining the bottleneck queue. + +BBR v3 continues to use its min_rtt and (currently-applicable) bandwidth +estimate to estimate the current bandwidth-delay product. The estimated BDP +still provides one important guideline for bounding inflight data. However, +because any min-filtered RTT and max-filtered bw inherently tend to both +overestimate, the estimated BDP is often too high; in this case loss or ECN +marks can ensue, in which case BBR v3 adjusts inflight_hi and inflight_lo to +adapt its sending rate and inflight down to match the available capacity of the +path. + +o Space: Note that ICSK_CA_PRIV_SIZE increased. This is because BBR v3 +requires more space. Note that much of the space is due to support for +per-socket parameterization and debugging in this release for research +and debugging. With that state removed, the full "struct bbr" is 140 +bytes, or 144 with padding. This is an increase of 40 bytes over the +existing ca_priv space. + +o Code: BBR v3 reuses many pieces from BBR v1. But it omits the following + significant pieces: + + o "packet conservation" (bbr_set_cwnd_to_recover_or_restore(), + bbr_can_grow_inflight()) + o long-term bandwidth estimator ("policer mode") + + The code layout tries to keep BBR v3 code near the bottom of the + file, so that v1-applicable code in the top does not accidentally + refer to v3 code. + +o Docs: + See the following docs for more details and diagrams decsribing the BBR v3 + algorithm: + https://datatracker.ietf.org/meeting/104/materials/slides-104-iccrg-an-update-on-bbr-00 + https://datatracker.ietf.org/meeting/102/materials/slides-102-iccrg-an-update-on-bbr-work-at-google-00 + +o Internal notes: + For this upstream rebase, Neal started from: + git show fed518041ac6:net/ipv4/tcp_bbr.c > net/ipv4/tcp_bbr.c + then removed dev instrumentation (dynamic get/set for parameters) + and code that was only used by BBRv1 + +Effort: net-tcp_bbr +Origin-9xx-SHA1: 2c84098e60bed6d67dde23cd7538c51dee273102 +Change-Id: I125cf26ba2a7a686f2fa5e87f4c2afceb65f7a05 +Signed-off-by: Alexandre Frade +--- + include/net/inet_connection_sock.h | 4 +- + include/net/tcp.h | 2 +- + include/uapi/linux/inet_diag.h | 23 + + net/ipv4/Kconfig | 21 +- + net/ipv4/tcp_bbr.c | 2214 +++++++++++++++++++++------- + 5 files changed, 1740 insertions(+), 524 deletions(-) + +--- a/include/net/inet_connection_sock.h ++++ b/include/net/inet_connection_sock.h +@@ -137,8 +137,8 @@ struct inet_connection_sock { + u32 icsk_probes_tstamp; + u32 icsk_user_timeout; + +- u64 icsk_ca_priv[104 / sizeof(u64)]; +-#define ICSK_CA_PRIV_SIZE sizeof_field(struct inet_connection_sock, icsk_ca_priv) ++#define ICSK_CA_PRIV_SIZE (144) ++ u64 icsk_ca_priv[ICSK_CA_PRIV_SIZE / sizeof(u64)]; + }; + + #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -2473,7 +2473,7 @@ struct tcp_plb_state { + u8 consec_cong_rounds:5, /* consecutive congested rounds */ + unused:3; + u32 pause_until; /* jiffies32 when PLB can resume rerouting */ +-}; ++} __attribute__ ((__packed__)); + + static inline void tcp_plb_init(const struct sock *sk, + struct tcp_plb_state *plb) +--- a/include/uapi/linux/inet_diag.h ++++ b/include/uapi/linux/inet_diag.h +@@ -229,6 +229,29 @@ struct tcp_bbr_info { + __u32 bbr_min_rtt; /* min-filtered RTT in uSec */ + __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */ + __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */ ++ __u32 bbr_bw_hi_lsb; /* lower 32 bits of bw_hi */ ++ __u32 bbr_bw_hi_msb; /* upper 32 bits of bw_hi */ ++ __u32 bbr_bw_lo_lsb; /* lower 32 bits of bw_lo */ ++ __u32 bbr_bw_lo_msb; /* upper 32 bits of bw_lo */ ++ __u8 bbr_mode; /* current bbr_mode in state machine */ ++ __u8 bbr_phase; /* current state machine phase */ ++ __u8 unused1; /* alignment padding; not used yet */ ++ __u8 bbr_version; /* BBR algorithm version */ ++ __u32 bbr_inflight_lo; /* lower short-term data volume bound */ ++ __u32 bbr_inflight_hi; /* higher long-term data volume bound */ ++ __u32 bbr_extra_acked; /* max excess packets ACKed in epoch */ ++}; ++ ++/* TCP BBR congestion control bbr_phase as reported in netlink/ss stats. */ ++enum tcp_bbr_phase { ++ BBR_PHASE_INVALID = 0, ++ BBR_PHASE_STARTUP = 1, ++ BBR_PHASE_DRAIN = 2, ++ BBR_PHASE_PROBE_RTT = 3, ++ BBR_PHASE_PROBE_BW_UP = 4, ++ BBR_PHASE_PROBE_BW_DOWN = 5, ++ BBR_PHASE_PROBE_BW_CRUISE = 6, ++ BBR_PHASE_PROBE_BW_REFILL = 7, + }; + + union tcp_cc_info { +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -668,15 +668,18 @@ config TCP_CONG_BBR + default n + help + +- BBR (Bottleneck Bandwidth and RTT) TCP congestion control aims to +- maximize network utilization and minimize queues. It builds an explicit +- model of the bottleneck delivery rate and path round-trip propagation +- delay. It tolerates packet loss and delay unrelated to congestion. It +- can operate over LAN, WAN, cellular, wifi, or cable modem links. It can +- coexist with flows that use loss-based congestion control, and can +- operate with shallow buffers, deep buffers, bufferbloat, policers, or +- AQM schemes that do not provide a delay signal. It requires the fq +- ("Fair Queue") pacing packet scheduler. ++ BBR (Bottleneck Bandwidth and RTT) TCP congestion control is a ++ model-based congestion control algorithm that aims to maximize ++ network utilization, keep queues and retransmit rates low, and to be ++ able to coexist with Reno/CUBIC in common scenarios. It builds an ++ explicit model of the network path. It tolerates a targeted degree ++ of random packet loss and delay. It can operate over LAN, WAN, ++ cellular, wifi, or cable modem links, and can use shallow-threshold ++ ECN signals. It can coexist to some degree with flows that use ++ loss-based congestion control, and can operate with shallow buffers, ++ deep buffers, bufferbloat, policers, or AQM schemes that do not ++ provide a delay signal. It requires pacing, using either TCP internal ++ pacing or the fq ("Fair Queue") pacing packet scheduler. + + choice + prompt "Default TCP congestion control" +--- a/net/ipv4/tcp_bbr.c ++++ b/net/ipv4/tcp_bbr.c +@@ -1,18 +1,19 @@ +-/* Bottleneck Bandwidth and RTT (BBR) congestion control ++/* BBR (Bottleneck Bandwidth and RTT) congestion control + * +- * BBR congestion control computes the sending rate based on the delivery +- * rate (throughput) estimated from ACKs. In a nutshell: ++ * BBR is a model-based congestion control algorithm that aims for low queues, ++ * low loss, and (bounded) Reno/CUBIC coexistence. To maintain a model of the ++ * network path, it uses measurements of bandwidth and RTT, as well as (if they ++ * occur) packet loss and/or shallow-threshold ECN signals. Note that although ++ * it can use ECN or loss signals explicitly, it does not require either; it ++ * can bound its in-flight data based on its estimate of the BDP. + * +- * On each ACK, update our model of the network path: +- * bottleneck_bandwidth = windowed_max(delivered / elapsed, 10 round trips) +- * min_rtt = windowed_min(rtt, 10 seconds) +- * pacing_rate = pacing_gain * bottleneck_bandwidth +- * cwnd = max(cwnd_gain * bottleneck_bandwidth * min_rtt, 4) +- * +- * The core algorithm does not react directly to packet losses or delays, +- * although BBR may adjust the size of next send per ACK when loss is +- * observed, or adjust the sending rate if it estimates there is a +- * traffic policer, in order to keep the drop rate reasonable. ++ * The model has both higher and lower bounds for the operating range: ++ * lo: bw_lo, inflight_lo: conservative short-term lower bound ++ * hi: bw_hi, inflight_hi: robust long-term upper bound ++ * The bandwidth-probing time scale is (a) extended dynamically based on ++ * estimated BDP to improve coexistence with Reno/CUBIC; (b) bounded by ++ * an interactive wall-clock time-scale to be more scalable and responsive ++ * than Reno and CUBIC. + * + * Here is a state transition diagram for BBR: + * +@@ -65,6 +66,13 @@ + #include + #include + ++#include ++#include "tcp_dctcp.h" ++ ++#define BBR_VERSION 3 ++ ++#define bbr_param(sk,name) (bbr_ ## name) ++ + /* Scale factor for rate in pkt/uSec unit to avoid truncation in bandwidth + * estimation. The rate unit ~= (1500 bytes / 1 usec / 2^24) ~= 715 bps. + * This handles bandwidths from 0.06pps (715bps) to 256Mpps (3Tbps) in a u32. +@@ -85,36 +93,41 @@ enum bbr_mode { + BBR_PROBE_RTT, /* cut inflight to min to probe min_rtt */ + }; + ++/* How does the incoming ACK stream relate to our bandwidth probing? */ ++enum bbr_ack_phase { ++ BBR_ACKS_INIT, /* not probing; not getting probe feedback */ ++ BBR_ACKS_REFILLING, /* sending at est. bw to fill pipe */ ++ BBR_ACKS_PROBE_STARTING, /* inflight rising to probe bw */ ++ BBR_ACKS_PROBE_FEEDBACK, /* getting feedback from bw probing */ ++ BBR_ACKS_PROBE_STOPPING, /* stopped probing; still getting feedback */ ++}; ++ + /* BBR congestion control block */ + struct bbr { + u32 min_rtt_us; /* min RTT in min_rtt_win_sec window */ + u32 min_rtt_stamp; /* timestamp of min_rtt_us */ + u32 probe_rtt_done_stamp; /* end time for BBR_PROBE_RTT mode */ +- struct minmax bw; /* Max recent delivery rate in pkts/uS << 24 */ +- u32 rtt_cnt; /* count of packet-timed rounds elapsed */ ++ u32 probe_rtt_min_us; /* min RTT in probe_rtt_win_ms win */ ++ u32 probe_rtt_min_stamp; /* timestamp of probe_rtt_min_us*/ + u32 next_rtt_delivered; /* scb->tx.delivered at end of round */ + u64 cycle_mstamp; /* time of this cycle phase start */ +- u32 mode:3, /* current bbr_mode in state machine */ ++ u32 mode:2, /* current bbr_mode in state machine */ + prev_ca_state:3, /* CA state on previous ACK */ +- packet_conservation:1, /* use packet conservation? */ + round_start:1, /* start of packet-timed tx->ack round? */ ++ ce_state:1, /* If most recent data has CE bit set */ ++ bw_probe_up_rounds:5, /* cwnd-limited rounds in PROBE_UP */ ++ try_fast_path:1, /* can we take fast path? */ + idle_restart:1, /* restarting after idle? */ + probe_rtt_round_done:1, /* a BBR_PROBE_RTT round at 4 pkts? */ +- unused:13, +- lt_is_sampling:1, /* taking long-term ("LT") samples now? */ +- lt_rtt_cnt:7, /* round trips in long-term interval */ +- lt_use_bw:1; /* use lt_bw as our bw estimate? */ +- u32 lt_bw; /* LT est delivery rate in pkts/uS << 24 */ +- u32 lt_last_delivered; /* LT intvl start: tp->delivered */ +- u32 lt_last_stamp; /* LT intvl start: tp->delivered_mstamp */ +- u32 lt_last_lost; /* LT intvl start: tp->lost */ ++ init_cwnd:7, /* initial cwnd */ ++ unused_1:10; + u32 pacing_gain:10, /* current gain for setting pacing rate */ + cwnd_gain:10, /* current gain for setting cwnd */ + full_bw_reached:1, /* reached full bw in Startup? */ + full_bw_cnt:2, /* number of rounds without large bw gains */ +- cycle_idx:3, /* current index in pacing_gain cycle array */ ++ cycle_idx:2, /* current index in pacing_gain cycle array */ + has_seen_rtt:1, /* have we seen an RTT sample yet? */ +- unused_b:5; ++ unused_2:6; + u32 prior_cwnd; /* prior cwnd upon entering loss recovery */ + u32 full_bw; /* recent bw, to estimate if pipe is full */ + +@@ -124,19 +137,67 @@ struct bbr { + u32 ack_epoch_acked:20, /* packets (S)ACKed in sampling epoch */ + extra_acked_win_rtts:5, /* age of extra_acked, in round trips */ + extra_acked_win_idx:1, /* current index in extra_acked array */ +- unused_c:6; ++ /* BBR v3 state: */ ++ full_bw_now:1, /* recently reached full bw plateau? */ ++ startup_ecn_rounds:2, /* consecutive hi ECN STARTUP rounds */ ++ loss_in_cycle:1, /* packet loss in this cycle? */ ++ ecn_in_cycle:1, /* ECN in this cycle? */ ++ unused_3:1; ++ u32 loss_round_delivered; /* scb->tx.delivered ending loss round */ ++ u32 undo_bw_lo; /* bw_lo before latest losses */ ++ u32 undo_inflight_lo; /* inflight_lo before latest losses */ ++ u32 undo_inflight_hi; /* inflight_hi before latest losses */ ++ u32 bw_latest; /* max delivered bw in last round trip */ ++ u32 bw_lo; /* lower bound on sending bandwidth */ ++ u32 bw_hi[2]; /* max recent measured bw sample */ ++ u32 inflight_latest; /* max delivered data in last round trip */ ++ u32 inflight_lo; /* lower bound of inflight data range */ ++ u32 inflight_hi; /* upper bound of inflight data range */ ++ u32 bw_probe_up_cnt; /* packets delivered per inflight_hi incr */ ++ u32 bw_probe_up_acks; /* packets (S)ACKed since inflight_hi incr */ ++ u32 probe_wait_us; /* PROBE_DOWN until next clock-driven probe */ ++ u32 prior_rcv_nxt; /* tp->rcv_nxt when CE state last changed */ ++ u32 ecn_eligible:1, /* sender can use ECN (RTT, handshake)? */ ++ ecn_alpha:9, /* EWMA delivered_ce/delivered; 0..256 */ ++ bw_probe_samples:1, /* rate samples reflect bw probing? */ ++ prev_probe_too_high:1, /* did last PROBE_UP go too high? */ ++ stopped_risky_probe:1, /* last PROBE_UP stopped due to risk? */ ++ rounds_since_probe:8, /* packet-timed rounds since probed bw */ ++ loss_round_start:1, /* loss_round_delivered round trip? */ ++ loss_in_round:1, /* loss marked in this round trip? */ ++ ecn_in_round:1, /* ECN marked in this round trip? */ ++ ack_phase:3, /* bbr_ack_phase: meaning of ACKs */ ++ loss_events_in_round:4,/* losses in STARTUP round */ ++ initialized:1; /* has bbr_init() been called? */ ++ u32 alpha_last_delivered; /* tp->delivered at alpha update */ ++ u32 alpha_last_delivered_ce; /* tp->delivered_ce at alpha update */ ++ ++ u8 unused_4; /* to preserve alignment */ ++ struct tcp_plb_state plb; + }; + +-#define CYCLE_LEN 8 /* number of phases in a pacing gain cycle */ ++struct bbr_context { ++ u32 sample_bw; ++}; + +-/* Window length of bw filter (in rounds): */ +-static const int bbr_bw_rtts = CYCLE_LEN + 2; + /* Window length of min_rtt filter (in sec): */ + static const u32 bbr_min_rtt_win_sec = 10; + /* Minimum time (in ms) spent at bbr_cwnd_min_target in BBR_PROBE_RTT mode: */ + static const u32 bbr_probe_rtt_mode_ms = 200; +-/* Skip TSO below the following bandwidth (bits/sec): */ +-static const int bbr_min_tso_rate = 1200000; ++/* Window length of probe_rtt_min_us filter (in ms), and consequently the ++ * typical interval between PROBE_RTT mode entries. The default is 5000ms. ++ * Note that bbr_probe_rtt_win_ms must be <= bbr_min_rtt_win_sec * MSEC_PER_SEC ++ */ ++static const u32 bbr_probe_rtt_win_ms = 5000; ++/* Proportion of cwnd to estimated BDP in PROBE_RTT, in units of BBR_UNIT: */ ++static const u32 bbr_probe_rtt_cwnd_gain = BBR_UNIT * 1 / 2; ++ ++/* Use min_rtt to help adapt TSO burst size, with smaller min_rtt resulting ++ * in bigger TSO bursts. We cut the RTT-based allowance in half ++ * for every 2^9 usec (aka 512 us) of RTT, so that the RTT-based allowance ++ * is below 1500 bytes after 6 * ~500 usec = 3ms. ++ */ ++static const u32 bbr_tso_rtt_shift = 9; + + /* Pace at ~1% below estimated bw, on average, to reduce queue at bottleneck. + * In order to help drive the network toward lower queues and low latency while +@@ -146,13 +207,15 @@ static const int bbr_min_tso_rate = 1200 + */ + static const int bbr_pacing_margin_percent = 1; + +-/* We use a high_gain value of 2/ln(2) because it's the smallest pacing gain ++/* We use a startup_pacing_gain of 4*ln(2) because it's the smallest value + * that will allow a smoothly increasing pacing rate that will double each RTT + * and send the same number of packets per RTT that an un-paced, slow-starting + * Reno or CUBIC flow would: + */ +-static const int bbr_high_gain = BBR_UNIT * 2885 / 1000 + 1; +-/* The pacing gain of 1/high_gain in BBR_DRAIN is calculated to typically drain ++static const int bbr_startup_pacing_gain = BBR_UNIT * 277 / 100 + 1; ++/* The gain for deriving startup cwnd: */ ++static const int bbr_startup_cwnd_gain = BBR_UNIT * 2; ++/* The pacing gain in BBR_DRAIN is calculated to typically drain + * the queue created in BBR_STARTUP in a single round: + */ + static const int bbr_drain_gain = BBR_UNIT * 1000 / 2885; +@@ -160,13 +223,17 @@ static const int bbr_drain_gain = BBR_UN + static const int bbr_cwnd_gain = BBR_UNIT * 2; + /* The pacing_gain values for the PROBE_BW gain cycle, to discover/share bw: */ + static const int bbr_pacing_gain[] = { +- BBR_UNIT * 5 / 4, /* probe for more available bw */ +- BBR_UNIT * 3 / 4, /* drain queue and/or yield bw to other flows */ +- BBR_UNIT, BBR_UNIT, BBR_UNIT, /* cruise at 1.0*bw to utilize pipe, */ +- BBR_UNIT, BBR_UNIT, BBR_UNIT /* without creating excess queue... */ ++ BBR_UNIT * 5 / 4, /* UP: probe for more available bw */ ++ BBR_UNIT * 91 / 100, /* DOWN: drain queue and/or yield bw */ ++ BBR_UNIT, /* CRUISE: try to use pipe w/ some headroom */ ++ BBR_UNIT, /* REFILL: refill pipe to estimated 100% */ ++}; ++enum bbr_pacing_gain_phase { ++ BBR_BW_PROBE_UP = 0, /* push up inflight to probe for bw/vol */ ++ BBR_BW_PROBE_DOWN = 1, /* drain excess inflight from the queue */ ++ BBR_BW_PROBE_CRUISE = 2, /* use pipe, w/ headroom in queue/pipe */ ++ BBR_BW_PROBE_REFILL = 3, /* v2: refill the pipe again to 100% */ + }; +-/* Randomize the starting gain cycling phase over N phases: */ +-static const u32 bbr_cycle_rand = 7; + + /* Try to keep at least this many packets in flight, if things go smoothly. For + * smooth functioning, a sliding window protocol ACKing every other packet +@@ -174,24 +241,12 @@ static const u32 bbr_cycle_rand = 7; + */ + static const u32 bbr_cwnd_min_target = 4; + +-/* To estimate if BBR_STARTUP mode (i.e. high_gain) has filled pipe... */ ++/* To estimate if BBR_STARTUP or BBR_BW_PROBE_UP has filled pipe... */ + /* If bw has increased significantly (1.25x), there may be more bw available: */ + static const u32 bbr_full_bw_thresh = BBR_UNIT * 5 / 4; + /* But after 3 rounds w/o significant bw growth, estimate pipe is full: */ + static const u32 bbr_full_bw_cnt = 3; + +-/* "long-term" ("LT") bandwidth estimator parameters... */ +-/* The minimum number of rounds in an LT bw sampling interval: */ +-static const u32 bbr_lt_intvl_min_rtts = 4; +-/* If lost/delivered ratio > 20%, interval is "lossy" and we may be policed: */ +-static const u32 bbr_lt_loss_thresh = 50; +-/* If 2 intervals have a bw ratio <= 1/8, their bw is "consistent": */ +-static const u32 bbr_lt_bw_ratio = BBR_UNIT / 8; +-/* If 2 intervals have a bw diff <= 4 Kbit/sec their bw is "consistent": */ +-static const u32 bbr_lt_bw_diff = 4000 / 8; +-/* If we estimate we're policed, use lt_bw for this many round trips: */ +-static const u32 bbr_lt_bw_max_rtts = 48; +- + /* Gain factor for adding extra_acked to target cwnd: */ + static const int bbr_extra_acked_gain = BBR_UNIT; + /* Window length of extra_acked window. */ +@@ -201,8 +256,121 @@ static const u32 bbr_ack_epoch_acked_res + /* Time period for clamping cwnd increment due to ack aggregation */ + static const u32 bbr_extra_acked_max_us = 100 * 1000; + ++/* Flags to control BBR ECN-related behavior... */ ++ ++/* Ensure ACKs only ACK packets with consistent ECN CE status? */ ++static const bool bbr_precise_ece_ack = true; ++ ++/* Max RTT (in usec) at which to use sender-side ECN logic. ++ * Disabled when 0 (ECN allowed at any RTT). ++ */ ++static const u32 bbr_ecn_max_rtt_us = 5000; ++ ++/* On losses, scale down inflight and pacing rate by beta scaled by BBR_SCALE. ++ * No loss response when 0. ++ */ ++static const u32 bbr_beta = BBR_UNIT * 30 / 100; ++ ++/* Gain factor for ECN mark ratio samples, scaled by BBR_SCALE (1/16 = 6.25%) */ ++static const u32 bbr_ecn_alpha_gain = BBR_UNIT * 1 / 16; ++ ++/* The initial value for ecn_alpha; 1.0 allows a flow to respond quickly ++ * to congestion if the bottleneck is congested when the flow starts up. ++ */ ++static const u32 bbr_ecn_alpha_init = BBR_UNIT; ++ ++/* On ECN, cut inflight_lo to (1 - ecn_factor * ecn_alpha) scaled by BBR_SCALE. ++ * No ECN based bounding when 0. ++ */ ++static const u32 bbr_ecn_factor = BBR_UNIT * 1 / 3; /* 1/3 = 33% */ ++ ++/* Estimate bw probing has gone too far if CE ratio exceeds this threshold. ++ * Scaled by BBR_SCALE. Disabled when 0. ++ */ ++static const u32 bbr_ecn_thresh = BBR_UNIT * 1 / 2; /* 1/2 = 50% */ ++ ++/* If non-zero, if in a cycle with no losses but some ECN marks, after ECN ++ * clears then make the first round's increment to inflight_hi the following ++ * fraction of inflight_hi. ++ */ ++static const u32 bbr_ecn_reprobe_gain = BBR_UNIT * 1 / 2; ++ ++/* Estimate bw probing has gone too far if loss rate exceeds this level. */ ++static const u32 bbr_loss_thresh = BBR_UNIT * 2 / 100; /* 2% loss */ ++ ++/* Slow down for a packet loss recovered by TLP? */ ++static const bool bbr_loss_probe_recovery = true; ++ ++/* Exit STARTUP if number of loss marking events in a Recovery round is >= N, ++ * and loss rate is higher than bbr_loss_thresh. ++ * Disabled if 0. ++ */ ++static const u32 bbr_full_loss_cnt = 6; ++ ++/* Exit STARTUP if number of round trips with ECN mark rate above ecn_thresh ++ * meets this count. ++ */ ++static const u32 bbr_full_ecn_cnt = 2; ++ ++/* Fraction of unutilized headroom to try to leave in path upon high loss. */ ++static const u32 bbr_inflight_headroom = BBR_UNIT * 15 / 100; ++ ++/* How much do we increase cwnd_gain when probing for bandwidth in ++ * BBR_BW_PROBE_UP? This specifies the increment in units of ++ * BBR_UNIT/4. The default is 1, meaning 0.25. ++ * The min value is 0 (meaning 0.0); max is 3 (meaning 0.75). ++ */ ++static const u32 bbr_bw_probe_cwnd_gain = 1; ++ ++/* Max number of packet-timed rounds to wait before probing for bandwidth. If ++ * we want to tolerate 1% random loss per round, and not have this cut our ++ * inflight too much, we must probe for bw periodically on roughly this scale. ++ * If low, limits Reno/CUBIC coexistence; if high, limits loss tolerance. ++ * We aim to be fair with Reno/CUBIC up to a BDP of at least: ++ * BDP = 25Mbps * .030sec /(1514bytes) = 61.9 packets ++ */ ++static const u32 bbr_bw_probe_max_rounds = 63; ++ ++/* Max amount of randomness to inject in round counting for Reno-coexistence. ++ */ ++static const u32 bbr_bw_probe_rand_rounds = 2; ++ ++/* Use BBR-native probe time scale starting at this many usec. ++ * We aim to be fair with Reno/CUBIC up to an inter-loss time epoch of at least: ++ * BDP*RTT = 25Mbps * .030sec /(1514bytes) * 0.030sec = 1.9 secs ++ */ ++static const u32 bbr_bw_probe_base_us = 2 * USEC_PER_SEC; /* 2 secs */ ++ ++/* Use BBR-native probes spread over this many usec: */ ++static const u32 bbr_bw_probe_rand_us = 1 * USEC_PER_SEC; /* 1 secs */ ++ ++/* Use fast path if app-limited, no loss/ECN, and target cwnd was reached? */ ++static const bool bbr_fast_path = true; ++ ++/* Use fast ack mode? */ ++static const bool bbr_fast_ack_mode = true; ++ ++static u32 bbr_max_bw(const struct sock *sk); ++static u32 bbr_bw(const struct sock *sk); ++static void bbr_exit_probe_rtt(struct sock *sk); ++static void bbr_reset_congestion_signals(struct sock *sk); ++static void bbr_run_loss_probe_recovery(struct sock *sk); ++ + static void bbr_check_probe_rtt_done(struct sock *sk); + ++/* This connection can use ECN if both endpoints have signaled ECN support in ++ * the handshake and the per-route settings indicated this is a ++ * shallow-threshold ECN environment, meaning both: ++ * (a) ECN CE marks indicate low-latency/shallow-threshold congestion, and ++ * (b) TCP endpoints provide precise ACKs that only ACK data segments ++ * with consistent ECN CE status ++ */ ++static bool bbr_can_use_ecn(const struct sock *sk) ++{ ++ return (tcp_sk(sk)->ecn_flags & TCP_ECN_OK) && ++ (tcp_sk(sk)->ecn_flags & TCP_ECN_LOW); ++} ++ + /* Do we estimate that STARTUP filled the pipe? */ + static bool bbr_full_bw_reached(const struct sock *sk) + { +@@ -214,17 +382,17 @@ static bool bbr_full_bw_reached(const st + /* Return the windowed max recent bandwidth sample, in pkts/uS << BW_SCALE. */ + static u32 bbr_max_bw(const struct sock *sk) + { +- struct bbr *bbr = inet_csk_ca(sk); ++ const struct bbr *bbr = inet_csk_ca(sk); + +- return minmax_get(&bbr->bw); ++ return max(bbr->bw_hi[0], bbr->bw_hi[1]); + } + + /* Return the estimated bandwidth of the path, in pkts/uS << BW_SCALE. */ + static u32 bbr_bw(const struct sock *sk) + { +- struct bbr *bbr = inet_csk_ca(sk); ++ const struct bbr *bbr = inet_csk_ca(sk); + +- return bbr->lt_use_bw ? bbr->lt_bw : bbr_max_bw(sk); ++ return min(bbr_max_bw(sk), bbr->bw_lo); + } + + /* Return maximum extra acked in past k-2k round trips, +@@ -241,15 +409,23 @@ static u16 bbr_extra_acked(const struct + * The order here is chosen carefully to avoid overflow of u64. This should + * work for input rates of up to 2.9Tbit/sec and gain of 2.89x. + */ +-static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain) ++static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain, ++ int margin) + { + unsigned int mss = tcp_sk(sk)->mss_cache; + + rate *= mss; + rate *= gain; + rate >>= BBR_SCALE; +- rate *= USEC_PER_SEC / 100 * (100 - bbr_pacing_margin_percent); +- return rate >> BW_SCALE; ++ rate *= USEC_PER_SEC / 100 * (100 - margin); ++ rate >>= BW_SCALE; ++ rate = max(rate, 1ULL); ++ return rate; ++} ++ ++static u64 bbr_bw_bytes_per_sec(struct sock *sk, u64 rate) ++{ ++ return bbr_rate_bytes_per_sec(sk, rate, BBR_UNIT, 0); + } + + /* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */ +@@ -257,12 +433,13 @@ static unsigned long bbr_bw_to_pacing_ra + { + u64 rate = bw; + +- rate = bbr_rate_bytes_per_sec(sk, rate, gain); ++ rate = bbr_rate_bytes_per_sec(sk, rate, gain, ++ bbr_pacing_margin_percent); + rate = min_t(u64, rate, READ_ONCE(sk->sk_max_pacing_rate)); + return rate; + } + +-/* Initialize pacing rate to: high_gain * init_cwnd / RTT. */ ++/* Initialize pacing rate to: startup_pacing_gain * init_cwnd / RTT. */ + static void bbr_init_pacing_rate_from_rtt(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); +@@ -279,7 +456,7 @@ static void bbr_init_pacing_rate_from_rt + bw = (u64)tcp_snd_cwnd(tp) * BW_UNIT; + do_div(bw, rtt_us); + WRITE_ONCE(sk->sk_pacing_rate, +- bbr_bw_to_pacing_rate(sk, bw, bbr_high_gain)); ++ bbr_bw_to_pacing_rate(sk, bw, bbr_param(sk, startup_pacing_gain))); + } + + /* Pace using current bw estimate and a gain factor. */ +@@ -295,31 +472,38 @@ static void bbr_set_pacing_rate(struct s + WRITE_ONCE(sk->sk_pacing_rate, rate); + } + +-/* override sysctl_tcp_min_tso_segs */ +-__bpf_kfunc static u32 bbr_min_tso_segs(struct sock *sk) +-{ +- return READ_ONCE(sk->sk_pacing_rate) < (bbr_min_tso_rate >> 3) ? 1 : 2; +-} +- +-/* Return the number of segments BBR would like in a TSO/GSO skb, given +- * a particular max gso size as a constraint. ++/* Return the number of segments BBR would like in a TSO/GSO skb, given a ++ * particular max gso size as a constraint. TODO: make this simpler and more ++ * consistent by switching bbr to just call tcp_tso_autosize(). + */ + static u32 bbr_tso_segs_generic(struct sock *sk, unsigned int mss_now, + u32 gso_max_size) + { +- u32 segs; ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 segs, r; + u64 bytes; + + /* Budget a TSO/GSO burst size allowance based on bw (pacing_rate). */ + bytes = READ_ONCE(sk->sk_pacing_rate) >> READ_ONCE(sk->sk_pacing_shift); + ++ /* Budget a TSO/GSO burst size allowance based on min_rtt. For every ++ * K = 2^tso_rtt_shift microseconds of min_rtt, halve the burst. ++ * The min_rtt-based burst allowance is: 64 KBytes / 2^(min_rtt/K) ++ */ ++ if (bbr_param(sk, tso_rtt_shift)) { ++ r = bbr->min_rtt_us >> bbr_param(sk, tso_rtt_shift); ++ if (r < BITS_PER_TYPE(u32)) /* prevent undefined behavior */ ++ bytes += GSO_LEGACY_MAX_SIZE >> r; ++ } ++ + bytes = min_t(u32, bytes, gso_max_size - 1 - MAX_TCP_HEADER); +- segs = max_t(u32, bytes / mss_now, bbr_min_tso_segs(sk)); ++ segs = max_t(u32, div_u64(bytes, mss_now), ++ sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); + return segs; + } + + /* Custom tcp_tso_autosize() for BBR, used at transmit time to cap skb size. */ +-static u32 bbr_tso_segs(struct sock *sk, unsigned int mss_now) ++__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, unsigned int mss_now) + { + return bbr_tso_segs_generic(sk, mss_now, sk->sk_gso_max_size); + } +@@ -329,7 +513,7 @@ static u32 bbr_tso_segs_goal(struct sock + { + struct tcp_sock *tp = tcp_sk(sk); + +- return bbr_tso_segs_generic(sk, tp->mss_cache, GSO_MAX_SIZE); ++ return bbr_tso_segs_generic(sk, tp->mss_cache, GSO_LEGACY_MAX_SIZE); + } + + /* Save "last known good" cwnd so we can restore it after losses or PROBE_RTT */ +@@ -349,7 +533,9 @@ __bpf_kfunc static void bbr_cwnd_event(s + struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); + +- if (event == CA_EVENT_TX_START && tp->app_limited) { ++ if (event == CA_EVENT_TX_START) { ++ if (!tp->app_limited) ++ return; + bbr->idle_restart = 1; + bbr->ack_epoch_mstamp = tp->tcp_mstamp; + bbr->ack_epoch_acked = 0; +@@ -360,6 +546,16 @@ __bpf_kfunc static void bbr_cwnd_event(s + bbr_set_pacing_rate(sk, bbr_bw(sk), BBR_UNIT); + else if (bbr->mode == BBR_PROBE_RTT) + bbr_check_probe_rtt_done(sk); ++ } else if ((event == CA_EVENT_ECN_IS_CE || ++ event == CA_EVENT_ECN_NO_CE) && ++ bbr_can_use_ecn(sk) && ++ bbr_param(sk, precise_ece_ack)) { ++ u32 state = bbr->ce_state; ++ dctcp_ece_ack_update(sk, event, &bbr->prior_rcv_nxt, &state); ++ bbr->ce_state = state; ++ } else if (event == CA_EVENT_TLP_RECOVERY && ++ bbr_param(sk, loss_probe_recovery)) { ++ bbr_run_loss_probe_recovery(sk); + } + } + +@@ -382,10 +578,10 @@ static u32 bbr_bdp(struct sock *sk, u32 + * default. This should only happen when the connection is not using TCP + * timestamps and has retransmitted all of the SYN/SYNACK/data packets + * ACKed so far. In this case, an RTO can cut cwnd to 1, in which +- * case we need to slow-start up toward something safe: TCP_INIT_CWND. ++ * case we need to slow-start up toward something safe: initial cwnd. + */ + if (unlikely(bbr->min_rtt_us == ~0U)) /* no valid RTT samples yet? */ +- return TCP_INIT_CWND; /* be safe: cap at default initial cwnd*/ ++ return bbr->init_cwnd; /* be safe: cap at initial cwnd */ + + w = (u64)bw * bbr->min_rtt_us; + +@@ -402,23 +598,23 @@ static u32 bbr_bdp(struct sock *sk, u32 + * - one skb in sending host Qdisc, + * - one skb in sending host TSO/GSO engine + * - one skb being received by receiver host LRO/GRO/delayed-ACK engine +- * Don't worry, at low rates (bbr_min_tso_rate) this won't bloat cwnd because +- * in such cases tso_segs_goal is 1. The minimum cwnd is 4 packets, ++ * Don't worry, at low rates this won't bloat cwnd because ++ * in such cases tso_segs_goal is small. The minimum cwnd is 4 packets, + * which allows 2 outstanding 2-packet sequences, to try to keep pipe + * full even with ACK-every-other-packet delayed ACKs. + */ + static u32 bbr_quantization_budget(struct sock *sk, u32 cwnd) + { + struct bbr *bbr = inet_csk_ca(sk); ++ u32 tso_segs_goal; + +- /* Allow enough full-sized skbs in flight to utilize end systems. */ +- cwnd += 3 * bbr_tso_segs_goal(sk); +- +- /* Reduce delayed ACKs by rounding up cwnd to the next even number. */ +- cwnd = (cwnd + 1) & ~1U; ++ tso_segs_goal = 3 * bbr_tso_segs_goal(sk); + ++ /* Allow enough full-sized skbs in flight to utilize end systems. */ ++ cwnd = max_t(u32, cwnd, tso_segs_goal); ++ cwnd = max_t(u32, cwnd, bbr_param(sk, cwnd_min_target)); + /* Ensure gain cycling gets inflight above BDP even for small BDPs. */ +- if (bbr->mode == BBR_PROBE_BW && bbr->cycle_idx == 0) ++ if (bbr->mode == BBR_PROBE_BW && bbr->cycle_idx == BBR_BW_PROBE_UP) + cwnd += 2; + + return cwnd; +@@ -473,10 +669,10 @@ static u32 bbr_ack_aggregation_cwnd(stru + { + u32 max_aggr_cwnd, aggr_cwnd = 0; + +- if (bbr_extra_acked_gain && bbr_full_bw_reached(sk)) { ++ if (bbr_param(sk, extra_acked_gain)) { + max_aggr_cwnd = ((u64)bbr_bw(sk) * bbr_extra_acked_max_us) + / BW_UNIT; +- aggr_cwnd = (bbr_extra_acked_gain * bbr_extra_acked(sk)) ++ aggr_cwnd = (bbr_param(sk, extra_acked_gain) * bbr_extra_acked(sk)) + >> BBR_SCALE; + aggr_cwnd = min(aggr_cwnd, max_aggr_cwnd); + } +@@ -484,66 +680,27 @@ static u32 bbr_ack_aggregation_cwnd(stru + return aggr_cwnd; + } + +-/* An optimization in BBR to reduce losses: On the first round of recovery, we +- * follow the packet conservation principle: send P packets per P packets acked. +- * After that, we slow-start and send at most 2*P packets per P packets acked. +- * After recovery finishes, or upon undo, we restore the cwnd we had when +- * recovery started (capped by the target cwnd based on estimated BDP). +- * +- * TODO(ycheng/ncardwell): implement a rate-based approach. +- */ +-static bool bbr_set_cwnd_to_recover_or_restore( +- struct sock *sk, const struct rate_sample *rs, u32 acked, u32 *new_cwnd) ++/* Returns the cwnd for PROBE_RTT mode. */ ++static u32 bbr_probe_rtt_cwnd(struct sock *sk) + { +- struct tcp_sock *tp = tcp_sk(sk); +- struct bbr *bbr = inet_csk_ca(sk); +- u8 prev_state = bbr->prev_ca_state, state = inet_csk(sk)->icsk_ca_state; +- u32 cwnd = tcp_snd_cwnd(tp); +- +- /* An ACK for P pkts should release at most 2*P packets. We do this +- * in two steps. First, here we deduct the number of lost packets. +- * Then, in bbr_set_cwnd() we slow start up toward the target cwnd. +- */ +- if (rs->losses > 0) +- cwnd = max_t(s32, cwnd - rs->losses, 1); +- +- if (state == TCP_CA_Recovery && prev_state != TCP_CA_Recovery) { +- /* Starting 1st round of Recovery, so do packet conservation. */ +- bbr->packet_conservation = 1; +- bbr->next_rtt_delivered = tp->delivered; /* start round now */ +- /* Cut unused cwnd from app behavior, TSQ, or TSO deferral: */ +- cwnd = tcp_packets_in_flight(tp) + acked; +- } else if (prev_state >= TCP_CA_Recovery && state < TCP_CA_Recovery) { +- /* Exiting loss recovery; restore cwnd saved before recovery. */ +- cwnd = max(cwnd, bbr->prior_cwnd); +- bbr->packet_conservation = 0; +- } +- bbr->prev_ca_state = state; +- +- if (bbr->packet_conservation) { +- *new_cwnd = max(cwnd, tcp_packets_in_flight(tp) + acked); +- return true; /* yes, using packet conservation */ +- } +- *new_cwnd = cwnd; +- return false; ++ return max_t(u32, bbr_param(sk, cwnd_min_target), ++ bbr_bdp(sk, bbr_bw(sk), bbr_param(sk, probe_rtt_cwnd_gain))); + } + + /* Slow-start up toward target cwnd (if bw estimate is growing, or packet loss + * has drawn us down below target), or snap down to target if we're above it. + */ + static void bbr_set_cwnd(struct sock *sk, const struct rate_sample *rs, +- u32 acked, u32 bw, int gain) ++ u32 acked, u32 bw, int gain, u32 cwnd, ++ struct bbr_context *ctx) + { + struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); +- u32 cwnd = tcp_snd_cwnd(tp), target_cwnd = 0; ++ u32 target_cwnd = 0; + + if (!acked) + goto done; /* no packet fully ACKed; just apply caps */ + +- if (bbr_set_cwnd_to_recover_or_restore(sk, rs, acked, &cwnd)) +- goto done; +- + target_cwnd = bbr_bdp(sk, bw, gain); + + /* Increment the cwnd to account for excess ACKed data that seems +@@ -552,74 +709,26 @@ static void bbr_set_cwnd(struct sock *sk + target_cwnd += bbr_ack_aggregation_cwnd(sk); + target_cwnd = bbr_quantization_budget(sk, target_cwnd); + +- /* If we're below target cwnd, slow start cwnd toward target cwnd. */ +- if (bbr_full_bw_reached(sk)) /* only cut cwnd if we filled the pipe */ +- cwnd = min(cwnd + acked, target_cwnd); +- else if (cwnd < target_cwnd || tp->delivered < TCP_INIT_CWND) +- cwnd = cwnd + acked; +- cwnd = max(cwnd, bbr_cwnd_min_target); ++ /* Update cwnd and enable fast path if cwnd reaches target_cwnd. */ ++ bbr->try_fast_path = 0; ++ if (bbr_full_bw_reached(sk)) { /* only cut cwnd if we filled the pipe */ ++ cwnd += acked; ++ if (cwnd >= target_cwnd) { ++ cwnd = target_cwnd; ++ bbr->try_fast_path = 1; ++ } ++ } else if (cwnd < target_cwnd || cwnd < 2 * bbr->init_cwnd) { ++ cwnd += acked; ++ } else { ++ bbr->try_fast_path = 1; ++ } + ++ cwnd = max_t(u32, cwnd, bbr_param(sk, cwnd_min_target)); + done: +- tcp_snd_cwnd_set(tp, min(cwnd, tp->snd_cwnd_clamp)); /* apply global cap */ ++ tcp_snd_cwnd_set(tp, min(cwnd, tp->snd_cwnd_clamp)); /* global cap */ + if (bbr->mode == BBR_PROBE_RTT) /* drain queue, refresh min_rtt */ +- tcp_snd_cwnd_set(tp, min(tcp_snd_cwnd(tp), bbr_cwnd_min_target)); +-} +- +-/* End cycle phase if it's time and/or we hit the phase's in-flight target. */ +-static bool bbr_is_next_cycle_phase(struct sock *sk, +- const struct rate_sample *rs) +-{ +- struct tcp_sock *tp = tcp_sk(sk); +- struct bbr *bbr = inet_csk_ca(sk); +- bool is_full_length = +- tcp_stamp_us_delta(tp->delivered_mstamp, bbr->cycle_mstamp) > +- bbr->min_rtt_us; +- u32 inflight, bw; +- +- /* The pacing_gain of 1.0 paces at the estimated bw to try to fully +- * use the pipe without increasing the queue. +- */ +- if (bbr->pacing_gain == BBR_UNIT) +- return is_full_length; /* just use wall clock time */ +- +- inflight = bbr_packets_in_net_at_edt(sk, rs->prior_in_flight); +- bw = bbr_max_bw(sk); +- +- /* A pacing_gain > 1.0 probes for bw by trying to raise inflight to at +- * least pacing_gain*BDP; this may take more than min_rtt if min_rtt is +- * small (e.g. on a LAN). We do not persist if packets are lost, since +- * a path with small buffers may not hold that much. +- */ +- if (bbr->pacing_gain > BBR_UNIT) +- return is_full_length && +- (rs->losses || /* perhaps pacing_gain*BDP won't fit */ +- inflight >= bbr_inflight(sk, bw, bbr->pacing_gain)); +- +- /* A pacing_gain < 1.0 tries to drain extra queue we added if bw +- * probing didn't find more bw. If inflight falls to match BDP then we +- * estimate queue is drained; persisting would underutilize the pipe. +- */ +- return is_full_length || +- inflight <= bbr_inflight(sk, bw, BBR_UNIT); +-} +- +-static void bbr_advance_cycle_phase(struct sock *sk) +-{ +- struct tcp_sock *tp = tcp_sk(sk); +- struct bbr *bbr = inet_csk_ca(sk); +- +- bbr->cycle_idx = (bbr->cycle_idx + 1) & (CYCLE_LEN - 1); +- bbr->cycle_mstamp = tp->delivered_mstamp; +-} +- +-/* Gain cycling: cycle pacing gain to converge to fair share of available bw. */ +-static void bbr_update_cycle_phase(struct sock *sk, +- const struct rate_sample *rs) +-{ +- struct bbr *bbr = inet_csk_ca(sk); +- +- if (bbr->mode == BBR_PROBE_BW && bbr_is_next_cycle_phase(sk, rs)) +- bbr_advance_cycle_phase(sk); ++ tcp_snd_cwnd_set(tp, min_t(u32, tcp_snd_cwnd(tp), ++ bbr_probe_rtt_cwnd(sk))); + } + + static void bbr_reset_startup_mode(struct sock *sk) +@@ -629,191 +738,49 @@ static void bbr_reset_startup_mode(struc + bbr->mode = BBR_STARTUP; + } + +-static void bbr_reset_probe_bw_mode(struct sock *sk) +-{ +- struct bbr *bbr = inet_csk_ca(sk); +- +- bbr->mode = BBR_PROBE_BW; +- bbr->cycle_idx = CYCLE_LEN - 1 - get_random_u32_below(bbr_cycle_rand); +- bbr_advance_cycle_phase(sk); /* flip to next phase of gain cycle */ +-} +- +-static void bbr_reset_mode(struct sock *sk) +-{ +- if (!bbr_full_bw_reached(sk)) +- bbr_reset_startup_mode(sk); +- else +- bbr_reset_probe_bw_mode(sk); +-} +- +-/* Start a new long-term sampling interval. */ +-static void bbr_reset_lt_bw_sampling_interval(struct sock *sk) +-{ +- struct tcp_sock *tp = tcp_sk(sk); +- struct bbr *bbr = inet_csk_ca(sk); +- +- bbr->lt_last_stamp = div_u64(tp->delivered_mstamp, USEC_PER_MSEC); +- bbr->lt_last_delivered = tp->delivered; +- bbr->lt_last_lost = tp->lost; +- bbr->lt_rtt_cnt = 0; +-} +- +-/* Completely reset long-term bandwidth sampling. */ +-static void bbr_reset_lt_bw_sampling(struct sock *sk) +-{ +- struct bbr *bbr = inet_csk_ca(sk); +- +- bbr->lt_bw = 0; +- bbr->lt_use_bw = 0; +- bbr->lt_is_sampling = false; +- bbr_reset_lt_bw_sampling_interval(sk); +-} +- +-/* Long-term bw sampling interval is done. Estimate whether we're policed. */ +-static void bbr_lt_bw_interval_done(struct sock *sk, u32 bw) +-{ +- struct bbr *bbr = inet_csk_ca(sk); +- u32 diff; +- +- if (bbr->lt_bw) { /* do we have bw from a previous interval? */ +- /* Is new bw close to the lt_bw from the previous interval? */ +- diff = abs(bw - bbr->lt_bw); +- if ((diff * BBR_UNIT <= bbr_lt_bw_ratio * bbr->lt_bw) || +- (bbr_rate_bytes_per_sec(sk, diff, BBR_UNIT) <= +- bbr_lt_bw_diff)) { +- /* All criteria are met; estimate we're policed. */ +- bbr->lt_bw = (bw + bbr->lt_bw) >> 1; /* avg 2 intvls */ +- bbr->lt_use_bw = 1; +- bbr->pacing_gain = BBR_UNIT; /* try to avoid drops */ +- bbr->lt_rtt_cnt = 0; +- return; +- } +- } +- bbr->lt_bw = bw; +- bbr_reset_lt_bw_sampling_interval(sk); +-} +- +-/* Token-bucket traffic policers are common (see "An Internet-Wide Analysis of +- * Traffic Policing", SIGCOMM 2016). BBR detects token-bucket policers and +- * explicitly models their policed rate, to reduce unnecessary losses. We +- * estimate that we're policed if we see 2 consecutive sampling intervals with +- * consistent throughput and high packet loss. If we think we're being policed, +- * set lt_bw to the "long-term" average delivery rate from those 2 intervals. ++/* See if we have reached next round trip. Upon start of the new round, ++ * returns packets delivered since previous round start plus this ACK. + */ +-static void bbr_lt_bw_sampling(struct sock *sk, const struct rate_sample *rs) ++static u32 bbr_update_round_start(struct sock *sk, ++ const struct rate_sample *rs, struct bbr_context *ctx) + { + struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); +- u32 lost, delivered; +- u64 bw; +- u32 t; +- +- if (bbr->lt_use_bw) { /* already using long-term rate, lt_bw? */ +- if (bbr->mode == BBR_PROBE_BW && bbr->round_start && +- ++bbr->lt_rtt_cnt >= bbr_lt_bw_max_rtts) { +- bbr_reset_lt_bw_sampling(sk); /* stop using lt_bw */ +- bbr_reset_probe_bw_mode(sk); /* restart gain cycling */ +- } +- return; +- } +- +- /* Wait for the first loss before sampling, to let the policer exhaust +- * its tokens and estimate the steady-state rate allowed by the policer. +- * Starting samples earlier includes bursts that over-estimate the bw. +- */ +- if (!bbr->lt_is_sampling) { +- if (!rs->losses) +- return; +- bbr_reset_lt_bw_sampling_interval(sk); +- bbr->lt_is_sampling = true; +- } +- +- /* To avoid underestimates, reset sampling if we run out of data. */ +- if (rs->is_app_limited) { +- bbr_reset_lt_bw_sampling(sk); +- return; +- } +- +- if (bbr->round_start) +- bbr->lt_rtt_cnt++; /* count round trips in this interval */ +- if (bbr->lt_rtt_cnt < bbr_lt_intvl_min_rtts) +- return; /* sampling interval needs to be longer */ +- if (bbr->lt_rtt_cnt > 4 * bbr_lt_intvl_min_rtts) { +- bbr_reset_lt_bw_sampling(sk); /* interval is too long */ +- return; +- } +- +- /* End sampling interval when a packet is lost, so we estimate the +- * policer tokens were exhausted. Stopping the sampling before the +- * tokens are exhausted under-estimates the policed rate. +- */ +- if (!rs->losses) +- return; +- +- /* Calculate packets lost and delivered in sampling interval. */ +- lost = tp->lost - bbr->lt_last_lost; +- delivered = tp->delivered - bbr->lt_last_delivered; +- /* Is loss rate (lost/delivered) >= lt_loss_thresh? If not, wait. */ +- if (!delivered || (lost << BBR_SCALE) < bbr_lt_loss_thresh * delivered) +- return; +- +- /* Find average delivery rate in this sampling interval. */ +- t = div_u64(tp->delivered_mstamp, USEC_PER_MSEC) - bbr->lt_last_stamp; +- if ((s32)t < 1) +- return; /* interval is less than one ms, so wait */ +- /* Check if can multiply without overflow */ +- if (t >= ~0U / USEC_PER_MSEC) { +- bbr_reset_lt_bw_sampling(sk); /* interval too long; reset */ +- return; +- } +- t *= USEC_PER_MSEC; +- bw = (u64)delivered * BW_UNIT; +- do_div(bw, t); +- bbr_lt_bw_interval_done(sk, bw); +-} +- +-/* Estimate the bandwidth based on how fast packets are delivered */ +-static void bbr_update_bw(struct sock *sk, const struct rate_sample *rs) +-{ +- struct tcp_sock *tp = tcp_sk(sk); +- struct bbr *bbr = inet_csk_ca(sk); +- u64 bw; ++ u32 round_delivered = 0; + + bbr->round_start = 0; +- if (rs->delivered < 0 || rs->interval_us <= 0) +- return; /* Not a valid observation */ + + /* See if we've reached the next RTT */ +- if (!before(rs->prior_delivered, bbr->next_rtt_delivered)) { ++ if (rs->interval_us > 0 && ++ !before(rs->prior_delivered, bbr->next_rtt_delivered)) { ++ round_delivered = tp->delivered - bbr->next_rtt_delivered; + bbr->next_rtt_delivered = tp->delivered; +- bbr->rtt_cnt++; + bbr->round_start = 1; +- bbr->packet_conservation = 0; + } ++ return round_delivered; ++} + +- bbr_lt_bw_sampling(sk, rs); ++/* Calculate the bandwidth based on how fast packets are delivered */ ++static void bbr_calculate_bw_sample(struct sock *sk, ++ const struct rate_sample *rs, struct bbr_context *ctx) ++{ ++ u64 bw = 0; + + /* Divide delivered by the interval to find a (lower bound) bottleneck + * bandwidth sample. Delivered is in packets and interval_us in uS and + * ratio will be <<1 for most connections. So delivered is first scaled. ++ * Round up to allow growth at low rates, even with integer division. + */ +- bw = div64_long((u64)rs->delivered * BW_UNIT, rs->interval_us); ++ if (rs->interval_us > 0) { ++ if (WARN_ONCE(rs->delivered < 0, ++ "negative delivered: %d interval_us: %ld\n", ++ rs->delivered, rs->interval_us)) ++ return; + +- /* If this sample is application-limited, it is likely to have a very +- * low delivered count that represents application behavior rather than +- * the available network rate. Such a sample could drag down estimated +- * bw, causing needless slow-down. Thus, to continue to send at the +- * last measured network rate, we filter out app-limited samples unless +- * they describe the path bw at least as well as our bw model. +- * +- * So the goal during app-limited phase is to proceed with the best +- * network rate no matter how long. We automatically leave this +- * phase when app writes faster than the network can deliver :) +- */ +- if (!rs->is_app_limited || bw >= bbr_max_bw(sk)) { +- /* Incorporate new sample into our max bw filter. */ +- minmax_running_max(&bbr->bw, bbr_bw_rtts, bbr->rtt_cnt, bw); ++ bw = DIV_ROUND_UP_ULL((u64)rs->delivered * BW_UNIT, rs->interval_us); + } ++ ++ ctx->sample_bw = bw; + } + + /* Estimates the windowed max degree of ack aggregation. +@@ -827,7 +794,7 @@ static void bbr_update_bw(struct sock *s + * + * Max extra_acked is clamped by cwnd and bw * bbr_extra_acked_max_us (100 ms). + * Max filter is an approximate sliding window of 5-10 (packet timed) round +- * trips. ++ * trips for non-startup phase, and 1-2 round trips for startup. + */ + static void bbr_update_ack_aggregation(struct sock *sk, + const struct rate_sample *rs) +@@ -835,15 +802,19 @@ static void bbr_update_ack_aggregation(s + u32 epoch_us, expected_acked, extra_acked; + struct bbr *bbr = inet_csk_ca(sk); + struct tcp_sock *tp = tcp_sk(sk); ++ u32 extra_acked_win_rtts_thresh = bbr_param(sk, extra_acked_win_rtts); + +- if (!bbr_extra_acked_gain || rs->acked_sacked <= 0 || ++ if (!bbr_param(sk, extra_acked_gain) || rs->acked_sacked <= 0 || + rs->delivered < 0 || rs->interval_us <= 0) + return; + + if (bbr->round_start) { + bbr->extra_acked_win_rtts = min(0x1F, + bbr->extra_acked_win_rtts + 1); +- if (bbr->extra_acked_win_rtts >= bbr_extra_acked_win_rtts) { ++ if (!bbr_full_bw_reached(sk)) ++ extra_acked_win_rtts_thresh = 1; ++ if (bbr->extra_acked_win_rtts >= ++ extra_acked_win_rtts_thresh) { + bbr->extra_acked_win_rtts = 0; + bbr->extra_acked_win_idx = bbr->extra_acked_win_idx ? + 0 : 1; +@@ -877,49 +848,6 @@ static void bbr_update_ack_aggregation(s + bbr->extra_acked[bbr->extra_acked_win_idx] = extra_acked; + } + +-/* Estimate when the pipe is full, using the change in delivery rate: BBR +- * estimates that STARTUP filled the pipe if the estimated bw hasn't changed by +- * at least bbr_full_bw_thresh (25%) after bbr_full_bw_cnt (3) non-app-limited +- * rounds. Why 3 rounds: 1: rwin autotuning grows the rwin, 2: we fill the +- * higher rwin, 3: we get higher delivery rate samples. Or transient +- * cross-traffic or radio noise can go away. CUBIC Hystart shares a similar +- * design goal, but uses delay and inter-ACK spacing instead of bandwidth. +- */ +-static void bbr_check_full_bw_reached(struct sock *sk, +- const struct rate_sample *rs) +-{ +- struct bbr *bbr = inet_csk_ca(sk); +- u32 bw_thresh; +- +- if (bbr_full_bw_reached(sk) || !bbr->round_start || rs->is_app_limited) +- return; +- +- bw_thresh = (u64)bbr->full_bw * bbr_full_bw_thresh >> BBR_SCALE; +- if (bbr_max_bw(sk) >= bw_thresh) { +- bbr->full_bw = bbr_max_bw(sk); +- bbr->full_bw_cnt = 0; +- return; +- } +- ++bbr->full_bw_cnt; +- bbr->full_bw_reached = bbr->full_bw_cnt >= bbr_full_bw_cnt; +-} +- +-/* If pipe is probably full, drain the queue and then enter steady-state. */ +-static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) +-{ +- struct bbr *bbr = inet_csk_ca(sk); +- +- if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { +- bbr->mode = BBR_DRAIN; /* drain queue we created */ +- tcp_sk(sk)->snd_ssthresh = +- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); +- } /* fall through to check if in-flight is already small: */ +- if (bbr->mode == BBR_DRAIN && +- bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= +- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT)) +- bbr_reset_probe_bw_mode(sk); /* we estimate queue is drained */ +-} +- + static void bbr_check_probe_rtt_done(struct sock *sk) + { + struct tcp_sock *tp = tcp_sk(sk); +@@ -929,9 +857,9 @@ static void bbr_check_probe_rtt_done(str + after(tcp_jiffies32, bbr->probe_rtt_done_stamp))) + return; + +- bbr->min_rtt_stamp = tcp_jiffies32; /* wait a while until PROBE_RTT */ ++ bbr->probe_rtt_min_stamp = tcp_jiffies32; /* schedule next PROBE_RTT */ + tcp_snd_cwnd_set(tp, max(tcp_snd_cwnd(tp), bbr->prior_cwnd)); +- bbr_reset_mode(sk); ++ bbr_exit_probe_rtt(sk); + } + + /* The goal of PROBE_RTT mode is to have BBR flows cooperatively and +@@ -957,23 +885,35 @@ static void bbr_update_min_rtt(struct so + { + struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); +- bool filter_expired; ++ bool probe_rtt_expired, min_rtt_expired; ++ u32 expire; + +- /* Track min RTT seen in the min_rtt_win_sec filter window: */ +- filter_expired = after(tcp_jiffies32, +- bbr->min_rtt_stamp + bbr_min_rtt_win_sec * HZ); ++ /* Track min RTT in probe_rtt_win_ms to time next PROBE_RTT state. */ ++ expire = bbr->probe_rtt_min_stamp + ++ msecs_to_jiffies(bbr_param(sk, probe_rtt_win_ms)); ++ probe_rtt_expired = after(tcp_jiffies32, expire); + if (rs->rtt_us >= 0 && +- (rs->rtt_us < bbr->min_rtt_us || +- (filter_expired && !rs->is_ack_delayed))) { +- bbr->min_rtt_us = rs->rtt_us; +- bbr->min_rtt_stamp = tcp_jiffies32; ++ (rs->rtt_us < bbr->probe_rtt_min_us || ++ (probe_rtt_expired && !rs->is_ack_delayed))) { ++ bbr->probe_rtt_min_us = rs->rtt_us; ++ bbr->probe_rtt_min_stamp = tcp_jiffies32; ++ } ++ /* Track min RTT seen in the min_rtt_win_sec filter window: */ ++ expire = bbr->min_rtt_stamp + bbr_param(sk, min_rtt_win_sec) * HZ; ++ min_rtt_expired = after(tcp_jiffies32, expire); ++ if (bbr->probe_rtt_min_us <= bbr->min_rtt_us || ++ min_rtt_expired) { ++ bbr->min_rtt_us = bbr->probe_rtt_min_us; ++ bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp; + } + +- if (bbr_probe_rtt_mode_ms > 0 && filter_expired && ++ if (bbr_param(sk, probe_rtt_mode_ms) > 0 && probe_rtt_expired && + !bbr->idle_restart && bbr->mode != BBR_PROBE_RTT) { + bbr->mode = BBR_PROBE_RTT; /* dip, drain queue */ + bbr_save_cwnd(sk); /* note cwnd so we can restore it */ + bbr->probe_rtt_done_stamp = 0; ++ bbr->ack_phase = BBR_ACKS_PROBE_STOPPING; ++ bbr->next_rtt_delivered = tp->delivered; + } + + if (bbr->mode == BBR_PROBE_RTT) { +@@ -982,9 +922,9 @@ static void bbr_update_min_rtt(struct so + (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; + /* Maintain min packets in flight for max(200 ms, 1 round). */ + if (!bbr->probe_rtt_done_stamp && +- tcp_packets_in_flight(tp) <= bbr_cwnd_min_target) { ++ tcp_packets_in_flight(tp) <= bbr_probe_rtt_cwnd(sk)) { + bbr->probe_rtt_done_stamp = tcp_jiffies32 + +- msecs_to_jiffies(bbr_probe_rtt_mode_ms); ++ msecs_to_jiffies(bbr_param(sk, probe_rtt_mode_ms)); + bbr->probe_rtt_round_done = 0; + bbr->next_rtt_delivered = tp->delivered; + } else if (bbr->probe_rtt_done_stamp) { +@@ -1005,18 +945,20 @@ static void bbr_update_gains(struct sock + + switch (bbr->mode) { + case BBR_STARTUP: +- bbr->pacing_gain = bbr_high_gain; +- bbr->cwnd_gain = bbr_high_gain; ++ bbr->pacing_gain = bbr_param(sk, startup_pacing_gain); ++ bbr->cwnd_gain = bbr_param(sk, startup_cwnd_gain); + break; + case BBR_DRAIN: +- bbr->pacing_gain = bbr_drain_gain; /* slow, to drain */ +- bbr->cwnd_gain = bbr_high_gain; /* keep cwnd */ ++ bbr->pacing_gain = bbr_param(sk, drain_gain); /* slow, to drain */ ++ bbr->cwnd_gain = bbr_param(sk, startup_cwnd_gain); /* keep cwnd */ + break; + case BBR_PROBE_BW: +- bbr->pacing_gain = (bbr->lt_use_bw ? +- BBR_UNIT : +- bbr_pacing_gain[bbr->cycle_idx]); +- bbr->cwnd_gain = bbr_cwnd_gain; ++ bbr->pacing_gain = bbr_pacing_gain[bbr->cycle_idx]; ++ bbr->cwnd_gain = bbr_param(sk, cwnd_gain); ++ if (bbr_param(sk, bw_probe_cwnd_gain) && ++ bbr->cycle_idx == BBR_BW_PROBE_UP) ++ bbr->cwnd_gain += ++ BBR_UNIT * bbr_param(sk, bw_probe_cwnd_gain) / 4; + break; + case BBR_PROBE_RTT: + bbr->pacing_gain = BBR_UNIT; +@@ -1028,27 +970,1108 @@ static void bbr_update_gains(struct sock + } + } + +-static void bbr_update_model(struct sock *sk, const struct rate_sample *rs) ++__bpf_kfunc static u32 bbr_sndbuf_expand(struct sock *sk) ++{ ++ /* Provision 3 * cwnd since BBR may slow-start even during recovery. */ ++ return 3; ++} ++ ++/* Incorporate a new bw sample into the current window of our max filter. */ ++static void bbr_take_max_bw_sample(struct sock *sk, u32 bw) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->bw_hi[1] = max(bw, bbr->bw_hi[1]); ++} ++ ++/* Keep max of last 1-2 cycles. Each PROBE_BW cycle, flip filter window. */ ++static void bbr_advance_max_bw_filter(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (!bbr->bw_hi[1]) ++ return; /* no samples in this window; remember old window */ ++ bbr->bw_hi[0] = bbr->bw_hi[1]; ++ bbr->bw_hi[1] = 0; ++} ++ ++/* Reset the estimator for reaching full bandwidth based on bw plateau. */ ++static void bbr_reset_full_bw(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->full_bw = 0; ++ bbr->full_bw_cnt = 0; ++ bbr->full_bw_now = 0; ++} ++ ++/* How much do we want in flight? Our BDP, unless congestion cut cwnd. */ ++static u32 bbr_target_inflight(struct sock *sk) ++{ ++ u32 bdp = bbr_inflight(sk, bbr_bw(sk), BBR_UNIT); ++ ++ return min(bdp, tcp_sk(sk)->snd_cwnd); ++} ++ ++static bool bbr_is_probing_bandwidth(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ return (bbr->mode == BBR_STARTUP) || ++ (bbr->mode == BBR_PROBE_BW && ++ (bbr->cycle_idx == BBR_BW_PROBE_REFILL || ++ bbr->cycle_idx == BBR_BW_PROBE_UP)); ++} ++ ++/* Has the given amount of time elapsed since we marked the phase start? */ ++static bool bbr_has_elapsed_in_phase(const struct sock *sk, u32 interval_us) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ const struct bbr *bbr = inet_csk_ca(sk); ++ ++ return tcp_stamp_us_delta(tp->tcp_mstamp, ++ bbr->cycle_mstamp + interval_us) > 0; ++} ++ ++static void bbr_handle_queue_too_high_in_startup(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 bdp; /* estimated BDP in packets, with quantization budget */ ++ ++ bbr->full_bw_reached = 1; ++ ++ bdp = bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); ++ bbr->inflight_hi = max(bdp, bbr->inflight_latest); ++} ++ ++/* Exit STARTUP upon N consecutive rounds with ECN mark rate > ecn_thresh. */ ++static void bbr_check_ecn_too_high_in_startup(struct sock *sk, u32 ce_ratio) + { +- bbr_update_bw(sk, rs); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr_full_bw_reached(sk) || !bbr->ecn_eligible || ++ !bbr_param(sk, full_ecn_cnt) || !bbr_param(sk, ecn_thresh)) ++ return; ++ ++ if (ce_ratio >= bbr_param(sk, ecn_thresh)) ++ bbr->startup_ecn_rounds++; ++ else ++ bbr->startup_ecn_rounds = 0; ++ ++ if (bbr->startup_ecn_rounds >= bbr_param(sk, full_ecn_cnt)) { ++ bbr_handle_queue_too_high_in_startup(sk); ++ return; ++ } ++} ++ ++/* Updates ecn_alpha and returns ce_ratio. -1 if not available. */ ++static int bbr_update_ecn_alpha(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct net *net = sock_net(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ s32 delivered, delivered_ce; ++ u64 alpha, ce_ratio; ++ u32 gain; ++ bool want_ecn_alpha; ++ ++ /* See if we should use ECN sender logic for this connection. */ ++ if (!bbr->ecn_eligible && bbr_can_use_ecn(sk) && ++ bbr_param(sk, ecn_factor) && ++ (bbr->min_rtt_us <= bbr_ecn_max_rtt_us || ++ !bbr_ecn_max_rtt_us)) ++ bbr->ecn_eligible = 1; ++ ++ /* Skip updating alpha only if not ECN-eligible and PLB is disabled. */ ++ want_ecn_alpha = (bbr->ecn_eligible || ++ (bbr_can_use_ecn(sk) && ++ READ_ONCE(net->ipv4.sysctl_tcp_plb_enabled))); ++ if (!want_ecn_alpha) ++ return -1; ++ ++ delivered = tp->delivered - bbr->alpha_last_delivered; ++ delivered_ce = tp->delivered_ce - bbr->alpha_last_delivered_ce; ++ ++ if (delivered == 0 || /* avoid divide by zero */ ++ WARN_ON_ONCE(delivered < 0 || delivered_ce < 0)) /* backwards? */ ++ return -1; ++ ++ BUILD_BUG_ON(BBR_SCALE != TCP_PLB_SCALE); ++ ce_ratio = (u64)delivered_ce << BBR_SCALE; ++ do_div(ce_ratio, delivered); ++ ++ gain = bbr_param(sk, ecn_alpha_gain); ++ alpha = ((BBR_UNIT - gain) * bbr->ecn_alpha) >> BBR_SCALE; ++ alpha += (gain * ce_ratio) >> BBR_SCALE; ++ bbr->ecn_alpha = min_t(u32, alpha, BBR_UNIT); ++ ++ bbr->alpha_last_delivered = tp->delivered; ++ bbr->alpha_last_delivered_ce = tp->delivered_ce; ++ ++ bbr_check_ecn_too_high_in_startup(sk, ce_ratio); ++ return (int)ce_ratio; ++} ++ ++/* Protective Load Balancing (PLB). PLB rehashes outgoing data (to a new IPv6 ++ * flow label) if it encounters sustained congestion in the form of ECN marks. ++ */ ++static void bbr_plb(struct sock *sk, const struct rate_sample *rs, int ce_ratio) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->round_start && ce_ratio >= 0) ++ tcp_plb_update_state(sk, &bbr->plb, ce_ratio); ++ ++ tcp_plb_check_rehash(sk, &bbr->plb); ++} ++ ++/* Each round trip of BBR_BW_PROBE_UP, double volume of probing data. */ ++static void bbr_raise_inflight_hi_slope(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 growth_this_round, cnt; ++ ++ /* Calculate "slope": packets S/Acked per inflight_hi increment. */ ++ growth_this_round = 1 << bbr->bw_probe_up_rounds; ++ bbr->bw_probe_up_rounds = min(bbr->bw_probe_up_rounds + 1, 30); ++ cnt = tcp_snd_cwnd(tp) / growth_this_round; ++ cnt = max(cnt, 1U); ++ bbr->bw_probe_up_cnt = cnt; ++} ++ ++/* In BBR_BW_PROBE_UP, not seeing high loss/ECN/queue, so raise inflight_hi. */ ++static void bbr_probe_inflight_hi_upward(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 delta; ++ ++ if (!tp->is_cwnd_limited || tcp_snd_cwnd(tp) < bbr->inflight_hi) ++ return; /* not fully using inflight_hi, so don't grow it */ ++ ++ /* For each bw_probe_up_cnt packets ACKed, increase inflight_hi by 1. */ ++ bbr->bw_probe_up_acks += rs->acked_sacked; ++ if (bbr->bw_probe_up_acks >= bbr->bw_probe_up_cnt) { ++ delta = bbr->bw_probe_up_acks / bbr->bw_probe_up_cnt; ++ bbr->bw_probe_up_acks -= delta * bbr->bw_probe_up_cnt; ++ bbr->inflight_hi += delta; ++ bbr->try_fast_path = 0; /* Need to update cwnd */ ++ } ++ ++ if (bbr->round_start) ++ bbr_raise_inflight_hi_slope(sk); ++} ++ ++/* Does loss/ECN rate for this sample say inflight is "too high"? ++ * This is used by both the bbr_check_loss_too_high_in_startup() function, ++ * which can be used in either v1 or v2, and the PROBE_UP phase of v2, which ++ * uses it to notice when loss/ECN rates suggest inflight is too high. ++ */ ++static bool bbr_is_inflight_too_high(const struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ const struct bbr *bbr = inet_csk_ca(sk); ++ u32 loss_thresh, ecn_thresh; ++ ++ if (rs->lost > 0 && rs->tx_in_flight) { ++ loss_thresh = (u64)rs->tx_in_flight * bbr_param(sk, loss_thresh) >> ++ BBR_SCALE; ++ if (rs->lost > loss_thresh) { ++ return true; ++ } ++ } ++ ++ if (rs->delivered_ce > 0 && rs->delivered > 0 && ++ bbr->ecn_eligible && bbr_param(sk, ecn_thresh)) { ++ ecn_thresh = (u64)rs->delivered * bbr_param(sk, ecn_thresh) >> ++ BBR_SCALE; ++ if (rs->delivered_ce > ecn_thresh) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/* Calculate the tx_in_flight level that corresponded to excessive loss. ++ * We find "lost_prefix" segs of the skb where loss rate went too high, ++ * by solving for "lost_prefix" in the following equation: ++ * lost / inflight >= loss_thresh ++ * (lost_prev + lost_prefix) / (inflight_prev + lost_prefix) >= loss_thresh ++ * Then we take that equation, convert it to fixed point, and ++ * round up to the nearest packet. ++ */ ++static u32 bbr_inflight_hi_from_lost_skb(const struct sock *sk, ++ const struct rate_sample *rs, ++ const struct sk_buff *skb) ++{ ++ const struct tcp_sock *tp = tcp_sk(sk); ++ u32 loss_thresh = bbr_param(sk, loss_thresh); ++ u32 pcount, divisor, inflight_hi; ++ s32 inflight_prev, lost_prev; ++ u64 loss_budget, lost_prefix; ++ ++ pcount = tcp_skb_pcount(skb); ++ ++ /* How much data was in flight before this skb? */ ++ inflight_prev = rs->tx_in_flight - pcount; ++ if (inflight_prev < 0) { ++ WARN_ONCE(tcp_skb_tx_in_flight_is_suspicious( ++ pcount, ++ TCP_SKB_CB(skb)->sacked, ++ rs->tx_in_flight), ++ "tx_in_flight: %u pcount: %u reneg: %u", ++ rs->tx_in_flight, pcount, tcp_sk(sk)->is_sack_reneg); ++ return ~0U; ++ } ++ ++ /* How much inflight data was marked lost before this skb? */ ++ lost_prev = rs->lost - pcount; ++ if (WARN_ONCE(lost_prev < 0, ++ "cwnd: %u ca: %d out: %u lost: %u pif: %u " ++ "tx_in_flight: %u tx.lost: %u tp->lost: %u rs->lost: %d " ++ "lost_prev: %d pcount: %d seq: %u end_seq: %u reneg: %u", ++ tcp_snd_cwnd(tp), inet_csk(sk)->icsk_ca_state, ++ tp->packets_out, tp->lost_out, tcp_packets_in_flight(tp), ++ rs->tx_in_flight, TCP_SKB_CB(skb)->tx.lost, tp->lost, ++ rs->lost, lost_prev, pcount, ++ TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, ++ tp->is_sack_reneg)) ++ return ~0U; ++ ++ /* At what prefix of this lost skb did losss rate exceed loss_thresh? */ ++ loss_budget = (u64)inflight_prev * loss_thresh + BBR_UNIT - 1; ++ loss_budget >>= BBR_SCALE; ++ if (lost_prev >= loss_budget) { ++ lost_prefix = 0; /* previous losses crossed loss_thresh */ ++ } else { ++ lost_prefix = loss_budget - lost_prev; ++ lost_prefix <<= BBR_SCALE; ++ divisor = BBR_UNIT - loss_thresh; ++ if (WARN_ON_ONCE(!divisor)) /* loss_thresh is 8 bits */ ++ return ~0U; ++ do_div(lost_prefix, divisor); ++ } ++ ++ inflight_hi = inflight_prev + lost_prefix; ++ return inflight_hi; ++} ++ ++/* If loss/ECN rates during probing indicated we may have overfilled a ++ * buffer, return an operating point that tries to leave unutilized headroom in ++ * the path for other flows, for fairness convergence and lower RTTs and loss. ++ */ ++static u32 bbr_inflight_with_headroom(const struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 headroom, headroom_fraction; ++ ++ if (bbr->inflight_hi == ~0U) ++ return ~0U; ++ ++ headroom_fraction = bbr_param(sk, inflight_headroom); ++ headroom = ((u64)bbr->inflight_hi * headroom_fraction) >> BBR_SCALE; ++ headroom = max(headroom, 1U); ++ return max_t(s32, bbr->inflight_hi - headroom, ++ bbr_param(sk, cwnd_min_target)); ++} ++ ++/* Bound cwnd to a sensible level, based on our current probing state ++ * machine phase and model of a good inflight level (inflight_lo, inflight_hi). ++ */ ++static void bbr_bound_cwnd_for_inflight_model(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 cap; ++ ++ /* tcp_rcv_synsent_state_process() currently calls tcp_ack() ++ * and thus cong_control() without first initializing us(!). ++ */ ++ if (!bbr->initialized) ++ return; ++ ++ cap = ~0U; ++ if (bbr->mode == BBR_PROBE_BW && ++ bbr->cycle_idx != BBR_BW_PROBE_CRUISE) { ++ /* Probe to see if more packets fit in the path. */ ++ cap = bbr->inflight_hi; ++ } else { ++ if (bbr->mode == BBR_PROBE_RTT || ++ (bbr->mode == BBR_PROBE_BW && ++ bbr->cycle_idx == BBR_BW_PROBE_CRUISE)) ++ cap = bbr_inflight_with_headroom(sk); ++ } ++ /* Adapt to any loss/ECN since our last bw probe. */ ++ cap = min(cap, bbr->inflight_lo); ++ ++ cap = max_t(u32, cap, bbr_param(sk, cwnd_min_target)); ++ tcp_snd_cwnd_set(tp, min(cap, tcp_snd_cwnd(tp))); ++} ++ ++/* How should we multiplicatively cut bw or inflight limits based on ECN? */ ++static u32 bbr_ecn_cut(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ return BBR_UNIT - ++ ((bbr->ecn_alpha * bbr_param(sk, ecn_factor)) >> BBR_SCALE); ++} ++ ++/* Init lower bounds if have not inited yet. */ ++static void bbr_init_lower_bounds(struct sock *sk, bool init_bw) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (init_bw && bbr->bw_lo == ~0U) ++ bbr->bw_lo = bbr_max_bw(sk); ++ if (bbr->inflight_lo == ~0U) ++ bbr->inflight_lo = tcp_snd_cwnd(tp); ++} ++ ++/* Reduce bw and inflight to (1 - beta). */ ++static void bbr_loss_lower_bounds(struct sock *sk, u32 *bw, u32 *inflight) ++{ ++ struct bbr* bbr = inet_csk_ca(sk); ++ u32 loss_cut = BBR_UNIT - bbr_param(sk, beta); ++ ++ *bw = max_t(u32, bbr->bw_latest, ++ (u64)bbr->bw_lo * loss_cut >> BBR_SCALE); ++ *inflight = max_t(u32, bbr->inflight_latest, ++ (u64)bbr->inflight_lo * loss_cut >> BBR_SCALE); ++} ++ ++/* Reduce inflight to (1 - alpha*ecn_factor). */ ++static void bbr_ecn_lower_bounds(struct sock *sk, u32 *inflight) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 ecn_cut = bbr_ecn_cut(sk); ++ ++ *inflight = (u64)bbr->inflight_lo * ecn_cut >> BBR_SCALE; ++} ++ ++/* Estimate a short-term lower bound on the capacity available now, based ++ * on measurements of the current delivery process and recent history. When we ++ * are seeing loss/ECN at times when we are not probing bw, then conservatively ++ * move toward flow balance by multiplicatively cutting our short-term ++ * estimated safe rate and volume of data (bw_lo and inflight_lo). We use a ++ * multiplicative decrease in order to converge to a lower capacity in time ++ * logarithmic in the magnitude of the decrease. ++ * ++ * However, we do not cut our short-term estimates lower than the current rate ++ * and volume of delivered data from this round trip, since from the current ++ * delivery process we can estimate the measured capacity available now. ++ * ++ * Anything faster than that approach would knowingly risk high loss, which can ++ * cause low bw for Reno/CUBIC and high loss recovery latency for ++ * request/response flows using any congestion control. ++ */ ++static void bbr_adapt_lower_bounds(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 ecn_inflight_lo = ~0U; ++ ++ /* We only use lower-bound estimates when not probing bw. ++ * When probing we need to push inflight higher to probe bw. ++ */ ++ if (bbr_is_probing_bandwidth(sk)) ++ return; ++ ++ /* ECN response. */ ++ if (bbr->ecn_in_round && bbr_param(sk, ecn_factor)) { ++ bbr_init_lower_bounds(sk, false); ++ bbr_ecn_lower_bounds(sk, &ecn_inflight_lo); ++ } ++ ++ /* Loss response. */ ++ if (bbr->loss_in_round) { ++ bbr_init_lower_bounds(sk, true); ++ bbr_loss_lower_bounds(sk, &bbr->bw_lo, &bbr->inflight_lo); ++ } ++ ++ /* Adjust to the lower of the levels implied by loss/ECN. */ ++ bbr->inflight_lo = min(bbr->inflight_lo, ecn_inflight_lo); ++ bbr->bw_lo = max(1U, bbr->bw_lo); ++} ++ ++/* Reset any short-term lower-bound adaptation to congestion, so that we can ++ * push our inflight up. ++ */ ++static void bbr_reset_lower_bounds(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->bw_lo = ~0U; ++ bbr->inflight_lo = ~0U; ++} ++ ++/* After bw probing (STARTUP/PROBE_UP), reset signals before entering a state ++ * machine phase where we adapt our lower bound based on congestion signals. ++ */ ++static void bbr_reset_congestion_signals(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->loss_in_round = 0; ++ bbr->ecn_in_round = 0; ++ bbr->loss_in_cycle = 0; ++ bbr->ecn_in_cycle = 0; ++ bbr->bw_latest = 0; ++ bbr->inflight_latest = 0; ++} ++ ++static void bbr_exit_loss_recovery(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ tcp_snd_cwnd_set(tp, max(tcp_snd_cwnd(tp), bbr->prior_cwnd)); ++ bbr->try_fast_path = 0; /* bound cwnd using latest model */ ++} ++ ++/* Update rate and volume of delivered data from latest round trip. */ ++static void bbr_update_latest_delivery_signals( ++ struct sock *sk, const struct rate_sample *rs, struct bbr_context *ctx) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->loss_round_start = 0; ++ if (rs->interval_us <= 0 || !rs->acked_sacked) ++ return; /* Not a valid observation */ ++ ++ bbr->bw_latest = max_t(u32, bbr->bw_latest, ctx->sample_bw); ++ bbr->inflight_latest = max_t(u32, bbr->inflight_latest, rs->delivered); ++ ++ if (!before(rs->prior_delivered, bbr->loss_round_delivered)) { ++ bbr->loss_round_delivered = tp->delivered; ++ bbr->loss_round_start = 1; /* mark start of new round trip */ ++ } ++} ++ ++/* Once per round, reset filter for latest rate and volume of delivered data. */ ++static void bbr_advance_latest_delivery_signals( ++ struct sock *sk, const struct rate_sample *rs, struct bbr_context *ctx) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ /* If ACK matches a TLP retransmit, persist the filter. If we detect ++ * that a TLP retransmit plugged a tail loss, we'll want to remember ++ * how much data the path delivered before the tail loss. ++ */ ++ if (bbr->loss_round_start && !rs->is_acking_tlp_retrans_seq) { ++ bbr->bw_latest = ctx->sample_bw; ++ bbr->inflight_latest = rs->delivered; ++ } ++} ++ ++/* Update (most of) our congestion signals: track the recent rate and volume of ++ * delivered data, presence of loss, and EWMA degree of ECN marking. ++ */ ++static void bbr_update_congestion_signals( ++ struct sock *sk, const struct rate_sample *rs, struct bbr_context *ctx) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u64 bw; ++ ++ if (rs->interval_us <= 0 || !rs->acked_sacked) ++ return; /* Not a valid observation */ ++ bw = ctx->sample_bw; ++ ++ if (!rs->is_app_limited || bw >= bbr_max_bw(sk)) ++ bbr_take_max_bw_sample(sk, bw); ++ ++ bbr->loss_in_round |= (rs->losses > 0); ++ ++ if (!bbr->loss_round_start) ++ return; /* skip the per-round-trip updates */ ++ /* Now do per-round-trip updates. */ ++ bbr_adapt_lower_bounds(sk, rs); ++ ++ bbr->loss_in_round = 0; ++ bbr->ecn_in_round = 0; ++} ++ ++/* Bandwidth probing can cause loss. To help coexistence with loss-based ++ * congestion control we spread out our probing in a Reno-conscious way. Due to ++ * the shape of the Reno sawtooth, the time required between loss epochs for an ++ * idealized Reno flow is a number of round trips that is the BDP of that ++ * flow. We count packet-timed round trips directly, since measured RTT can ++ * vary widely, and Reno is driven by packet-timed round trips. ++ */ ++static bool bbr_is_reno_coexistence_probe_time(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 rounds; ++ ++ /* Random loss can shave some small percentage off of our inflight ++ * in each round. To survive this, flows need robust periodic probes. ++ */ ++ rounds = min_t(u32, bbr_param(sk, bw_probe_max_rounds), bbr_target_inflight(sk)); ++ return bbr->rounds_since_probe >= rounds; ++} ++ ++/* How long do we want to wait before probing for bandwidth (and risking ++ * loss)? We randomize the wait, for better mixing and fairness convergence. ++ * ++ * We bound the Reno-coexistence inter-bw-probe time to be 62-63 round trips. ++ * This is calculated to allow fairness with a 25Mbps, 30ms Reno flow, ++ * (eg 4K video to a broadband user): ++ * BDP = 25Mbps * .030sec /(1514bytes) = 61.9 packets ++ * ++ * We bound the BBR-native inter-bw-probe wall clock time to be: ++ * (a) higher than 2 sec: to try to avoid causing loss for a long enough time ++ * to allow Reno at 30ms to get 4K video bw, the inter-bw-probe time must ++ * be at least: 25Mbps * .030sec / (1514bytes) * 0.030sec = 1.9secs ++ * (b) lower than 3 sec: to ensure flows can start probing in a reasonable ++ * amount of time to discover unutilized bw on human-scale interactive ++ * time-scales (e.g. perhaps traffic from a web page download that we ++ * were competing with is now complete). ++ */ ++static void bbr_pick_probe_wait(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ /* Decide the random round-trip bound for wait until probe: */ ++ bbr->rounds_since_probe = ++ get_random_u32_below(bbr_param(sk, bw_probe_rand_rounds)); ++ /* Decide the random wall clock bound for wait until probe: */ ++ bbr->probe_wait_us = bbr_param(sk, bw_probe_base_us) + ++ get_random_u32_below(bbr_param(sk, bw_probe_rand_us)); ++} ++ ++static void bbr_set_cycle_idx(struct sock *sk, int cycle_idx) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->cycle_idx = cycle_idx; ++ /* New phase, so need to update cwnd and pacing rate. */ ++ bbr->try_fast_path = 0; ++} ++ ++/* Send at estimated bw to fill the pipe, but not queue. We need this phase ++ * before PROBE_UP, because as soon as we send faster than the available bw ++ * we will start building a queue, and if the buffer is shallow we can cause ++ * loss. If we do not fill the pipe before we cause this loss, our bw_hi and ++ * inflight_hi estimates will underestimate. ++ */ ++static void bbr_start_bw_probe_refill(struct sock *sk, u32 bw_probe_up_rounds) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr_reset_lower_bounds(sk); ++ bbr->bw_probe_up_rounds = bw_probe_up_rounds; ++ bbr->bw_probe_up_acks = 0; ++ bbr->stopped_risky_probe = 0; ++ bbr->ack_phase = BBR_ACKS_REFILLING; ++ bbr->next_rtt_delivered = tp->delivered; ++ bbr_set_cycle_idx(sk, BBR_BW_PROBE_REFILL); ++} ++ ++/* Now probe max deliverable data rate and volume. */ ++static void bbr_start_bw_probe_up(struct sock *sk, struct bbr_context *ctx) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr->ack_phase = BBR_ACKS_PROBE_STARTING; ++ bbr->next_rtt_delivered = tp->delivered; ++ bbr->cycle_mstamp = tp->tcp_mstamp; ++ bbr_reset_full_bw(sk); ++ bbr->full_bw = ctx->sample_bw; ++ bbr_set_cycle_idx(sk, BBR_BW_PROBE_UP); ++ bbr_raise_inflight_hi_slope(sk); ++} ++ ++/* Start a new PROBE_BW probing cycle of some wall clock length. Pick a wall ++ * clock time at which to probe beyond an inflight that we think to be ++ * safe. This will knowingly risk packet loss, so we want to do this rarely, to ++ * keep packet loss rates low. Also start a round-trip counter, to probe faster ++ * if we estimate a Reno flow at our BDP would probe faster. ++ */ ++static void bbr_start_bw_probe_down(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr_reset_congestion_signals(sk); ++ bbr->bw_probe_up_cnt = ~0U; /* not growing inflight_hi any more */ ++ bbr_pick_probe_wait(sk); ++ bbr->cycle_mstamp = tp->tcp_mstamp; /* start wall clock */ ++ bbr->ack_phase = BBR_ACKS_PROBE_STOPPING; ++ bbr->next_rtt_delivered = tp->delivered; ++ bbr_set_cycle_idx(sk, BBR_BW_PROBE_DOWN); ++} ++ ++/* Cruise: maintain what we estimate to be a neutral, conservative ++ * operating point, without attempting to probe up for bandwidth or down for ++ * RTT, and only reducing inflight in response to loss/ECN signals. ++ */ ++static void bbr_start_bw_probe_cruise(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->inflight_lo != ~0U) ++ bbr->inflight_lo = min(bbr->inflight_lo, bbr->inflight_hi); ++ ++ bbr_set_cycle_idx(sk, BBR_BW_PROBE_CRUISE); ++} ++ ++/* Loss and/or ECN rate is too high while probing. ++ * Adapt (once per bw probe) by cutting inflight_hi and then restarting cycle. ++ */ ++static void bbr_handle_inflight_too_high(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ const u32 beta = bbr_param(sk, beta); ++ ++ bbr->prev_probe_too_high = 1; ++ bbr->bw_probe_samples = 0; /* only react once per probe */ ++ /* If we are app-limited then we are not robustly ++ * probing the max volume of inflight data we think ++ * might be safe (analogous to how app-limited bw ++ * samples are not known to be robustly probing bw). ++ */ ++ if (!rs->is_app_limited) { ++ bbr->inflight_hi = max_t(u32, rs->tx_in_flight, ++ (u64)bbr_target_inflight(sk) * ++ (BBR_UNIT - beta) >> BBR_SCALE); ++ } ++ if (bbr->mode == BBR_PROBE_BW && bbr->cycle_idx == BBR_BW_PROBE_UP) ++ bbr_start_bw_probe_down(sk); ++} ++ ++/* If we're seeing bw and loss samples reflecting our bw probing, adapt ++ * using the signals we see. If loss or ECN mark rate gets too high, then adapt ++ * inflight_hi downward. If we're able to push inflight higher without such ++ * signals, push higher: adapt inflight_hi upward. ++ */ ++static bool bbr_adapt_upper_bounds(struct sock *sk, ++ const struct rate_sample *rs, ++ struct bbr_context *ctx) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ /* Track when we'll see bw/loss samples resulting from our bw probes. */ ++ if (bbr->ack_phase == BBR_ACKS_PROBE_STARTING && bbr->round_start) ++ bbr->ack_phase = BBR_ACKS_PROBE_FEEDBACK; ++ if (bbr->ack_phase == BBR_ACKS_PROBE_STOPPING && bbr->round_start) { ++ /* End of samples from bw probing phase. */ ++ bbr->bw_probe_samples = 0; ++ bbr->ack_phase = BBR_ACKS_INIT; ++ /* At this point in the cycle, our current bw sample is also ++ * our best recent chance at finding the highest available bw ++ * for this flow. So now is the best time to forget the bw ++ * samples from the previous cycle, by advancing the window. ++ */ ++ if (bbr->mode == BBR_PROBE_BW && !rs->is_app_limited) ++ bbr_advance_max_bw_filter(sk); ++ /* If we had an inflight_hi, then probed and pushed inflight all ++ * the way up to hit that inflight_hi without seeing any ++ * high loss/ECN in all the resulting ACKs from that probing, ++ * then probe up again, this time letting inflight persist at ++ * inflight_hi for a round trip, then accelerating beyond. ++ */ ++ if (bbr->mode == BBR_PROBE_BW && ++ bbr->stopped_risky_probe && !bbr->prev_probe_too_high) { ++ bbr_start_bw_probe_refill(sk, 0); ++ return true; /* yes, decided state transition */ ++ } ++ } ++ if (bbr_is_inflight_too_high(sk, rs)) { ++ if (bbr->bw_probe_samples) /* sample is from bw probing? */ ++ bbr_handle_inflight_too_high(sk, rs); ++ } else { ++ /* Loss/ECN rate is declared safe. Adjust upper bound upward. */ ++ ++ if (bbr->inflight_hi == ~0U) ++ return false; /* no excess queue signals yet */ ++ ++ /* To be resilient to random loss, we must raise bw/inflight_hi ++ * if we observe in any phase that a higher level is safe. ++ */ ++ if (rs->tx_in_flight > bbr->inflight_hi) { ++ bbr->inflight_hi = rs->tx_in_flight; ++ } ++ ++ if (bbr->mode == BBR_PROBE_BW && ++ bbr->cycle_idx == BBR_BW_PROBE_UP) ++ bbr_probe_inflight_hi_upward(sk, rs); ++ } ++ ++ return false; ++} ++ ++/* Check if it's time to probe for bandwidth now, and if so, kick it off. */ ++static bool bbr_check_time_to_probe_bw(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 n; ++ ++ /* If we seem to be at an operating point where we are not seeing loss ++ * but we are seeing ECN marks, then when the ECN marks cease we reprobe ++ * quickly (in case cross-traffic has ceased and freed up bw). ++ */ ++ if (bbr_param(sk, ecn_reprobe_gain) && bbr->ecn_eligible && ++ bbr->ecn_in_cycle && !bbr->loss_in_cycle && ++ inet_csk(sk)->icsk_ca_state == TCP_CA_Open) { ++ /* Calculate n so that when bbr_raise_inflight_hi_slope() ++ * computes growth_this_round as 2^n it will be roughly the ++ * desired volume of data (inflight_hi*ecn_reprobe_gain). ++ */ ++ n = ilog2((((u64)bbr->inflight_hi * ++ bbr_param(sk, ecn_reprobe_gain)) >> BBR_SCALE)); ++ bbr_start_bw_probe_refill(sk, n); ++ return true; ++ } ++ ++ if (bbr_has_elapsed_in_phase(sk, bbr->probe_wait_us) || ++ bbr_is_reno_coexistence_probe_time(sk)) { ++ bbr_start_bw_probe_refill(sk, 0); ++ return true; ++ } ++ return false; ++} ++ ++/* Is it time to transition from PROBE_DOWN to PROBE_CRUISE? */ ++static bool bbr_check_time_to_cruise(struct sock *sk, u32 inflight, u32 bw) ++{ ++ /* Always need to pull inflight down to leave headroom in queue. */ ++ if (inflight > bbr_inflight_with_headroom(sk)) ++ return false; ++ ++ return inflight <= bbr_inflight(sk, bw, BBR_UNIT); ++} ++ ++/* PROBE_BW state machine: cruise, refill, probe for bw, or drain? */ ++static void bbr_update_cycle_phase(struct sock *sk, ++ const struct rate_sample *rs, ++ struct bbr_context *ctx) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ bool is_bw_probe_done = false; ++ u32 inflight, bw; ++ ++ if (!bbr_full_bw_reached(sk)) ++ return; ++ ++ /* In DRAIN, PROBE_BW, or PROBE_RTT, adjust upper bounds. */ ++ if (bbr_adapt_upper_bounds(sk, rs, ctx)) ++ return; /* already decided state transition */ ++ ++ if (bbr->mode != BBR_PROBE_BW) ++ return; ++ ++ inflight = bbr_packets_in_net_at_edt(sk, rs->prior_in_flight); ++ bw = bbr_max_bw(sk); ++ ++ switch (bbr->cycle_idx) { ++ /* First we spend most of our time cruising with a pacing_gain of 1.0, ++ * which paces at the estimated bw, to try to fully use the pipe ++ * without building queue. If we encounter loss/ECN marks, we adapt ++ * by slowing down. ++ */ ++ case BBR_BW_PROBE_CRUISE: ++ if (bbr_check_time_to_probe_bw(sk, rs)) ++ return; /* already decided state transition */ ++ break; ++ ++ /* After cruising, when it's time to probe, we first "refill": we send ++ * at the estimated bw to fill the pipe, before probing higher and ++ * knowingly risking overflowing the bottleneck buffer (causing loss). ++ */ ++ case BBR_BW_PROBE_REFILL: ++ if (bbr->round_start) { ++ /* After one full round trip of sending in REFILL, we ++ * start to see bw samples reflecting our REFILL, which ++ * may be putting too much data in flight. ++ */ ++ bbr->bw_probe_samples = 1; ++ bbr_start_bw_probe_up(sk, ctx); ++ } ++ break; ++ ++ /* After we refill the pipe, we probe by using a pacing_gain > 1.0, to ++ * probe for bw. If we have not seen loss/ECN, we try to raise inflight ++ * to at least pacing_gain*BDP; note that this may take more than ++ * min_rtt if min_rtt is small (e.g. on a LAN). ++ * ++ * We terminate PROBE_UP bandwidth probing upon any of the following: ++ * ++ * (1) We've pushed inflight up to hit the inflight_hi target set in the ++ * most recent previous bw probe phase. Thus we want to start ++ * draining the queue immediately because it's very likely the most ++ * recently sent packets will fill the queue and cause drops. ++ * (2) If inflight_hi has not limited bandwidth growth recently, and ++ * yet delivered bandwidth has not increased much recently ++ * (bbr->full_bw_now). ++ * (3) Loss filter says loss rate is "too high". ++ * (4) ECN filter says ECN mark rate is "too high". ++ * ++ * (1) (2) checked here, (3) (4) checked in bbr_is_inflight_too_high() ++ */ ++ case BBR_BW_PROBE_UP: ++ if (bbr->prev_probe_too_high && ++ inflight >= bbr->inflight_hi) { ++ bbr->stopped_risky_probe = 1; ++ is_bw_probe_done = true; ++ } else { ++ if (tp->is_cwnd_limited && ++ tcp_snd_cwnd(tp) >= bbr->inflight_hi) { ++ /* inflight_hi is limiting bw growth */ ++ bbr_reset_full_bw(sk); ++ bbr->full_bw = ctx->sample_bw; ++ } else if (bbr->full_bw_now) { ++ /* Plateau in estimated bw. Pipe looks full. */ ++ is_bw_probe_done = true; ++ } ++ } ++ if (is_bw_probe_done) { ++ bbr->prev_probe_too_high = 0; /* no loss/ECN (yet) */ ++ bbr_start_bw_probe_down(sk); /* restart w/ down */ ++ } ++ break; ++ ++ /* After probing in PROBE_UP, we have usually accumulated some data in ++ * the bottleneck buffer (if bw probing didn't find more bw). We next ++ * enter PROBE_DOWN to try to drain any excess data from the queue. To ++ * do this, we use a pacing_gain < 1.0. We hold this pacing gain until ++ * our inflight is less then that target cruising point, which is the ++ * minimum of (a) the amount needed to leave headroom, and (b) the ++ * estimated BDP. Once inflight falls to match the target, we estimate ++ * the queue is drained; persisting would underutilize the pipe. ++ */ ++ case BBR_BW_PROBE_DOWN: ++ if (bbr_check_time_to_probe_bw(sk, rs)) ++ return; /* already decided state transition */ ++ if (bbr_check_time_to_cruise(sk, inflight, bw)) ++ bbr_start_bw_probe_cruise(sk); ++ break; ++ ++ default: ++ WARN_ONCE(1, "BBR invalid cycle index %u\n", bbr->cycle_idx); ++ } ++} ++ ++/* Exiting PROBE_RTT, so return to bandwidth probing in STARTUP or PROBE_BW. */ ++static void bbr_exit_probe_rtt(struct sock *sk) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ bbr_reset_lower_bounds(sk); ++ if (bbr_full_bw_reached(sk)) { ++ bbr->mode = BBR_PROBE_BW; ++ /* Raising inflight after PROBE_RTT may cause loss, so reset ++ * the PROBE_BW clock and schedule the next bandwidth probe for ++ * a friendly and randomized future point in time. ++ */ ++ bbr_start_bw_probe_down(sk); ++ /* Since we are exiting PROBE_RTT, we know inflight is ++ * below our estimated BDP, so it is reasonable to cruise. ++ */ ++ bbr_start_bw_probe_cruise(sk); ++ } else { ++ bbr->mode = BBR_STARTUP; ++ } ++} ++ ++/* Exit STARTUP based on loss rate > 1% and loss gaps in round >= N. Wait until ++ * the end of the round in recovery to get a good estimate of how many packets ++ * have been lost, and how many we need to drain with a low pacing rate. ++ */ ++static void bbr_check_loss_too_high_in_startup(struct sock *sk, ++ const struct rate_sample *rs) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr_full_bw_reached(sk)) ++ return; ++ ++ /* For STARTUP exit, check the loss rate at the end of each round trip ++ * of Recovery episodes in STARTUP. We check the loss rate at the end ++ * of the round trip to filter out noisy/low loss and have a better ++ * sense of inflight (extent of loss), so we can drain more accurately. ++ */ ++ if (rs->losses && bbr->loss_events_in_round < 0xf) ++ bbr->loss_events_in_round++; /* update saturating counter */ ++ if (bbr_param(sk, full_loss_cnt) && bbr->loss_round_start && ++ inet_csk(sk)->icsk_ca_state == TCP_CA_Recovery && ++ bbr->loss_events_in_round >= bbr_param(sk, full_loss_cnt) && ++ bbr_is_inflight_too_high(sk, rs)) { ++ bbr_handle_queue_too_high_in_startup(sk); ++ return; ++ } ++ if (bbr->loss_round_start) ++ bbr->loss_events_in_round = 0; ++} ++ ++/* Estimate when the pipe is full, using the change in delivery rate: BBR ++ * estimates bw probing filled the pipe if the estimated bw hasn't changed by ++ * at least bbr_full_bw_thresh (25%) after bbr_full_bw_cnt (3) non-app-limited ++ * rounds. Why 3 rounds: 1: rwin autotuning grows the rwin, 2: we fill the ++ * higher rwin, 3: we get higher delivery rate samples. Or transient ++ * cross-traffic or radio noise can go away. CUBIC Hystart shares a similar ++ * design goal, but uses delay and inter-ACK spacing instead of bandwidth. ++ */ ++static void bbr_check_full_bw_reached(struct sock *sk, ++ const struct rate_sample *rs, ++ struct bbr_context *ctx) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 bw_thresh, full_cnt, thresh; ++ ++ if (bbr->full_bw_now || rs->is_app_limited) ++ return; ++ ++ thresh = bbr_param(sk, full_bw_thresh); ++ full_cnt = bbr_param(sk, full_bw_cnt); ++ bw_thresh = (u64)bbr->full_bw * thresh >> BBR_SCALE; ++ if (ctx->sample_bw >= bw_thresh) { ++ bbr_reset_full_bw(sk); ++ bbr->full_bw = ctx->sample_bw; ++ return; ++ } ++ if (!bbr->round_start) ++ return; ++ ++bbr->full_bw_cnt; ++ bbr->full_bw_now = bbr->full_bw_cnt >= full_cnt; ++ bbr->full_bw_reached |= bbr->full_bw_now; ++} ++ ++/* If pipe is probably full, drain the queue and then enter steady-state. */ ++static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs, ++ struct bbr_context *ctx) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { ++ bbr->mode = BBR_DRAIN; /* drain queue we created */ ++ /* Set ssthresh to export purely for monitoring, to signal ++ * completion of initial STARTUP by setting to a non- ++ * TCP_INFINITE_SSTHRESH value (ssthresh is not used by BBR). ++ */ ++ tcp_sk(sk)->snd_ssthresh = ++ bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); ++ bbr_reset_congestion_signals(sk); ++ } /* fall through to check if in-flight is already small: */ ++ if (bbr->mode == BBR_DRAIN && ++ bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= ++ bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT)) { ++ bbr->mode = BBR_PROBE_BW; ++ bbr_start_bw_probe_down(sk); ++ } ++} ++ ++static void bbr_update_model(struct sock *sk, const struct rate_sample *rs, ++ struct bbr_context *ctx) ++{ ++ bbr_update_congestion_signals(sk, rs, ctx); + bbr_update_ack_aggregation(sk, rs); +- bbr_update_cycle_phase(sk, rs); +- bbr_check_full_bw_reached(sk, rs); +- bbr_check_drain(sk, rs); ++ bbr_check_loss_too_high_in_startup(sk, rs); ++ bbr_check_full_bw_reached(sk, rs, ctx); ++ bbr_check_drain(sk, rs, ctx); ++ bbr_update_cycle_phase(sk, rs, ctx); + bbr_update_min_rtt(sk, rs); +- bbr_update_gains(sk); ++} ++ ++/* Fast path for app-limited case. ++ * ++ * On each ack, we execute bbr state machine, which primarily consists of: ++ * 1) update model based on new rate sample, and ++ * 2) update control based on updated model or state change. ++ * ++ * There are certain workload/scenarios, e.g. app-limited case, where ++ * either we can skip updating model or we can skip update of both model ++ * as well as control. This provides signifcant softirq cpu savings for ++ * processing incoming acks. ++ * ++ * In case of app-limited, if there is no congestion (loss/ecn) and ++ * if observed bw sample is less than current estimated bw, then we can ++ * skip some of the computation in bbr state processing: ++ * ++ * - if there is no rtt/mode/phase change: In this case, since all the ++ * parameters of the network model are constant, we can skip model ++ * as well control update. ++ * ++ * - else we can skip rest of the model update. But we still need to ++ * update the control to account for the new rtt/mode/phase. ++ * ++ * Returns whether we can take fast path or not. ++ */ ++static bool bbr_run_fast_path(struct sock *sk, bool *update_model, ++ const struct rate_sample *rs, struct bbr_context *ctx) ++{ ++ struct bbr *bbr = inet_csk_ca(sk); ++ u32 prev_min_rtt_us, prev_mode; ++ ++ if (bbr_param(sk, fast_path) && bbr->try_fast_path && ++ rs->is_app_limited && ctx->sample_bw < bbr_max_bw(sk) && ++ !bbr->loss_in_round && !bbr->ecn_in_round ) { ++ prev_mode = bbr->mode; ++ prev_min_rtt_us = bbr->min_rtt_us; ++ bbr_check_drain(sk, rs, ctx); ++ bbr_update_cycle_phase(sk, rs, ctx); ++ bbr_update_min_rtt(sk, rs); ++ ++ if (bbr->mode == prev_mode && ++ bbr->min_rtt_us == prev_min_rtt_us && ++ bbr->try_fast_path) { ++ return true; ++ } ++ ++ /* Skip model update, but control still needs to be updated */ ++ *update_model = false; ++ } ++ return false; + } + + __bpf_kfunc static void bbr_main(struct sock *sk, u32 ack, int flag, const struct rate_sample *rs) + { ++ struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); +- u32 bw; ++ struct bbr_context ctx = { 0 }; ++ bool update_model = true; ++ u32 bw, round_delivered; ++ int ce_ratio = -1; ++ ++ round_delivered = bbr_update_round_start(sk, rs, &ctx); ++ if (bbr->round_start) { ++ bbr->rounds_since_probe = ++ min_t(s32, bbr->rounds_since_probe + 1, 0xFF); ++ ce_ratio = bbr_update_ecn_alpha(sk); ++ } ++ bbr_plb(sk, rs, ce_ratio); ++ ++ bbr->ecn_in_round |= (bbr->ecn_eligible && rs->is_ece); ++ bbr_calculate_bw_sample(sk, rs, &ctx); ++ bbr_update_latest_delivery_signals(sk, rs, &ctx); + +- bbr_update_model(sk, rs); ++ if (bbr_run_fast_path(sk, &update_model, rs, &ctx)) ++ goto out; + ++ if (update_model) ++ bbr_update_model(sk, rs, &ctx); ++ ++ bbr_update_gains(sk); + bw = bbr_bw(sk); + bbr_set_pacing_rate(sk, bw, bbr->pacing_gain); +- bbr_set_cwnd(sk, rs, rs->acked_sacked, bw, bbr->cwnd_gain); ++ bbr_set_cwnd(sk, rs, rs->acked_sacked, bw, bbr->cwnd_gain, ++ tcp_snd_cwnd(tp), &ctx); ++ bbr_bound_cwnd_for_inflight_model(sk); ++ ++out: ++ bbr_advance_latest_delivery_signals(sk, rs, &ctx); ++ bbr->prev_ca_state = inet_csk(sk)->icsk_ca_state; ++ bbr->loss_in_cycle |= rs->lost > 0; ++ bbr->ecn_in_cycle |= rs->delivered_ce > 0; + } + + __bpf_kfunc static void bbr_init(struct sock *sk) +@@ -1056,20 +2079,21 @@ __bpf_kfunc static void bbr_init(struct + struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); + +- bbr->prior_cwnd = 0; ++ bbr->initialized = 1; ++ ++ bbr->init_cwnd = min(0x7FU, tcp_snd_cwnd(tp)); ++ bbr->prior_cwnd = tp->prior_cwnd; + tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; +- bbr->rtt_cnt = 0; + bbr->next_rtt_delivered = tp->delivered; + bbr->prev_ca_state = TCP_CA_Open; +- bbr->packet_conservation = 0; + + bbr->probe_rtt_done_stamp = 0; + bbr->probe_rtt_round_done = 0; ++ bbr->probe_rtt_min_us = tcp_min_rtt(tp); ++ bbr->probe_rtt_min_stamp = tcp_jiffies32; + bbr->min_rtt_us = tcp_min_rtt(tp); + bbr->min_rtt_stamp = tcp_jiffies32; + +- minmax_reset(&bbr->bw, bbr->rtt_cnt, 0); /* init max bw to 0 */ +- + bbr->has_seen_rtt = 0; + bbr_init_pacing_rate_from_rtt(sk); + +@@ -1080,7 +2104,7 @@ __bpf_kfunc static void bbr_init(struct + bbr->full_bw_cnt = 0; + bbr->cycle_mstamp = 0; + bbr->cycle_idx = 0; +- bbr_reset_lt_bw_sampling(sk); ++ + bbr_reset_startup_mode(sk); + + bbr->ack_epoch_mstamp = tp->tcp_mstamp; +@@ -1090,78 +2114,236 @@ __bpf_kfunc static void bbr_init(struct + bbr->extra_acked[0] = 0; + bbr->extra_acked[1] = 0; + ++ bbr->ce_state = 0; ++ bbr->prior_rcv_nxt = tp->rcv_nxt; ++ bbr->try_fast_path = 0; ++ + cmpxchg(&sk->sk_pacing_status, SK_PACING_NONE, SK_PACING_NEEDED); ++ ++ /* Start sampling ECN mark rate after first full flight is ACKed: */ ++ bbr->loss_round_delivered = tp->delivered + 1; ++ bbr->loss_round_start = 0; ++ bbr->undo_bw_lo = 0; ++ bbr->undo_inflight_lo = 0; ++ bbr->undo_inflight_hi = 0; ++ bbr->loss_events_in_round = 0; ++ bbr->startup_ecn_rounds = 0; ++ bbr_reset_congestion_signals(sk); ++ bbr->bw_lo = ~0U; ++ bbr->bw_hi[0] = 0; ++ bbr->bw_hi[1] = 0; ++ bbr->inflight_lo = ~0U; ++ bbr->inflight_hi = ~0U; ++ bbr_reset_full_bw(sk); ++ bbr->bw_probe_up_cnt = ~0U; ++ bbr->bw_probe_up_acks = 0; ++ bbr->bw_probe_up_rounds = 0; ++ bbr->probe_wait_us = 0; ++ bbr->stopped_risky_probe = 0; ++ bbr->ack_phase = BBR_ACKS_INIT; ++ bbr->rounds_since_probe = 0; ++ bbr->bw_probe_samples = 0; ++ bbr->prev_probe_too_high = 0; ++ bbr->ecn_eligible = 0; ++ bbr->ecn_alpha = bbr_param(sk, ecn_alpha_init); ++ bbr->alpha_last_delivered = 0; ++ bbr->alpha_last_delivered_ce = 0; ++ bbr->plb.pause_until = 0; ++ ++ tp->fast_ack_mode = bbr_fast_ack_mode ? 1 : 0; + } + +-__bpf_kfunc static u32 bbr_sndbuf_expand(struct sock *sk) ++/* BBR marks the current round trip as a loss round. */ ++static void bbr_note_loss(struct sock *sk) + { +- /* Provision 3 * cwnd since BBR may slow-start even during recovery. */ +- return 3; ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ ++ /* Capture "current" data over the full round trip of loss, to ++ * have a better chance of observing the full capacity of the path. ++ */ ++ if (!bbr->loss_in_round) /* first loss in this round trip? */ ++ bbr->loss_round_delivered = tp->delivered; /* set round trip */ ++ bbr->loss_in_round = 1; ++ bbr->loss_in_cycle = 1; + } + +-/* In theory BBR does not need to undo the cwnd since it does not +- * always reduce cwnd on losses (see bbr_main()). Keep it for now. +- */ ++/* Core TCP stack informs us that the given skb was just marked lost. */ ++__bpf_kfunc static void bbr_skb_marked_lost(struct sock *sk, ++ const struct sk_buff *skb) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ struct tcp_skb_cb *scb = TCP_SKB_CB(skb); ++ struct rate_sample rs = {}; ++ ++ bbr_note_loss(sk); ++ ++ if (!bbr->bw_probe_samples) ++ return; /* not an skb sent while probing for bandwidth */ ++ if (unlikely(!scb->tx.delivered_mstamp)) ++ return; /* skb was SACKed, reneged, marked lost; ignore it */ ++ /* We are probing for bandwidth. Construct a rate sample that ++ * estimates what happened in the flight leading up to this lost skb, ++ * then see if the loss rate went too high, and if so at which packet. ++ */ ++ rs.tx_in_flight = scb->tx.in_flight; ++ rs.lost = tp->lost - scb->tx.lost; ++ rs.is_app_limited = scb->tx.is_app_limited; ++ if (bbr_is_inflight_too_high(sk, &rs)) { ++ rs.tx_in_flight = bbr_inflight_hi_from_lost_skb(sk, &rs, skb); ++ bbr_handle_inflight_too_high(sk, &rs); ++ } ++} ++ ++static void bbr_run_loss_probe_recovery(struct sock *sk) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct bbr *bbr = inet_csk_ca(sk); ++ struct rate_sample rs = {0}; ++ ++ bbr_note_loss(sk); ++ ++ if (!bbr->bw_probe_samples) ++ return; /* not sent while probing for bandwidth */ ++ /* We are probing for bandwidth. Construct a rate sample that ++ * estimates what happened in the flight leading up to this ++ * loss, then see if the loss rate went too high. ++ */ ++ rs.lost = 1; /* TLP probe repaired loss of a single segment */ ++ rs.tx_in_flight = bbr->inflight_latest + rs.lost; ++ rs.is_app_limited = tp->tlp_orig_data_app_limited; ++ if (bbr_is_inflight_too_high(sk, &rs)) ++ bbr_handle_inflight_too_high(sk, &rs); ++} ++ ++/* Revert short-term model if current loss recovery event was spurious. */ + __bpf_kfunc static u32 bbr_undo_cwnd(struct sock *sk) + { + struct bbr *bbr = inet_csk_ca(sk); + +- bbr->full_bw = 0; /* spurious slow-down; reset full pipe detection */ +- bbr->full_bw_cnt = 0; +- bbr_reset_lt_bw_sampling(sk); +- return tcp_snd_cwnd(tcp_sk(sk)); ++ bbr_reset_full_bw(sk); /* spurious slow-down; reset full bw detector */ ++ bbr->loss_in_round = 0; ++ ++ /* Revert to cwnd and other state saved before loss episode. */ ++ bbr->bw_lo = max(bbr->bw_lo, bbr->undo_bw_lo); ++ bbr->inflight_lo = max(bbr->inflight_lo, bbr->undo_inflight_lo); ++ bbr->inflight_hi = max(bbr->inflight_hi, bbr->undo_inflight_hi); ++ bbr->try_fast_path = 0; /* take slow path to set proper cwnd, pacing */ ++ return bbr->prior_cwnd; + } + +-/* Entering loss recovery, so save cwnd for when we exit or undo recovery. */ ++/* Entering loss recovery, so save state for when we undo recovery. */ + __bpf_kfunc static u32 bbr_ssthresh(struct sock *sk) + { ++ struct bbr *bbr = inet_csk_ca(sk); ++ + bbr_save_cwnd(sk); ++ /* For undo, save state that adapts based on loss signal. */ ++ bbr->undo_bw_lo = bbr->bw_lo; ++ bbr->undo_inflight_lo = bbr->inflight_lo; ++ bbr->undo_inflight_hi = bbr->inflight_hi; + return tcp_sk(sk)->snd_ssthresh; + } + ++static enum tcp_bbr_phase bbr_get_phase(struct bbr *bbr) ++{ ++ switch (bbr->mode) { ++ case BBR_STARTUP: ++ return BBR_PHASE_STARTUP; ++ case BBR_DRAIN: ++ return BBR_PHASE_DRAIN; ++ case BBR_PROBE_BW: ++ break; ++ case BBR_PROBE_RTT: ++ return BBR_PHASE_PROBE_RTT; ++ default: ++ return BBR_PHASE_INVALID; ++ } ++ switch (bbr->cycle_idx) { ++ case BBR_BW_PROBE_UP: ++ return BBR_PHASE_PROBE_BW_UP; ++ case BBR_BW_PROBE_DOWN: ++ return BBR_PHASE_PROBE_BW_DOWN; ++ case BBR_BW_PROBE_CRUISE: ++ return BBR_PHASE_PROBE_BW_CRUISE; ++ case BBR_BW_PROBE_REFILL: ++ return BBR_PHASE_PROBE_BW_REFILL; ++ default: ++ return BBR_PHASE_INVALID; ++ } ++} ++ + static size_t bbr_get_info(struct sock *sk, u32 ext, int *attr, +- union tcp_cc_info *info) ++ union tcp_cc_info *info) + { + if (ext & (1 << (INET_DIAG_BBRINFO - 1)) || + ext & (1 << (INET_DIAG_VEGASINFO - 1))) { +- struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); +- u64 bw = bbr_bw(sk); +- +- bw = bw * tp->mss_cache * USEC_PER_SEC >> BW_SCALE; +- memset(&info->bbr, 0, sizeof(info->bbr)); +- info->bbr.bbr_bw_lo = (u32)bw; +- info->bbr.bbr_bw_hi = (u32)(bw >> 32); +- info->bbr.bbr_min_rtt = bbr->min_rtt_us; +- info->bbr.bbr_pacing_gain = bbr->pacing_gain; +- info->bbr.bbr_cwnd_gain = bbr->cwnd_gain; ++ u64 bw = bbr_bw_bytes_per_sec(sk, bbr_bw(sk)); ++ u64 bw_hi = bbr_bw_bytes_per_sec(sk, bbr_max_bw(sk)); ++ u64 bw_lo = bbr->bw_lo == ~0U ? ++ ~0ULL : bbr_bw_bytes_per_sec(sk, bbr->bw_lo); ++ struct tcp_bbr_info *bbr_info = &info->bbr; ++ ++ memset(bbr_info, 0, sizeof(*bbr_info)); ++ bbr_info->bbr_bw_lo = (u32)bw; ++ bbr_info->bbr_bw_hi = (u32)(bw >> 32); ++ bbr_info->bbr_min_rtt = bbr->min_rtt_us; ++ bbr_info->bbr_pacing_gain = bbr->pacing_gain; ++ bbr_info->bbr_cwnd_gain = bbr->cwnd_gain; ++ bbr_info->bbr_bw_hi_lsb = (u32)bw_hi; ++ bbr_info->bbr_bw_hi_msb = (u32)(bw_hi >> 32); ++ bbr_info->bbr_bw_lo_lsb = (u32)bw_lo; ++ bbr_info->bbr_bw_lo_msb = (u32)(bw_lo >> 32); ++ bbr_info->bbr_mode = bbr->mode; ++ bbr_info->bbr_phase = (__u8)bbr_get_phase(bbr); ++ bbr_info->bbr_version = (__u8)BBR_VERSION; ++ bbr_info->bbr_inflight_lo = bbr->inflight_lo; ++ bbr_info->bbr_inflight_hi = bbr->inflight_hi; ++ bbr_info->bbr_extra_acked = bbr_extra_acked(sk); + *attr = INET_DIAG_BBRINFO; +- return sizeof(info->bbr); ++ return sizeof(*bbr_info); + } + return 0; + } + + __bpf_kfunc static void bbr_set_state(struct sock *sk, u8 new_state) + { ++ struct tcp_sock *tp = tcp_sk(sk); + struct bbr *bbr = inet_csk_ca(sk); + + if (new_state == TCP_CA_Loss) { +- struct rate_sample rs = { .losses = 1 }; + + bbr->prev_ca_state = TCP_CA_Loss; +- bbr->full_bw = 0; +- bbr->round_start = 1; /* treat RTO like end of a round */ +- bbr_lt_bw_sampling(sk, &rs); ++ tcp_plb_update_state_upon_rto(sk, &bbr->plb); ++ /* The tcp_write_timeout() call to sk_rethink_txhash() likely ++ * repathed this flow, so re-learn the min network RTT on the ++ * new path: ++ */ ++ bbr_reset_full_bw(sk); ++ if (!bbr_is_probing_bandwidth(sk) && bbr->inflight_lo == ~0U) { ++ /* bbr_adapt_lower_bounds() needs cwnd before ++ * we suffered an RTO, to update inflight_lo: ++ */ ++ bbr->inflight_lo = ++ max(tcp_snd_cwnd(tp), bbr->prior_cwnd); ++ } ++ } else if (bbr->prev_ca_state == TCP_CA_Loss && ++ new_state != TCP_CA_Loss) { ++ bbr_exit_loss_recovery(sk); + } + } + ++ + static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = { +- .flags = TCP_CONG_NON_RESTRICTED, ++ .flags = TCP_CONG_NON_RESTRICTED | TCP_CONG_WANTS_CE_EVENTS, + .name = "bbr", + .owner = THIS_MODULE, + .init = bbr_init, + .cong_control = bbr_main, + .sndbuf_expand = bbr_sndbuf_expand, ++ .skb_marked_lost = bbr_skb_marked_lost, + .undo_cwnd = bbr_undo_cwnd, + .cwnd_event = bbr_cwnd_event, + .ssthresh = bbr_ssthresh, +@@ -1174,10 +2356,11 @@ BTF_KFUNCS_START(tcp_bbr_check_kfunc_ids + BTF_ID_FLAGS(func, bbr_init) + BTF_ID_FLAGS(func, bbr_main) + BTF_ID_FLAGS(func, bbr_sndbuf_expand) ++BTF_ID_FLAGS(func, bbr_skb_marked_lost) + BTF_ID_FLAGS(func, bbr_undo_cwnd) + BTF_ID_FLAGS(func, bbr_cwnd_event) + BTF_ID_FLAGS(func, bbr_ssthresh) +-BTF_ID_FLAGS(func, bbr_min_tso_segs) ++BTF_ID_FLAGS(func, bbr_tso_segs) + BTF_ID_FLAGS(func, bbr_set_state) + BTF_KFUNCS_END(tcp_bbr_check_kfunc_ids) + +@@ -1210,5 +2393,12 @@ MODULE_AUTHOR("Van Jacobson "); + MODULE_AUTHOR("Yuchung Cheng "); + MODULE_AUTHOR("Soheil Hassas Yeganeh "); ++MODULE_AUTHOR("Priyaranjan Jha "); ++MODULE_AUTHOR("Yousuk Seung "); ++MODULE_AUTHOR("Kevin Yang "); ++MODULE_AUTHOR("Arjun Roy "); ++MODULE_AUTHOR("David Morley "); ++ + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_DESCRIPTION("TCP BBR (Bottleneck Bandwidth and RTT)"); ++MODULE_VERSION(__stringify(BBR_VERSION)); diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch new file mode 100644 index 000000000..5198547c1 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch @@ -0,0 +1,59 @@ +From 34211656d13a329fe2adbf7d9932c805338062b7 Mon Sep 17 00:00:00 2001 +From: Adithya Abraham Philip +Date: Fri, 11 Jun 2021 21:56:10 +0000 +Subject: [PATCH 17/19] net-tcp_bbr: v3: ensure ECN-enabled BBR flows set ECT + on retransmits + +Adds a new flag TCP_ECN_ECT_PERMANENT that is used by CCAs to +indicate that retransmitted packets and pure ACKs must have the +ECT bit set. This is necessary for BBR, which when using +ECN expects ECT to be set even on retransmitted packets and ACKs. + +Previous to this addition of TCP_ECN_ECT_PERMANENT, CCAs which can use +ECN but don't "need" it did not have a way to indicate that ECT should +be set on retransmissions/ACKs. + +Signed-off-by: Adithya Abraham Philip +Signed-off-by: Neal Cardwell +Change-Id: I8b048eaab35e136fe6501ef6cd89fd9faa15e6d2 +Signed-off-by: Alexandre Frade +--- + include/net/tcp.h | 1 + + net/ipv4/tcp_bbr.c | 3 +++ + net/ipv4/tcp_output.c | 3 ++- + 3 files changed, 6 insertions(+), 1 deletion(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -376,6 +376,7 @@ static inline void tcp_dec_quickack_mode + #define TCP_ECN_DEMAND_CWR 4 + #define TCP_ECN_SEEN 8 + #define TCP_ECN_LOW 16 ++#define TCP_ECN_ECT_PERMANENT 32 + + enum tcp_tw_status { + TCP_TW_SUCCESS = 0, +--- a/net/ipv4/tcp_bbr.c ++++ b/net/ipv4/tcp_bbr.c +@@ -2151,6 +2151,9 @@ __bpf_kfunc static void bbr_init(struct + bbr->plb.pause_until = 0; + + tp->fast_ack_mode = bbr_fast_ack_mode ? 1 : 0; ++ ++ if (bbr_can_use_ecn(sk)) ++ tp->ecn_flags |= TCP_ECN_ECT_PERMANENT; + } + + /* BBR marks the current round trip as a loss round. */ +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -390,7 +390,8 @@ static void tcp_ecn_send(struct sock *sk + th->cwr = 1; + skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; + } +- } else if (!tcp_ca_needs_ecn(sk)) { ++ } else if (!(tp->ecn_flags & TCP_ECN_ECT_PERMANENT) && ++ !tcp_ca_needs_ecn(sk)) { + /* ACK or retransmitted segment: clear ECT|CE */ + INET_ECN_dontxmit(sk); + } diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch new file mode 100644 index 000000000..eb1762553 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch @@ -0,0 +1,38 @@ +From 9d940cabd1eed8cdfa009d1530255578a1acd43c Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Sun, 23 Jul 2023 23:25:34 -0400 +Subject: [PATCH 18/19] tcp: export TCPI_OPT_ECN_LOW in tcp_info tcpi_options + field + +Analogous to other important ECN information, export TCPI_OPT_ECN_LOW +in tcp_info tcpi_options field. + +Signed-off-by: Neal Cardwell +Change-Id: I08d8d8c7e8780e6e37df54038ee50301ac5a0320 +Signed-off-by: Alexandre Frade +--- + include/uapi/linux/tcp.h | 1 + + net/ipv4/tcp.c | 2 ++ + 2 files changed, 3 insertions(+) + +--- a/include/uapi/linux/tcp.h ++++ b/include/uapi/linux/tcp.h +@@ -178,6 +178,7 @@ enum tcp_fastopen_client_fail { + #define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */ + #define TCPI_OPT_SYN_DATA 32 /* SYN-ACK acked data in SYN sent or rcvd */ + #define TCPI_OPT_USEC_TS 64 /* usec timestamps */ ++#define TCPI_OPT_ECN_LOW 128 /* Low-latency ECN configured at init */ + + /* + * Sender's congestion state indicating normal or abnormal situations +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3850,6 +3850,8 @@ void tcp_get_info(struct sock *sk, struc + info->tcpi_options |= TCPI_OPT_ECN; + if (tp->ecn_flags & TCP_ECN_SEEN) + info->tcpi_options |= TCPI_OPT_ECN_SEEN; ++ if (tp->ecn_flags & TCP_ECN_LOW) ++ info->tcpi_options |= TCPI_OPT_ECN_LOW; + if (tp->syn_data_acked) + info->tcpi_options |= TCPI_OPT_SYN_DATA; + if (tp->tcp_usec_ts) diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch new file mode 100644 index 000000000..9715997c8 --- /dev/null +++ b/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch @@ -0,0 +1,39 @@ +From 98a0fa5ab307df750c73790f9db0ce883af26982 Mon Sep 17 00:00:00 2001 +From: Oleksandr Natalenko +Date: Mon, 22 Jan 2024 20:21:40 +0100 +Subject: [PATCH 19/19] x86/cfi,bpf: Add tso_segs and skb_marked_lost to + bpf_struct_ops CFI + +--- + net/ipv4/bpf_tcp_ca.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/net/ipv4/bpf_tcp_ca.c ++++ b/net/ipv4/bpf_tcp_ca.c +@@ -305,11 +305,15 @@ static void bpf_tcp_ca_pkts_acked(struct + { + } + +-static u32 bpf_tcp_ca_min_tso_segs(struct sock *sk) ++static u32 bpf_tcp_ca_tso_segs(struct sock *sk, unsigned int mss_now) + { + return 0; + } + ++static void bpf_tcp_ca_skb_marked_lost(struct sock *sk, const struct sk_buff *skb) ++{ ++} ++ + static void bpf_tcp_ca_cong_control(struct sock *sk, u32 ack, int flag, + const struct rate_sample *rs) + { +@@ -340,7 +344,8 @@ static struct tcp_congestion_ops __bpf_o + .cwnd_event = bpf_tcp_ca_cwnd_event, + .in_ack_event = bpf_tcp_ca_in_ack_event, + .pkts_acked = bpf_tcp_ca_pkts_acked, +- .min_tso_segs = bpf_tcp_ca_min_tso_segs, ++ .tso_segs = bpf_tcp_ca_tso_segs, ++ .skb_marked_lost = bpf_tcp_ca_skb_marked_lost, + .cong_control = bpf_tcp_ca_cong_control, + .undo_cwnd = bpf_tcp_ca_undo_cwnd, + .sndbuf_expand = bpf_tcp_ca_sndbuf_expand, diff --git a/openwrt/patch/kernel-6.11/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.11/btf/990-btf-silence-btf-module-warning-messages.patch new file mode 100644 index 000000000..013337eb9 --- /dev/null +++ b/openwrt/patch/kernel-6.11/btf/990-btf-silence-btf-module-warning-messages.patch @@ -0,0 +1,21 @@ +From 5e5aa2d2722f835878447e93f7bc623d344611ae Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 14 Jan 2024 04:35:39 +0800 +Subject: [PATCH] btf: silence btf module warning messages + +Signed-off-by: sbwml +--- + kernel/bpf/btf.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/kernel/bpf/btf.c ++++ b/kernel/bpf/btf.c +@@ -7847,8 +7847,6 @@ static int btf_module_notify(struct noti + pr_warn("failed to validate module [%s] BTF: %ld\n", + mod->name, PTR_ERR(btf)); + err = PTR_ERR(btf); +- } else { +- pr_warn_once("Kernel module BTF mismatch detected, BTF debug info may be unavailable for some modules\n"); + } + goto out; + } diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch new file mode 100644 index 000000000..b8ee1c382 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch @@ -0,0 +1,4336 @@ +From a736ccf49716dde80660d93f32358b455662d1e1 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Tue, 25 Apr 2023 22:22:44 +0200 +Subject: [PATCH 01/25] LRNG: Entropy Source and DRNG Manager + +The kernel crypto API contains deterministic random number generators +(DRNG) which a caller must seed and reseed. The task of seeding a DRNG +is a non-trivial task requiring the consideration of a significant +number of aspects. The Entropy Source and DRNG Manager (ESDM) fills +that gap to transparently seed and reseed DRNGs. A user of the ESDM +obtains random numbers from an appropriately seeded and initialized +DRNG. Further, the ESDM controls various entropy sources guaranteeing +that they are properly initialized and managed. + +The ESDM consists of two main parts: + +- The entropy source (ES) manager implemented in lrng_es_mgr.c + controls the available entropy sources including pulling appropritate + amount of data from them for the DRNG manager. + +- The DRNG manager provided with lrng_drng_mgr.c controls the DRNG(s) + and ensures proper seeding and reseeding. + +The entropy source manager controls the entropy sources registered in +the lrng_es array. The entropy sources provide a function pointer data +structure that is used to obtain the services from it. + +The ES manager triggers the initial seeding of the DRNGs during boot +time in three stages: + +1. The DRNG is seeded from the entropy sources if all entropy sources + collectively have at least 32 bits of entropy available. The goal + of this step is to ensure that the DRNG receive some initial entropy + as early as possible. + +2. The DRNG is reseeded from the entropy sources if all entropy sources + collectively have at least 128 bits of entropy available. + +3. The DRNG is reseeded from the entropy sources if all entropy sources + collectively have at least 256 bits of entropy available. + +At the time of the reseeding steps, the DRNG requests as much entropy as +is available in order to skip certain steps and reach the seeding level +of 256 bits. This may imply that one or more of the aforementioned steps +are skipped. + +In all listed steps, the DRNG is (re)seeded with a number of random bytes +from the entropy pool that is at most the amount of entropy present in +the entropy pool. This means that for example when the entropy pool +contains 128 or more bits of entropy, the DRNG is seeded with that amount +of entropy as well. + +Entropy sources (ES) inform the ES manager when new entropy has been +collected using the lrng_es_add_entropy() function. That function +schedules a DRNG (re)seed with the DRNG manager. When the DRNG manager +requests entropy data, the function lrng_fill_seed_buffer fills the seed +buffer by iterating through all available ES. The output of all entropy +sources is concatenated with each other. Further, the seed buffer +contains the amount of entropy each entropy credits its data. Finally a +time stamp is added. + +The ES trigger such (re)seeding events only as long as not all DRNGs +are fully seeded with 256 bits of entropy. Once that seeding level is +reached, the triggers are not further processed. + +The DRNG manager initializes the initial DRNG instance during late stage +of the kernel boot process before user space is triggered. The DRNG is +seeded at the following occasions: + +- when the DRNG is initialized, the available amount of entropy is used, + +- during boot time until the DRNG is fully initialized, the reaching of + the aforementioned seeding steps of 32/128/256 bits of entropy trigger + a reseed of the DRNG. + +- at runtime after the elapse of 600 seconds since the last seeding, + the DRNG reseeding flag is raised + +- at runtime when more than 2^20 generate operations were performed by + the given DRNG since last reseeding, the reseeding flag is raised + +Raising the reseeding flag implies that the DRNG is seeded in process +context the next time a caller requests random numbers. + +At runtime, the DRNG manager requires at least 128 bits of entropy from +the entropy sources (or 256 bits when the FIPS mode is active to be +SP800-90C compliant). It may be possible that the entropy sources may +not deliver that amount. The DRNG is reseeded with the available amount +of entropy and continues to operate. Yet, when after 2^30 generate +requests since the last seeding with 128 bits (or 256 bits in FIPS mode) +the DRNG cannot be seeded with 128 bits (or 256 bits), the DRNG becomes +unseeded which means it will not produce random numbers until it is +fully reseeded again. + +To support the DRNG manager, a DRNG implementation is provided with +lrng_drng_kcapi.c. It uses the kernel crypto API RNG framework and +allows the specification of the used DRNG with the kernel command line +option of lrng_drng_kcapi.drng_name. If no reference is given, the +default is the SP800-90A DRBG. In case the chosen DRNG requires the seed +to have a certain length, a hash is used bring the entropy buffer into +the proper size. + +In addition, the DRNG manager controls the message digest implementation +offered to entropy sources when they want to perform a conditioning +operation. As entropy sources may require the conditioning operation at +any time, the default is a SHA-256 software hash implementation that +neither sleeps nor does it need any memory allocation operation. +Therefore, this hash is available even for the earliest kernel +operations. + +The initial drop of the ESDM includes the entropy source of the +"auxiliary" pool. This entropy source must always be present. It is an +entropy pool that is based on the state of a message digest. Every +insertion of data is a hash update operation. In order to obtain data, a +hash final operation is performed. The purpose of this auxiliary pool is +twofold: + +- Provide a general interface to inject an arbitrary amount of data from + any external source. When providing such data, the caller may specify + the amount of entropy it contains. + +- The auxiliary pool also provides the backtracking resistance for all + entropy sources. Once a seed buffer is filled from all entropy sources + it is re-inserted into the auxiliary pool at the same time it is used + for seeding the DRNG. Naturally, the insertion of the seed buffer into + the auxiliary pool is not credited with any entropy. + +If enabled during compile time with the boot option of +fips=1, the entropy source oversampling is activated. The oversampling +pulls 128 more bits of entropy than originally requested. This implies +that when 256 bits of entropy are requested for a (re)seed of a DRNG, +the ES are queried for 384 bits. This oversampling complies with +SP800-90C. + +This patch set contains a number of header files for subsequent +additions, but with the current Kconfig settings, these additional +settings will be folded to noops. + +Signed-off-by: Stephan Mueller +--- + drivers/char/Kconfig | 2 + + drivers/char/Makefile | 2 + + drivers/char/lrng/Kconfig | 1017 +++++++++++++++++ + drivers/char/lrng/Makefile | 11 + + drivers/char/lrng/lrng_definitions.h | 163 +++ + drivers/char/lrng/lrng_drng_atomic.h | 23 + + drivers/char/lrng/lrng_drng_chacha20.c | 195 ++++ + drivers/char/lrng/lrng_drng_chacha20.h | 42 + + drivers/char/lrng/lrng_drng_drbg.h | 13 + + drivers/char/lrng/lrng_drng_kcapi.h | 13 + + drivers/char/lrng/lrng_drng_mgr.c | 742 ++++++++++++ + drivers/char/lrng/lrng_drng_mgr.h | 86 ++ + drivers/char/lrng/lrng_es_aux.c | 335 ++++++ + drivers/char/lrng/lrng_es_aux.h | 44 + + drivers/char/lrng/lrng_es_cpu.h | 17 + + drivers/char/lrng/lrng_es_irq.h | 24 + + drivers/char/lrng/lrng_es_jent.h | 17 + + drivers/char/lrng/lrng_es_krng.h | 17 + + drivers/char/lrng/lrng_es_mgr.c | 506 ++++++++ + drivers/char/lrng/lrng_es_mgr.h | 56 + + drivers/char/lrng/lrng_es_mgr_cb.h | 87 ++ + drivers/char/lrng/lrng_es_sched.h | 20 + + drivers/char/lrng/lrng_es_timer_common.h | 83 ++ + drivers/char/lrng/lrng_interface_dev_common.h | 51 + + .../char/lrng/lrng_interface_random_kernel.h | 17 + + drivers/char/lrng/lrng_numa.h | 11 + + drivers/char/lrng/lrng_sha.h | 14 + + drivers/char/lrng/lrng_sha1.c | 88 ++ + drivers/char/lrng/lrng_sha256.c | 72 ++ + drivers/char/lrng/lrng_sysctl.h | 15 + + include/linux/lrng.h | 251 ++++ + 31 files changed, 4034 insertions(+) + create mode 100644 drivers/char/lrng/Kconfig + create mode 100644 drivers/char/lrng/Makefile + create mode 100644 drivers/char/lrng/lrng_definitions.h + create mode 100644 drivers/char/lrng/lrng_drng_atomic.h + create mode 100644 drivers/char/lrng/lrng_drng_chacha20.c + create mode 100644 drivers/char/lrng/lrng_drng_chacha20.h + create mode 100644 drivers/char/lrng/lrng_drng_drbg.h + create mode 100644 drivers/char/lrng/lrng_drng_kcapi.h + create mode 100644 drivers/char/lrng/lrng_drng_mgr.c + create mode 100644 drivers/char/lrng/lrng_drng_mgr.h + create mode 100644 drivers/char/lrng/lrng_es_aux.c + create mode 100644 drivers/char/lrng/lrng_es_aux.h + create mode 100644 drivers/char/lrng/lrng_es_cpu.h + create mode 100644 drivers/char/lrng/lrng_es_irq.h + create mode 100644 drivers/char/lrng/lrng_es_jent.h + create mode 100644 drivers/char/lrng/lrng_es_krng.h + create mode 100644 drivers/char/lrng/lrng_es_mgr.c + create mode 100644 drivers/char/lrng/lrng_es_mgr.h + create mode 100644 drivers/char/lrng/lrng_es_mgr_cb.h + create mode 100644 drivers/char/lrng/lrng_es_sched.h + create mode 100644 drivers/char/lrng/lrng_es_timer_common.h + create mode 100644 drivers/char/lrng/lrng_interface_dev_common.h + create mode 100644 drivers/char/lrng/lrng_interface_random_kernel.h + create mode 100644 drivers/char/lrng/lrng_numa.h + create mode 100644 drivers/char/lrng/lrng_sha.h + create mode 100644 drivers/char/lrng/lrng_sha1.c + create mode 100644 drivers/char/lrng/lrng_sha256.c + create mode 100644 drivers/char/lrng/lrng_sysctl.h + create mode 100644 include/linux/lrng.h + +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -422,4 +422,6 @@ config ADI + and SSM (Silicon Secured Memory). Intended consumers of this + driver include crash and makedumpfile. + ++source "drivers/char/lrng/Kconfig" ++ + endmenu +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -43,3 +43,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o + obj-$(CONFIG_XILLYBUS_CLASS) += xillybus/ + obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o + obj-$(CONFIG_ADI) += adi.o ++ ++obj-$(CONFIG_LRNG) += lrng/ +--- /dev/null ++++ b/drivers/char/lrng/Kconfig +@@ -0,0 +1,1017 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Linux Random Number Generator configuration ++# ++ ++config RANDOM_DEFAULT_IMPL ++ bool "Kernel RNG Default Implementation" ++ default y ++ help ++ The default random number generator as provided with ++ drivers/char/random.c is selected with this option. ++ ++config LRNG_AUTO_SELECTED ++ bool ++ default y if !RANDOM_DEFAULT_IMPL ++ default n if RANDOM_DEFAULT_IMPL ++ select LRNG ++ ++config LRNG ++ bool "Linux Random Number Generator" ++ default n ++ select CRYPTO_LIB_SHA256 if CRYPTO ++ help ++ The Linux Random Number Generator (LRNG) generates entropy ++ from different entropy sources. Each entropy source can ++ be enabled and configured independently. The interrupt ++ entropy source can be configured to be SP800-90B compliant. ++ The entire LRNG can be configured to be SP800-90C compliant. ++ Runtime-switchable cryptographic support is available. ++ The LRNG delivers significant entropy during boot. ++ ++ The LRNG also provides compliance to SP800-90A/B/C. ++ ++menu "Linux Random Number Generator Configuration" ++ depends on LRNG ++ ++if LRNG ++ ++config LRNG_SHA256 ++ bool ++ default y if CRYPTO_LIB_SHA256 ++ ++config LRNG_SHA1 ++ bool ++ default y if !CRYPTO_LIB_SHA256 ++ ++config LRNG_COMMON_DEV_IF ++ bool ++ ++config LRNG_DRNG_ATOMIC ++ bool ++ select LRNG_DRNG_CHACHA20 ++ ++config LRNG_SYSCTL ++ bool ++ depends on SYSCTL ++ ++config LRNG_RANDOM_IF ++ bool ++ default n if RANDOM_DEFAULT_IMPL ++ default y if !RANDOM_DEFAULT_IMPL ++ select LRNG_COMMON_DEV_IF ++ select LRNG_DRNG_ATOMIC ++ select LRNG_SYSCTL ++ ++menu "Specific DRNG seeding strategies" ++ ++config LRNG_AIS2031_NTG1_SEEDING_STRATEGY ++ bool "AIS 20/31 NTG.1 seeding strategy" ++ default n ++ help ++ When enabling this option, two entropy sources must ++ deliver 220 bits of entropy each to consider a DRNG ++ as fully seeded. Any two entropy sources can be used ++ to fulfill this requirement. If specific entropy sources ++ shall not be capable of contributing to this seeding ++ strategy, the respective entropy source must be configured ++ to provide less than 220 bits of entropy. ++ ++ The strategy is consistent with the requirements for ++ NTG.1 compliance in German AIS 20/31 draft from 2022 ++ and is only enforced with lrng_es_mgr.ntg1=1. ++ ++ Compliance with German AIS 20/31 from 2011 is always ++ present when using /dev/random with the flag O_SYNC or ++ getrandom(2) with GRND_RANDOM. ++ ++ If unsure, say N. ++ ++endmenu # "Specific DRNG seeding strategies" ++ ++# menu "LRNG Interfaces" ++# ++# config LRNG_KCAPI_IF ++# tristate "Interface with Kernel Crypto API" ++# depends on CRYPTO_RNG ++# help ++# The LRNG can be registered with the kernel crypto API's ++# random number generator framework. This offers a random ++# number generator with the name "lrng" and a priority that ++# is intended to be higher than the existing RNG ++# implementations. ++# ++# config LRNG_HWRAND_IF ++# tristate "Interface with Hardware Random Number Generator Framework" ++# depends on HW_RANDOM ++# select LRNG_DRNG_ATOMIC ++# help ++# The LRNG can be registered with the hardware random number ++# generator framework. This offers a random number generator ++# with the name "lrng" that is accessible via the framework. ++# For example it allows pulling data from the LRNG via the ++# /dev/hwrng file. ++# ++# config LRNG_DEV_IF ++# bool "Character device file interface" ++# select LRNG_COMMON_DEV_IF ++# help ++# The LRNG can create a character device file that operates ++# identically to /dev/random including IOCTL, read and write ++# operations. ++# ++# endmenu # "LRNG Interfaces" ++ ++# menu "Entropy Source Configuration" ++# ++# config LRNG_RUNTIME_ES_CONFIG ++# bool "Enable runtime configuration of entropy sources" ++# help ++# When enabling this option, the LRNG provides the mechanism ++# allowing to alter the entropy rate of each entropy source ++# during boot time and runtime. ++# ++# Each entropy source allows its entropy rate changed with ++# a kernel command line option. When not providing any ++# option, the default specified during kernel compilation ++# is applied. ++# ++# comment "Common Timer-based Entropy Source Configuration" ++# ++# config LRNG_IRQ_DFLT_TIMER_ES ++# bool ++# ++# config LRNG_SCHED_DFLT_TIMER_ES ++# bool ++# ++# config LRNG_TIMER_COMMON ++# bool ++# ++# choice ++# prompt "Default Timer-based Entropy Source" ++# default LRNG_IRQ_DFLT_TIMER_ES ++# depends on LRNG_TIMER_COMMON ++# help ++# Select the timer-based entropy source that is credited ++# with entropy. The other timer-based entropy sources may ++# be operational and provide data, but are credited with no ++# entropy. ++# ++# config LRNG_IRQ_DFLT_TIMER_ES ++# bool "Interrupt Entropy Source" ++# depends on LRNG_IRQ ++# help ++# The interrupt entropy source is selected as a timer-based ++# entropy source to provide entropy. ++# ++# config LRNG_SCHED_DFLT_TIMER_ES ++# bool "Scheduler Entropy Source" ++# depends on LRNG_SCHED ++# help ++# The scheduler entropy source is selected as timer-based ++# entropy source to provide entropy. ++# endchoice ++# ++# choice ++# prompt "LRNG Entropy Collection Pool Size" ++# default LRNG_COLLECTION_SIZE_1024 ++# depends on LRNG_TIMER_COMMON ++# help ++# Select the size of the LRNG entropy collection pool ++# storing data for the interrupt as well as the scheduler ++# entropy sources without performing a compression ++# operation. The larger the collection size is, the faster ++# the average interrupt handling will be. The collection ++# size represents the number of bytes of the per-CPU memory ++# used to batch up entropy event data. ++# ++# The default value is good for regular operations. Choose ++# larger sizes for servers that have no memory limitations. ++# If runtime memory is precious, choose a smaller size. ++# ++# The collection size is unrelated to the entropy rate ++# or the amount of entropy the LRNG can process. ++# ++# config LRNG_COLLECTION_SIZE_32 ++# depends on LRNG_CONTINUOUS_COMPRESSION_ENABLED ++# depends on !LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION ++# depends on !CRYPTO_FIPS ++# bool "32 interrupt events" ++# ++# config LRNG_COLLECTION_SIZE_256 ++# depends on !CRYPTO_FIPS ++# bool "256 interrupt events" ++# ++# config LRNG_COLLECTION_SIZE_512 ++# bool "512 interrupt events" ++# ++# config LRNG_COLLECTION_SIZE_1024 ++# bool "1024 interrupt events (default)" ++# ++# config LRNG_COLLECTION_SIZE_2048 ++# bool "2048 interrupt events" ++# ++# config LRNG_COLLECTION_SIZE_4096 ++# bool "4096 interrupt events" ++# ++# config LRNG_COLLECTION_SIZE_8192 ++# bool "8192 interrupt events" ++# ++# endchoice ++# ++# config LRNG_COLLECTION_SIZE ++# int ++# default 32 if LRNG_COLLECTION_SIZE_32 ++# default 256 if LRNG_COLLECTION_SIZE_256 ++# default 512 if LRNG_COLLECTION_SIZE_512 ++# default 1024 if LRNG_COLLECTION_SIZE_1024 ++# default 2048 if LRNG_COLLECTION_SIZE_2048 ++# default 4096 if LRNG_COLLECTION_SIZE_4096 ++# default 8192 if LRNG_COLLECTION_SIZE_8192 ++# ++# config LRNG_HEALTH_TESTS ++# bool "Enable internal entropy source online health tests" ++# depends on LRNG_TIMER_COMMON ++# help ++# The online health tests applied to the interrupt entropy ++# source and to the scheduler entropy source to validate ++# the noise source at runtime for fatal errors. These tests ++# include SP800-90B compliant tests which are invoked if ++# the system is booted with fips=1. In case of fatal errors ++# during active SP800-90B tests, the issue is logged and ++# the noise data is discarded. These tests are required for ++# full compliance of the interrupt entropy source with ++# SP800-90B. ++# ++# If both, the scheduler and the interrupt entropy sources, ++# are enabled, the health tests for both are applied ++# independent of each other. ++# ++# If unsure, say Y. ++# ++# config LRNG_RCT_BROKEN ++# bool "SP800-90B RCT with dangerous low cutoff value" ++# depends on LRNG_HEALTH_TESTS ++# depends on BROKEN ++# default n ++# help ++# This option enables a dangerously low SP800-90B repetitive ++# count test (RCT) cutoff value which makes it very likely ++# that the RCT is triggered to raise a self test failure. ++# ++# This option is ONLY intended for developers wanting to ++# test the effectiveness of the SP800-90B RCT health test. ++# ++# If unsure, say N. ++# ++# config LRNG_APT_BROKEN ++# bool "SP800-90B APT with dangerous low cutoff value" ++# depends on LRNG_HEALTH_TESTS ++# depends on BROKEN ++# default n ++# help ++# This option enables a dangerously low SP800-90B adaptive ++# proportion test (APT) cutoff value which makes it very ++# likely that the APT is triggered to raise a self test ++# failure. ++# ++# This option is ONLY intended for developers wanting to ++# test the effectiveness of the SP800-90B APT health test. ++# ++# If unsure, say N. ++# ++# Default taken from SP800-90B sec 4.4.1 - significance level 2^-30 ++# config LRNG_RCT_CUTOFF ++# int ++# default 31 if !LRNG_RCT_BROKEN ++# default 1 if LRNG_RCT_BROKEN ++# ++# Default taken from SP800-90B sec 4.4.1 - significance level 2^-80 ++# config LRNG_RCT_CUTOFF_PERMANENT ++# int ++# default 81 if !LRNG_RCT_BROKEN ++# default 2 if LRNG_RCT_BROKEN ++# ++# Default taken from SP800-90B sec 4.4.2 - significance level 2^-30 ++# config LRNG_APT_CUTOFF ++# int ++# default 325 if !LRNG_APT_BROKEN ++# default 32 if LRNG_APT_BROKEN ++# ++# Default taken from SP800-90B sec 4.4.2 - significance level 2^-80 ++# config LRNG_APT_CUTOFF_PERMANENT ++# int ++# default 371 if !LRNG_APT_BROKEN ++# default 33 if LRNG_APT_BROKEN ++# ++# comment "Interrupt Entropy Source" ++# ++# config LRNG_IRQ ++# bool "Enable Interrupt Entropy Source as LRNG Seed Source" ++# default y ++# depends on !RANDOM_DEFAULT_IMPL ++# select LRNG_TIMER_COMMON ++# help ++# The LRNG models an entropy source based on the timing of the ++# occurrence of interrupts. Enable this option to enable this ++# IRQ entropy source. ++# ++# The IRQ entropy source is triggered every time an interrupt ++# arrives and thus causes the interrupt handler to execute ++# slightly longer. Disabling the IRQ entropy source implies ++# that the performance penalty on the interrupt handler added ++# by the LRNG is eliminated. Yet, this entropy source is ++# considered to be an internal entropy source of the LRNG. ++# Thus, only disable it if you ensured that other entropy ++# sources are available that supply the LRNG with entropy. ++# ++# If you disable the IRQ entropy source, you MUST ensure ++# one or more entropy sources collectively have the ++# capability to deliver sufficient entropy with one invocation ++# at a rate compliant to the security strength of the DRNG ++# (usually 256 bits of entropy). In addition, if those ++# entropy sources do not deliver sufficient entropy during ++# first request, the reseed must be triggered from user ++# space or kernel space when sufficient entropy is considered ++# to be present. ++# ++# If unsure, say Y. ++# ++# choice ++# prompt "Continuous entropy compression boot time setting" ++# default LRNG_CONTINUOUS_COMPRESSION_ENABLED ++# depends on LRNG_IRQ ++# help ++# Select the default behavior of the interrupt entropy source ++# continuous compression operation. ++# ++# The LRNG IRQ ES collects entropy data during each interrupt. ++# For performance reasons, a amount of entropy data defined by ++# the LRNG entropy collection pool size is concatenated into ++# an array. When that array is filled up, a hash is calculated ++# to compress the entropy. That hash is calculated in ++# interrupt context. ++# ++# In case such hash calculation in interrupt context is deemed ++# too time-consuming, the continuous compression operation ++# can be disabled. If disabled, the collection of entropy will ++# not trigger a hash compression operation in interrupt context. ++# The compression happens only when the DRNG is reseeded which is ++# in process context. This implies that old entropy data ++# collected after the last DRNG-reseed is overwritten with newer ++# entropy data once the collection pool is full instead of ++# retaining its entropy with the compression operation. ++# ++# config LRNG_CONTINUOUS_COMPRESSION_ENABLED ++# bool "Enable continuous compression (default)" ++# ++# config LRNG_CONTINUOUS_COMPRESSION_DISABLED ++# bool "Disable continuous compression" ++# ++# endchoice ++# ++# config LRNG_ENABLE_CONTINUOUS_COMPRESSION ++# bool ++# default y if LRNG_CONTINUOUS_COMPRESSION_ENABLED ++# default n if LRNG_CONTINUOUS_COMPRESSION_DISABLED ++# ++# config LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION ++# bool "Runtime-switchable continuous entropy compression" ++# depends on LRNG_IRQ ++# help ++# Per default, the interrupt entropy source continuous ++# compression operation behavior is hard-wired into the kernel. ++# Enable this option to allow it to be configurable at boot time. ++# ++# To modify the default behavior of the continuous ++# compression operation, use the kernel command line option ++# of lrng_sw_noise.lrng_pcpu_continuous_compression. ++# ++# If unsure, say N. ++# ++# config LRNG_IRQ_ENTROPY_RATE ++# int "Interrupt Entropy Source Entropy Rate" ++# depends on LRNG_IRQ ++# range 256 4294967295 if LRNG_IRQ_DFLT_TIMER_ES ++# range 4294967295 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES ++# default 256 if LRNG_IRQ_DFLT_TIMER_ES ++# default 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES ++# help ++# The LRNG will collect the configured number of interrupts to ++# obtain 256 bits of entropy. This value can be set to any between ++# 256 and 4294967295. The LRNG guarantees that this value is not ++# lower than 256. This lower limit implies that one interrupt event ++# is credited with one bit of entropy. This value is subject to the ++# increase by the oversampling factor, if no high-resolution timer ++# is found. ++# ++# In order to effectively disable the interrupt entropy source, ++# the option has to be set to 4294967295. In this case, the ++# interrupt entropy source will still deliver data but without ++# being credited with entropy. ++# ++# comment "Jitter RNG Entropy Source" ++# ++# config LRNG_JENT ++# bool "Enable Jitter RNG as LRNG Seed Source" ++# depends on CRYPTO ++# select CRYPTO_JITTERENTROPY ++# help ++# The LRNG may use the Jitter RNG as entropy source. Enabling ++# this option enables the use of the Jitter RNG. Its default ++# entropy level is 16 bits of entropy per 256 data bits delivered ++# by the Jitter RNG. This entropy level can be changed at boot ++# time or at runtime with the lrng_base.jitterrng configuration ++# variable. ++# ++#choice ++# prompt "Jitter RNG Async Block Number" ++# default LRNG_JENT_ENTROPY_BLOCKS_NO_128 ++# depends on LRNG_JENT ++# help ++# Select the number of Jitter RNG entropy blocks the asynchronous ++# collection operation will fill. A caller for Jitter RNG entropy ++# will be given data from the pre-filled blocks if available to ++# prevent the Jitter RNG from utilizing the CPU too much in a ++# possible hot code path. ++# ++# The number specifies the number of 256/384 bit blocks that will ++# be held in memory and asynchronously filled with Jitter RNG data. ++# ++# The asynchronous entropy collection can also be disabled at ++# kernel startup time when setting the command line option of ++# lrng_es_jent.jent_async_enabled=0. Also, setting this option at ++# runtime is allowed via the corresponding SysFS interface. This ++# option is only available with the options SysFS and ++# CONFIG_LRNG_RUNTIME_ES_CONFIG enabled. ++# ++# config LRNG_JENT_ENTROPY_BLOCKS_DISABLED ++# bool "Async collection disabled" ++# ++# # Any block number is allowed, provided it is a power of 2 and ++# # equal or larger than 4 (4 is due to the division in ++# # lrng_jent_async_get when deciding to wake up the monitor). ++# config LRNG_JENT_ENTROPY_BLOCKS_NO_32 ++# bool "32 blocks" ++# ++# config LRNG_JENT_ENTROPY_BLOCKS_NO_64 ++# bool "64 blocks" ++# ++# config LRNG_JENT_ENTROPY_BLOCKS_NO_128 ++# bool "128 blocks (default)" ++# ++# config LRNG_JENT_ENTROPY_BLOCKS_NO_256 ++# bool "256 blocks" ++# ++# config LRNG_JENT_ENTROPY_BLOCKS_NO_512 ++# bool "512 blocks" ++# ++# config LRNG_JENT_ENTROPY_BLOCKS_NO_1024 ++# bool "1024 blocks" ++# ++#endchoice ++# ++#config LRNG_JENT_ENTROPY_BLOCKS ++# int ++# default 0 if LRNG_JENT_ENTROPY_BLOCKS_DISABLED ++# default 32 if LRNG_JENT_ENTROPY_BLOCKS_NO_32 ++# default 64 if LRNG_JENT_ENTROPY_BLOCKS_NO_64 ++# default 128 if LRNG_JENT_ENTROPY_BLOCKS_NO_128 ++# default 256 if LRNG_JENT_ENTROPY_BLOCKS_NO_256 ++# default 512 if LRNG_JENT_ENTROPY_BLOCKS_NO_512 ++# default 1024 if LRNG_JENT_ENTROPY_BLOCKS_NO_1024 ++# ++# config LRNG_JENT_ENTROPY_RATE ++# int "Jitter RNG Entropy Source Entropy Rate" ++# depends on LRNG_JENT ++# range 0 256 ++# default 16 ++# help ++# The option defines the amount of entropy the LRNG applies to 256 ++# bits of data obtained from the Jitter RNG entropy source. The ++# LRNG enforces the limit that this value must be in the range ++# between 0 and 256. ++# ++# When configuring this value to 0, the Jitter RNG entropy source ++# will provide 256 bits of data without being credited to contain ++# entropy. ++# ++# comment "CPU Entropy Source" ++# ++# config LRNG_CPU ++# bool "Enable CPU Entropy Source as LRNG Seed Source" ++# default y ++# help ++# Current CPUs commonly contain entropy sources which can be ++# used to seed the LRNG. For example, the Intel RDSEED ++# instruction, or the POWER DARN instruction will be sourced ++# to seed the LRNG if this option is enabled. ++# ++# Note, if this option is enabled and the underlying CPU ++# does not offer such entropy source, the LRNG will automatically ++# detect this and ignore the hardware. ++# ++# config LRNG_CPU_FULL_ENT_MULTIPLIER ++# int ++# default 1 if !LRNG_TEST_CPU_ES_COMPRESSION ++# default 123 if LRNG_TEST_CPU_ES_COMPRESSION ++# ++# config LRNG_CPU_ENTROPY_RATE ++# int "CPU Entropy Source Entropy Rate" ++# depends on LRNG_CPU ++# range 0 256 ++# default 8 ++# help ++# The option defines the amount of entropy the LRNG applies to 256 ++# bits of data obtained from the CPU entropy source. The LRNG ++# enforces the limit that this value must be in the range between ++# 0 and 256. ++# ++# When configuring this value to 0, the CPU entropy source will ++# provide 256 bits of data without being credited to contain ++# entropy. ++# ++# Note, this option is overwritten when the option ++# CONFIG_RANDOM_TRUST_CPU is set. ++# ++# comment "Scheduler Entropy Source" ++# ++# config LRNG_SCHED ++# bool "Enable Scheduer Entropy Source as LRNG Seed Source" ++# select LRNG_TIMER_COMMON ++# help ++# The LRNG models an entropy source based on the timing of the ++# occurrence of scheduler-triggered context switches. Enable ++# this option to enable this scheduler entropy source. ++# ++# The scheduler entropy source is triggered every time a ++# context switch is triggered thus causes the scheduler to ++# execute slightly longer. Disabling the scheduler entropy ++# source implies that the performance penalty on the scheduler ++# added by the LRNG is eliminated. Yet, this entropy source is ++# considered to be an internal entropy source of the LRNG. ++# Thus, only disable it if you ensured that other entropy ++# sources are available that supply the LRNG with entropy. ++# ++# If you disable the scheduler entropy source, you MUST ++# ensure one or more entropy sources collectively have the ++# capability to deliver sufficient entropy with one invocation ++# at a rate compliant to the security strength of the DRNG ++# (usually 256 bits of entropy). In addition, if those ++# entropy sources do not deliver sufficient entropy during ++# first request, the reseed must be triggered from user ++# space or kernel space when sufficient entropy is considered ++# to be present. ++# ++# If unsure, say Y. ++# ++# config LRNG_SCHED_ENTROPY_RATE ++# int "Scheduler Entropy Source Entropy Rate" ++# depends on LRNG_SCHED ++# range 256 4294967295 if LRNG_SCHED_DFLT_TIMER_ES ++# range 4294967295 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES ++# default 256 if LRNG_SCHED_DFLT_TIMER_ES ++# default 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES ++# help ++# The LRNG will collect the configured number of context switches ++# triggered by the scheduler to obtain 256 bits of entropy. This ++# value can be set to any between 256 and 4294967295. The LRNG ++# guarantees that this value is not lower than 256. This lower ++# limit implies that one interrupt event is credited with one bit ++# of entropy. This value is subject to the increase by the ++# oversampling factor, if no high-resolution timer is found. ++# ++# In order to effectively disable the scheduler entropy source, ++# the option has to be set to 4294967295. In this case, the ++# scheduler entropy source will still deliver data but without ++# being credited with entropy. ++# ++# comment "Kernel RNG Entropy Source" ++# ++# config LRNG_KERNEL_RNG ++# bool "Enable Kernel RNG as LRNG Seed Source" ++# depends on RANDOM_DEFAULT_IMPL ++# help ++# The LRNG may use the kernel RNG (random.c) as entropy ++# source. ++# ++# config LRNG_KERNEL_RNG_ENTROPY_RATE ++# int "Kernel RNG Entropy Source Entropy Rate" ++# depends on LRNG_KERNEL_RNG ++# range 0 256 ++# default 256 ++# help ++# The option defines the amount of entropy the LRNG applies to 256 ++# bits of data obtained from the kernel RNG entropy source. The ++# LRNG enforces the limit that this value must be in the range ++# between 0 and 256. ++# ++# When configuring this value to 0, the kernel RNG entropy source ++# will provide 256 bits of data without being credited to contain ++# entropy. ++# ++# Note: This value is set to 0 automatically when booting the ++# kernel in FIPS mode (with fips=1 kernel command line option). ++# This is due to the fact that random.c is not SP800-90B ++# compliant. ++# ++# endmenu # "Entropy Source Configuration" ++ ++config LRNG_DRNG_CHACHA20 ++ tristate ++ ++# config LRNG_DRBG ++# tristate ++# depends on CRYPTO ++# select CRYPTO_DRBG_MENU ++# ++# config LRNG_DRNG_KCAPI ++# tristate ++# depends on CRYPTO ++# select CRYPTO_RNG ++# ++# config LRNG_SWITCH ++# bool ++# ++# menuconfig LRNG_SWITCH_HASH ++# bool "Support conditioning hash runtime switching" ++# select LRNG_SWITCH ++# help ++# The LRNG uses a default message digest. With this ++# configuration option other message digests can be selected ++# and loaded at runtime. ++# ++# if LRNG_SWITCH_HASH ++# ++# config LRNG_HASH_KCAPI ++# tristate "Kernel crypto API hashing support for LRNG" ++# select CRYPTO_HASH ++# select CRYPTO_SHA512 ++# help ++# Enable the kernel crypto API support for entropy compression ++# and conditioning functions. ++# ++# endif # LRNG_SWITCH_HASH ++# ++# menuconfig LRNG_SWITCH_DRNG ++# bool "Support DRNG runtime switching" ++# select LRNG_SWITCH ++# help ++# The LRNG uses a default DRNG With this configuration ++# option other DRNGs or message digests can be selected and ++# loaded at runtime. ++# ++# if LRNG_SWITCH_DRNG ++# ++# config LRNG_SWITCH_DRNG_CHACHA20 ++# tristate "ChaCha20-based DRNG support for LRNG" ++# depends on !LRNG_DFLT_DRNG_CHACHA20 ++# select LRNG_DRNG_CHACHA20 ++# help ++# Enable the ChaCha20-based DRNG. This DRNG implementation ++# does not depend on the kernel crypto API presence. ++# ++# config LRNG_SWITCH_DRBG ++# tristate "SP800-90A support for the LRNG" ++# depends on !LRNG_DFLT_DRNG_DRBG ++# select LRNG_DRBG ++# help ++# Enable the SP800-90A DRBG support for the LRNG. Once the ++# module is loaded, output from /dev/random, /dev/urandom, ++# getrandom(2), or get_random_bytes_full is provided by a DRBG. ++# ++# config LRNG_SWITCH_DRNG_KCAPI ++# tristate "Kernel Crypto API support for the LRNG" ++# depends on !LRNG_DFLT_DRNG_KCAPI ++# depends on !LRNG_SWITCH_DRBG ++# select LRNG_DRNG_KCAPI ++# help ++# Enable the support for generic pseudo-random number ++# generators offered by the kernel crypto API with the ++# LRNG. Once the module is loaded, output from /dev/random, ++# /dev/urandom, getrandom(2), or get_random_bytes is ++# provided by the selected kernel crypto API RNG. ++# ++# endif # LRNG_SWITCH_DRNG ++ ++choice ++ prompt "LRNG Default DRNG" ++ default LRNG_DFLT_DRNG_CHACHA20 ++ help ++ Select the default deterministic random number generator ++ that is used by the LRNG. When enabling the switchable ++ cryptographic mechanism support, this DRNG can be ++ replaced at runtime. ++ ++ config LRNG_DFLT_DRNG_CHACHA20 ++ bool "ChaCha20-based DRNG" ++ select LRNG_DRNG_CHACHA20 ++ ++# config LRNG_DFLT_DRNG_DRBG ++# depends on RANDOM_DEFAULT_IMPL ++# bool "SP800-90A DRBG" ++# select LRNG_DRBG ++# ++# config LRNG_DFLT_DRNG_KCAPI ++# depends on RANDOM_DEFAULT_IMPL ++# bool "Kernel Crypto API DRNG" ++# select LRNG_DRNG_KCAPI ++endchoice ++ ++# menuconfig LRNG_TESTING_MENU ++# bool "LRNG testing interfaces" ++# depends on DEBUG_FS ++# help ++# Enable one or more of the following test interfaces. ++# ++# If unsure, say N. ++# ++# if LRNG_TESTING_MENU ++# ++# config LRNG_TESTING ++# bool ++# ++# config LRNG_TESTING_RECORDING ++# bool ++# ++# comment "Interrupt Entropy Source Test Interfaces" ++# ++# config LRNG_RAW_HIRES_ENTROPY ++# bool "Interface to obtain raw unprocessed IRQ noise source data" ++# default y ++# depends on LRNG_IRQ ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned high resolution time stamp noise that ++# is collected by the LRNG for statistical analysis. Extracted ++# noise data is not used to seed the LRNG. ++# ++# The raw noise data can be obtained using the lrng_raw_hires ++# debugfs file. Using the option lrng_testing.boot_raw_hires_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_RAW_JIFFIES_ENTROPY ++# bool "Entropy test interface to Jiffies of IRQ noise source" ++# depends on LRNG_IRQ ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned Jiffies that is collected by ++# the LRNG for statistical analysis. This data is used for ++# seeding the LRNG if a high-resolution time stamp is not ++# available. If a high-resolution time stamp is detected, ++# the Jiffies value is not collected by the LRNG and no ++# data is provided via the test interface. Extracted noise ++# data is not used to seed the random number generator. ++# ++# The raw noise data can be obtained using the lrng_raw_jiffies ++# debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_RAW_IRQ_ENTROPY ++# bool "Entropy test interface to IRQ number noise source" ++# depends on LRNG_IRQ ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned interrupt number that is collected by ++# the LRNG for statistical analysis. Extracted noise data is ++# not used to seed the random number generator. ++# ++# The raw noise data can be obtained using the lrng_raw_irq ++# debugfs file. Using the option lrng_testing.boot_raw_irq_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_RAW_RETIP_ENTROPY ++# bool "Entropy test interface to RETIP value of IRQ noise source" ++# depends on LRNG_IRQ ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned return instruction pointer value ++# that is collected by the LRNG for statistical analysis. ++# Extracted noise data is not used to seed the random number ++# generator. ++# ++# The raw noise data can be obtained using the lrng_raw_retip ++# debugfs file. Using the option lrng_testing.boot_raw_retip_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_RAW_REGS_ENTROPY ++# bool "Entropy test interface to IRQ register value noise source" ++# depends on LRNG_IRQ ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned interrupt register value that is ++# collected by the LRNG for statistical analysis. Extracted noise ++# data is not used to seed the random number generator. ++# ++# The raw noise data can be obtained using the lrng_raw_regs ++# debugfs file. Using the option lrng_testing.boot_raw_regs_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_RAW_ARRAY ++# bool "Test interface to LRNG raw entropy IRQ storage array" ++# depends on LRNG_IRQ ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw noise data that is collected by the LRNG ++# in the per-CPU array for statistical analysis. The purpose ++# of this interface is to verify that the array handling code ++# truly only concatenates data and provides the same entropy ++# rate as the raw unconditioned noise source when assessing ++# the collected data byte-wise. ++# ++# The data can be obtained using the lrng_raw_array debugfs ++# file. Using the option lrng_testing.boot_raw_array=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_IRQ_PERF ++# bool "LRNG interrupt entropy source performance monitor" ++# depends on LRNG_IRQ ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# With this option, the performance monitor of the LRNG ++# interrupt handling code is enabled. The file provides ++# the execution time of the interrupt handler in ++# cycles. ++# ++# The interrupt performance data can be obtained using ++# the lrng_irq_perf debugfs file. Using the option ++# lrng_testing.boot_irq_perf=1 the performance data of ++# the first 1000 entropy events since boot can be sampled. ++# ++# comment "Scheduler Entropy Source Test Interfaces" ++# ++# config LRNG_RAW_SCHED_HIRES_ENTROPY ++# bool "Interface to obtain raw unprocessed scheduler noise source data" ++# depends on LRNG_SCHED ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned high resolution time stamp noise that ++# is collected by the LRNG for the Scheduler-based noise source ++# for statistical analysis. Extracted noise data is not used to ++# seed the LRNG. ++# ++# The raw noise data can be obtained using the lrng_raw_sched_hires ++# debugfs file. Using the option ++# lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the ++# first 1000 entropy events since boot can be sampled. ++# ++# config LRNG_RAW_SCHED_PID_ENTROPY ++# bool "Entropy test interface to PID value" ++# depends on LRNG_SCHED ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned PID value that is collected by the ++# LRNG for statistical analysis. Extracted noise ++# data is not used to seed the random number generator. ++# ++# The raw noise data can be obtained using the ++# lrng_raw_sched_pid debugfs file. Using the option ++# lrng_testing.boot_raw_sched_pid_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_RAW_SCHED_START_TIME_ENTROPY ++# bool "Entropy test interface to task start time value" ++# depends on LRNG_SCHED ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned task start time value that is collected ++# by the LRNG for statistical analysis. Extracted noise ++# data is not used to seed the random number generator. ++# ++# The raw noise data can be obtained using the ++# lrng_raw_sched_starttime debugfs file. Using the option ++# lrng_testing.boot_raw_sched_starttime_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# ++# config LRNG_RAW_SCHED_NVCSW_ENTROPY ++# bool "Entropy test interface to task context switch numbers" ++# depends on LRNG_SCHED ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# The test interface allows a privileged process to capture ++# the raw unconditioned task numbers of context switches that ++# are collected by the LRNG for statistical analysis. Extracted ++# noise data is not used to seed the random number generator. ++# ++# The raw noise data can be obtained using the ++# lrng_raw_sched_nvcsw debugfs file. Using the option ++# lrng_testing.boot_raw_sched_nvcsw_test=1 ++# the raw noise of the first 1000 entropy events since boot ++# can be sampled. ++# ++# config LRNG_SCHED_PERF ++# bool "LRNG scheduler entropy source performance monitor" ++# depends on LRNG_SCHED ++# select LRNG_TESTING ++# select LRNG_TESTING_RECORDING ++# help ++# With this option, the performance monitor of the LRNG ++# scheduler event handling code is enabled. The file provides ++# the execution time of the interrupt handler in cycles. ++# ++# The scheduler performance data can be obtained using ++# the lrng_sched_perf debugfs file. Using the option ++# lrng_testing.boot_sched_perf=1 the performance data of ++# the first 1000 entropy events since boot can be sampled. ++# ++# comment "Auxiliary Test Interfaces" ++# ++# config LRNG_ACVT_HASH ++# bool "Enable LRNG ACVT Hash interface" ++# select LRNG_TESTING ++# help ++# With this option, the LRNG built-in hash function used for ++# auxiliary pool management and prior to switching the ++# cryptographic backends is made available for ACVT. The ++# interface allows writing of the data to be hashed ++# into the interface. The read operation triggers the hash ++# operation to generate message digest. ++# ++# The ACVT interface is available with the lrng_acvt_hash ++# debugfs file. ++# ++# config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG ++# bool "Enable runtime configuration of max reseed threshold" ++# help ++# When enabling this option, the LRNG provides an interface ++# allowing the setting of the maximum number of DRNG generate ++# operations without a reseed that has full entropy. The ++# interface is lrng_drng.max_wo_reseed. ++# ++#config LRNG_RUNTIME_FORCE_SEEDING_DISABLE ++# bool "Enable runtime configuration of force seeding" ++# help ++# When enabling this option, the LRNG provides an interface ++# allowing the disabling of the force seeding when the DRNG ++# is not fully seeded but entropy is available. ++# ++# config LRNG_TEST_CPU_ES_COMPRESSION ++# bool "Force CPU ES compression operation" ++# help ++# When enabling this option, the CPU ES compression operation ++# is forced by setting an arbitrary value > 1 for the data ++# multiplier even when the CPU ES would deliver full entropy. ++# This allows testing of the compression operation. It ++# therefore forces to pull more data from the CPU ES ++# than what may be required. ++# ++# endif #LRNG_TESTING_MENU ++# ++# config LRNG_SELFTEST ++# bool "Enable power-on and on-demand self-tests" ++# help ++# The power-on self-tests are executed during boot time ++# covering the ChaCha20 DRNG, the hash operation used for ++# processing the entropy pools and the auxiliary pool, and ++# the time stamp management of the LRNG. ++# ++# The on-demand self-tests are triggered by writing any ++# value into the SysFS file selftest_status. At the same ++# time, when reading this file, the test status is ++# returned. A zero indicates that all tests were executed ++# successfully. ++# ++# If unsure, say Y. ++# ++# if LRNG_SELFTEST ++# ++# config LRNG_SELFTEST_PANIC ++# bool "Panic the kernel upon self-test failure" ++# help ++# If the option is enabled, the kernel is terminated if an ++# LRNG power-on self-test failure is detected. ++# ++# endif # LRNG_SELFTEST ++ ++endif # LRNG ++ ++endmenu # LRNG +--- /dev/null ++++ b/drivers/char/lrng/Makefile +@@ -0,0 +1,11 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for the Entropy Source and DRNG Manager. ++# ++ ++obj-y += lrng_es_mgr.o lrng_drng_mgr.o \ ++ lrng_es_aux.o ++obj-$(CONFIG_LRNG_SHA256) += lrng_sha256.o ++obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o ++ ++obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_definitions.h +@@ -0,0 +1,163 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022 - 2023, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_DEFINITIONS_H ++#define _LRNG_DEFINITIONS_H ++ ++#include ++#include ++#include ++ ++/*************************** General LRNG parameter ***************************/ ++ ++/* ++ * Specific settings for different use cases ++ */ ++#ifdef CONFIG_CRYPTO_FIPS ++# define LRNG_OVERSAMPLE_ES_BITS 64 ++# define LRNG_SEED_BUFFER_INIT_ADD_BITS 128 ++#else /* CONFIG_CRYPTO_FIPS */ ++# define LRNG_OVERSAMPLE_ES_BITS 0 ++# define LRNG_SEED_BUFFER_INIT_ADD_BITS 0 ++#endif /* CONFIG_CRYPTO_FIPS */ ++ ++/* Security strength of LRNG -- this must match DRNG security strength */ ++#define LRNG_DRNG_SECURITY_STRENGTH_BYTES 32 ++#define LRNG_DRNG_SECURITY_STRENGTH_BITS (LRNG_DRNG_SECURITY_STRENGTH_BYTES * 8) ++#define LRNG_DRNG_INIT_SEED_SIZE_BITS \ ++ (LRNG_DRNG_SECURITY_STRENGTH_BITS + LRNG_SEED_BUFFER_INIT_ADD_BITS) ++#define LRNG_DRNG_INIT_SEED_SIZE_BYTES (LRNG_DRNG_INIT_SEED_SIZE_BITS >> 3) ++ ++/* ++ * SP800-90A defines a maximum request size of 1<<16 bytes. The given value is ++ * considered a safer margin. ++ * ++ * This value is allowed to be changed. ++ */ ++#define LRNG_DRNG_MAX_REQSIZE (1<<12) ++ ++/* ++ * SP800-90A defines a maximum number of requests between reseeds of 2^48. ++ * The given value is considered a much safer margin, balancing requests for ++ * frequent reseeds with the need to conserve entropy. This value MUST NOT be ++ * larger than INT_MAX because it is used in an atomic_t. ++ * ++ * This value is allowed to be changed. ++ */ ++#define LRNG_DRNG_RESEED_THRESH (1<<20) ++ ++/* ++ * Maximum DRNG generation operations without reseed having full entropy ++ * This value defines the absolute maximum value of DRNG generation operations ++ * without a reseed holding full entropy. LRNG_DRNG_RESEED_THRESH is the ++ * threshold when a new reseed is attempted. But it is possible that this fails ++ * to deliver full entropy. In this case the DRNG will continue to provide data ++ * even though it was not reseeded with full entropy. To avoid in the extreme ++ * case that no reseed is performed for too long, this threshold is enforced. ++ * If that absolute low value is reached, the LRNG is marked as not operational. ++ * ++ * This value is allowed to be changed. ++ */ ++#define LRNG_DRNG_MAX_WITHOUT_RESEED (1<<30) ++ ++/* ++ * Min required seed entropy is 128 bits covering the minimum entropy ++ * requirement of SP800-131A and the German BSI's TR02102. ++ * ++ * This value is allowed to be changed. ++ */ ++#define LRNG_FULL_SEED_ENTROPY_BITS LRNG_DRNG_SECURITY_STRENGTH_BITS ++#define LRNG_MIN_SEED_ENTROPY_BITS 128 ++#define LRNG_INIT_ENTROPY_BITS 32 ++ ++/* AIS20/31: NTG.1.4 minimum entropy rate for one entropy source*/ ++#define LRNG_AIS2031_NPTRNG_MIN_ENTROPY 220 ++ ++/* ++ * Wakeup value ++ * ++ * This value is allowed to be changed but must not be larger than the ++ * digest size of the hash operation used update the aux_pool. ++ */ ++#ifdef CONFIG_LRNG_SHA256 ++# define LRNG_ATOMIC_DIGEST_SIZE SHA256_DIGEST_SIZE ++#else ++# define LRNG_ATOMIC_DIGEST_SIZE SHA1_DIGEST_SIZE ++#endif ++#define LRNG_WRITE_WAKEUP_ENTROPY LRNG_ATOMIC_DIGEST_SIZE ++ ++/* ++ * If the switching support is configured, we must provide support up to ++ * the largest digest size. Without switching support, we know it is only ++ * the built-in digest size. ++ */ ++#ifdef CONFIG_LRNG_SWITCH ++# define LRNG_MAX_DIGESTSIZE 64 ++#else ++# define LRNG_MAX_DIGESTSIZE LRNG_ATOMIC_DIGEST_SIZE ++#endif ++ ++/* ++ * Oversampling factor of timer-based events to obtain ++ * LRNG_DRNG_SECURITY_STRENGTH_BYTES. This factor is used when a ++ * high-resolution time stamp is not available. In this case, jiffies and ++ * register contents are used to fill the entropy pool. These noise sources ++ * are much less entropic than the high-resolution timer. The entropy content ++ * is the entropy content assumed with LRNG_[IRQ|SCHED]_ENTROPY_BITS divided by ++ * LRNG_ES_OVERSAMPLING_FACTOR. ++ * ++ * This value is allowed to be changed. ++ */ ++#define LRNG_ES_OVERSAMPLING_FACTOR 10 ++ ++/* Alignmask that is intended to be identical to CRYPTO_MINALIGN */ ++#define LRNG_KCAPI_ALIGN ARCH_KMALLOC_MINALIGN ++ ++/* ++ * This definition must provide a buffer that is equal to SHASH_DESC_ON_STACK ++ * as it will be casted into a struct shash_desc. ++ */ ++#define LRNG_POOL_SIZE (sizeof(struct shash_desc) + HASH_MAX_DESCSIZE) ++ ++/* ++ * Identification of a permanent health falure. ++ * ++ * Allow the given number of back-to-back health failures until incuring a ++ * permanent health failure. The chosen value implies an alpha of 2^-60 ++ * considering that the alpha of one health failure is 2^-30 ++ */ ++#define LRNG_PERMANENT_HEALTH_FAILURES 2 ++ ++/****************************** Helper code ***********************************/ ++ ++static inline u32 lrng_fast_noise_entropylevel(u32 ent_bits, u32 requested_bits) ++{ ++ /* Obtain entropy statement */ ++ ent_bits = ent_bits * requested_bits / LRNG_DRNG_SECURITY_STRENGTH_BITS; ++ /* Cap entropy to buffer size in bits */ ++ ent_bits = min_t(u32, ent_bits, requested_bits); ++ return ent_bits; ++} ++ ++/* Convert entropy in bits into nr. of events with the same entropy content. */ ++static inline u32 lrng_entropy_to_data(u32 entropy_bits, u32 entropy_rate) ++{ ++ return ((entropy_bits * entropy_rate) / ++ LRNG_DRNG_SECURITY_STRENGTH_BITS); ++} ++ ++/* Convert number of events into entropy value. */ ++static inline u32 lrng_data_to_entropy(u32 num, u32 entropy_rate) ++{ ++ return ((num * LRNG_DRNG_SECURITY_STRENGTH_BITS) / ++ entropy_rate); ++} ++ ++static inline u32 atomic_read_u32(atomic_t *v) ++{ ++ return (u32)atomic_read(v); ++} ++ ++#endif /* _LRNG_DEFINITIONS_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_atomic.h +@@ -0,0 +1,23 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_DRNG_ATOMIC_H ++#define _LRNG_DRNG_ATOMIC_H ++ ++#include "lrng_drng_mgr.h" ++ ++#ifdef CONFIG_LRNG_DRNG_ATOMIC ++void lrng_drng_atomic_reset(void); ++void lrng_drng_atomic_seed_drng(struct lrng_drng *drng); ++void lrng_drng_atomic_force_reseed(void); ++struct lrng_drng *lrng_get_atomic(void); ++#else /* CONFIG_LRNG_DRNG_ATOMIC */ ++static inline void lrng_drng_atomic_reset(void) { } ++static inline void lrng_drng_atomic_seed_drng(struct lrng_drng *drng) { } ++static inline void lrng_drng_atomic_force_reseed(void) { } ++static inline struct lrng_drng *lrng_get_atomic(void) { return NULL; } ++#endif /* CONFIG_LRNG_DRNG_ATOMIC */ ++ ++#endif /* _LRNG_DRNG_ATOMIC_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_chacha20.c +@@ -0,0 +1,195 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * Backend for the LRNG providing the cryptographic primitives using ++ * ChaCha20 cipher implementations. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++ ++#include "lrng_drng_chacha20.h" ++ ++/******************************* ChaCha20 DRNG *******************************/ ++ ++#define CHACHA_BLOCK_WORDS (CHACHA_BLOCK_SIZE / sizeof(u32)) ++ ++/* ++ * Update of the ChaCha20 state by either using an unused buffer part or by ++ * generating one ChaCha20 block which is half of the state of the ChaCha20. ++ * The block is XORed into the key part of the state. This shall ensure ++ * backtracking resistance as well as a proper mix of the ChaCha20 state once ++ * the key is injected. ++ */ ++static void lrng_chacha20_update(struct chacha20_state *chacha20_state, ++ __le32 *buf, u32 used_words) ++{ ++ struct chacha20_block *chacha20 = &chacha20_state->block; ++ u32 i; ++ __le32 tmp[CHACHA_BLOCK_WORDS]; ++ ++ BUILD_BUG_ON(sizeof(struct chacha20_block) != CHACHA_BLOCK_SIZE); ++ BUILD_BUG_ON(CHACHA_BLOCK_SIZE != 2 * CHACHA_KEY_SIZE); ++ ++ if (used_words > CHACHA_KEY_SIZE_WORDS) { ++ chacha20_block(&chacha20->constants[0], (u8 *)tmp); ++ for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++) ++ chacha20->key.u[i] ^= le32_to_cpu(tmp[i]); ++ memzero_explicit(tmp, sizeof(tmp)); ++ } else { ++ for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++) ++ chacha20->key.u[i] ^= le32_to_cpu(buf[i + used_words]); ++ } ++ ++ /* Deterministic increment of nonce as required in RFC 7539 chapter 4 */ ++ chacha20->nonce[0]++; ++ if (chacha20->nonce[0] == 0) { ++ chacha20->nonce[1]++; ++ if (chacha20->nonce[1] == 0) ++ chacha20->nonce[2]++; ++ } ++ ++ /* Leave counter untouched as it is start value is undefined in RFC */ ++} ++ ++/* ++ * Seed the ChaCha20 DRNG by injecting the input data into the key part of ++ * the ChaCha20 state. If the input data is longer than the ChaCha20 key size, ++ * perform a ChaCha20 operation after processing of key size input data. ++ * This operation shall spread out the entropy into the ChaCha20 state before ++ * new entropy is injected into the key part. ++ */ ++static int lrng_cc20_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen) ++{ ++ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng; ++ struct chacha20_block *chacha20 = &chacha20_state->block; ++ ++ while (inbuflen) { ++ u32 i, todo = min_t(u32, inbuflen, CHACHA_KEY_SIZE); ++ ++ for (i = 0; i < todo; i++) ++ chacha20->key.b[i] ^= inbuf[i]; ++ ++ /* Break potential dependencies between the inbuf key blocks */ ++ lrng_chacha20_update(chacha20_state, NULL, ++ CHACHA_BLOCK_WORDS); ++ inbuf += todo; ++ inbuflen -= todo; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Chacha20 DRNG generation of random numbers: the stream output of ChaCha20 ++ * is the random number. After the completion of the generation of the ++ * stream, the entire ChaCha20 state is updated. ++ * ++ * Note, as the ChaCha20 implements a 32 bit counter, we must ensure ++ * that this function is only invoked for at most 2^32 - 1 ChaCha20 blocks ++ * before a reseed or an update happens. This is ensured by the variable ++ * outbuflen which is a 32 bit integer defining the number of bytes to be ++ * generated by the ChaCha20 DRNG. At the end of this function, an update ++ * operation is invoked which implies that the 32 bit counter will never be ++ * overflown in this implementation. ++ */ ++static int lrng_cc20_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen) ++{ ++ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng; ++ struct chacha20_block *chacha20 = &chacha20_state->block; ++ __le32 aligned_buf[CHACHA_BLOCK_WORDS]; ++ u32 ret = outbuflen, used = CHACHA_BLOCK_WORDS; ++ int zeroize_buf = 0; ++ ++ while (outbuflen >= CHACHA_BLOCK_SIZE) { ++ chacha20_block(&chacha20->constants[0], outbuf); ++ outbuf += CHACHA_BLOCK_SIZE; ++ outbuflen -= CHACHA_BLOCK_SIZE; ++ } ++ ++ if (outbuflen) { ++ chacha20_block(&chacha20->constants[0], (u8 *)aligned_buf); ++ memcpy(outbuf, aligned_buf, outbuflen); ++ used = ((outbuflen + sizeof(aligned_buf[0]) - 1) / ++ sizeof(aligned_buf[0])); ++ zeroize_buf = 1; ++ } ++ ++ lrng_chacha20_update(chacha20_state, aligned_buf, used); ++ ++ if (zeroize_buf) ++ memzero_explicit(aligned_buf, sizeof(aligned_buf)); ++ ++ return ret; ++} ++ ++/* ++ * Allocation of the DRNG state ++ */ ++static void *lrng_cc20_drng_alloc(u32 sec_strength) ++{ ++ struct chacha20_state *state = NULL; ++ ++ if (sec_strength > CHACHA_KEY_SIZE) { ++ pr_err("Security strength of ChaCha20 DRNG (%u bits) lower than requested by LRNG (%u bits)\n", ++ CHACHA_KEY_SIZE * 8, sec_strength * 8); ++ return ERR_PTR(-EINVAL); ++ } ++ if (sec_strength < CHACHA_KEY_SIZE) ++ pr_warn("Security strength of ChaCha20 DRNG (%u bits) higher than requested by LRNG (%u bits)\n", ++ CHACHA_KEY_SIZE * 8, sec_strength * 8); ++ ++ state = kmalloc(sizeof(struct chacha20_state), GFP_KERNEL); ++ if (!state) ++ return ERR_PTR(-ENOMEM); ++ pr_debug("memory for ChaCha20 core allocated\n"); ++ ++ lrng_cc20_init_rfc7539(&state->block); ++ ++ return state; ++} ++ ++static void lrng_cc20_drng_dealloc(void *drng) ++{ ++ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng; ++ ++ pr_debug("ChaCha20 core zeroized and freed\n"); ++ kfree_sensitive(chacha20_state); ++} ++ ++static const char *lrng_cc20_drng_name(void) ++{ ++ return "ChaCha20 DRNG"; ++} ++ ++const struct lrng_drng_cb lrng_cc20_drng_cb = { ++ .drng_name = lrng_cc20_drng_name, ++ .drng_alloc = lrng_cc20_drng_alloc, ++ .drng_dealloc = lrng_cc20_drng_dealloc, ++ .drng_seed = lrng_cc20_drng_seed_helper, ++ .drng_generate = lrng_cc20_drng_generate_helper, ++}; ++ ++#if !defined(CONFIG_LRNG_DFLT_DRNG_CHACHA20) && \ ++ !defined(CONFIG_LRNG_DRNG_ATOMIC) ++static int __init lrng_cc20_drng_init(void) ++{ ++ return lrng_set_drng_cb(&lrng_cc20_drng_cb); ++} ++ ++static void __exit lrng_cc20_drng_exit(void) ++{ ++ lrng_set_drng_cb(NULL); ++} ++ ++late_initcall(lrng_cc20_drng_init); ++module_exit(lrng_cc20_drng_exit); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Stephan Mueller "); ++MODULE_DESCRIPTION("Entropy Source and DRNG Manager - ChaCha20-based DRNG backend"); ++#endif /* CONFIG_LRNG_DFLT_DRNG_CHACHA20 */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_chacha20.h +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * LRNG ChaCha20 definitions ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_CHACHA20_H ++#define _LRNG_CHACHA20_H ++ ++#include ++ ++/* State according to RFC 7539 section 2.3 */ ++struct chacha20_block { ++ u32 constants[4]; ++ union { ++#define CHACHA_KEY_SIZE_WORDS (CHACHA_KEY_SIZE / sizeof(u32)) ++ u32 u[CHACHA_KEY_SIZE_WORDS]; ++ u8 b[CHACHA_KEY_SIZE]; ++ } key; ++ u32 counter; ++ u32 nonce[3]; ++}; ++ ++struct chacha20_state { ++ struct chacha20_block block; ++}; ++ ++static inline void lrng_cc20_init_rfc7539(struct chacha20_block *chacha20) ++{ ++ chacha_init_consts(chacha20->constants); ++} ++ ++#define LRNG_CC20_INIT_RFC7539(x) \ ++ x.constants[0] = 0x61707865, \ ++ x.constants[1] = 0x3320646e, \ ++ x.constants[2] = 0x79622d32, \ ++ x.constants[3] = 0x6b206574, ++ ++extern const struct lrng_drng_cb lrng_cc20_drng_cb; ++ ++#endif /* _LRNG_CHACHA20_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_drbg.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * LRNG SP800-90A definitions ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_DRBG_H ++#define _LRNG_DRBG_H ++ ++extern const struct lrng_drng_cb lrng_drbg_cb; ++ ++#endif /* _LRNG_DRBG_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_kcapi.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * LRNG kernel crypto API DRNG definition ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_KCAPI_DRNG_H ++#define _LRNG_KCAPI_DRNG_H ++ ++extern const struct lrng_drng_cb lrng_kcapi_drng_cb; ++ ++#endif /* _LRNG_KCAPI_DRNG_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_mgr.c +@@ -0,0 +1,742 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG DRNG management ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_drng_atomic.h" ++#include "lrng_drng_chacha20.h" ++#include "lrng_drng_drbg.h" ++#include "lrng_drng_kcapi.h" ++#include "lrng_drng_mgr.h" ++#include "lrng_es_aux.h" ++#include "lrng_es_mgr.h" ++#include "lrng_interface_random_kernel.h" ++#include "lrng_numa.h" ++#include "lrng_sha.h" ++ ++/* ++ * Maximum number of seconds between DRNG reseed intervals of the DRNG. Note, ++ * this is enforced with the next request of random numbers from the ++ * DRNG. Setting this value to zero implies a reseeding attempt before every ++ * generated random number. ++ */ ++int lrng_drng_reseed_max_time = 600; ++ ++/* ++ * Is LRNG for general-purpose use (i.e. is at least the lrng_drng_init ++ * fully allocated)? ++ */ ++static atomic_t lrng_avail = ATOMIC_INIT(0); ++ ++/* Guard protecting all crypto callback update operation of all DRNGs. */ ++DEFINE_MUTEX(lrng_crypto_cb_update); ++ ++/* ++ * Default hash callback that provides the crypto primitive right from the ++ * kernel start. It must not perform any memory allocation operation, but ++ * simply perform the hash calculation. ++ */ ++const struct lrng_hash_cb *lrng_default_hash_cb = &lrng_sha_hash_cb; ++ ++/* ++ * Default DRNG callback that provides the crypto primitive which is ++ * allocated either during late kernel boot stage. So, it is permissible for ++ * the callback to perform memory allocation operations. ++ */ ++const struct lrng_drng_cb *lrng_default_drng_cb = ++#if defined(CONFIG_LRNG_DFLT_DRNG_CHACHA20) ++ &lrng_cc20_drng_cb; ++#elif defined(CONFIG_LRNG_DFLT_DRNG_DRBG) ++ &lrng_drbg_cb; ++#elif defined(CONFIG_LRNG_DFLT_DRNG_KCAPI) ++ &lrng_kcapi_drng_cb; ++#else ++#error "Unknown default DRNG selected" ++#endif ++ ++/* DRNG for non-atomic use cases */ ++static struct lrng_drng lrng_drng_init = { ++ LRNG_DRNG_STATE_INIT(lrng_drng_init, NULL, NULL, NULL, ++ &lrng_sha_hash_cb), ++ .lock = __MUTEX_INITIALIZER(lrng_drng_init.lock), ++}; ++ ++/* Prediction-resistance DRNG: only deliver as much data as received entropy */ ++static struct lrng_drng lrng_drng_pr = { ++ LRNG_DRNG_STATE_INIT(lrng_drng_pr, NULL, NULL, NULL, ++ &lrng_sha_hash_cb), ++ .lock = __MUTEX_INITIALIZER(lrng_drng_pr.lock), ++}; ++ ++static u32 max_wo_reseed = LRNG_DRNG_MAX_WITHOUT_RESEED; ++#ifdef CONFIG_LRNG_RUNTIME_MAX_WO_RESEED_CONFIG ++module_param(max_wo_reseed, uint, 0444); ++MODULE_PARM_DESC(max_wo_reseed, ++ "Maximum number of DRNG generate operation without full reseed\n"); ++#endif ++ ++static bool force_seeding = true; ++#ifdef CONFIG_LRNG_RUNTIME_FORCE_SEEDING_DISABLE ++module_param(force_seeding, bool, 0444); ++MODULE_PARM_DESC(force_seeding, ++ "Allow disabling of the forced seeding when insufficient entropy is available\n"); ++#endif ++ ++/* Wait queue to wait until the LRNG is initialized - can freely be used */ ++DECLARE_WAIT_QUEUE_HEAD(lrng_init_wait); ++ ++/********************************** Helper ************************************/ ++ ++bool lrng_get_available(void) ++{ ++ return likely(atomic_read(&lrng_avail)); ++} ++ ++struct lrng_drng *lrng_drng_init_instance(void) ++{ ++ return &lrng_drng_init; ++} ++ ++struct lrng_drng *lrng_drng_pr_instance(void) ++{ ++ return &lrng_drng_pr; ++} ++ ++struct lrng_drng *lrng_drng_node_instance(void) ++{ ++ struct lrng_drng **lrng_drng = lrng_drng_instances(); ++ int node = numa_node_id(); ++ ++ if (lrng_drng && lrng_drng[node]) ++ return lrng_drng[node]; ++ ++ return lrng_drng_init_instance(); ++} ++ ++void lrng_drng_reset(struct lrng_drng *drng) ++{ ++ /* Ensure reseed during next call */ ++ atomic_set(&drng->requests, 1); ++ atomic_set(&drng->requests_since_fully_seeded, 0); ++ drng->last_seeded = jiffies; ++ drng->fully_seeded = false; ++ /* Do not set force, as this flag is used for the emergency reseeding */ ++ drng->force_reseed = false; ++ pr_debug("reset DRNG\n"); ++} ++ ++/* Initialize the DRNG, except the mutex lock */ ++int lrng_drng_alloc_common(struct lrng_drng *drng, ++ const struct lrng_drng_cb *drng_cb) ++{ ++ if (!drng || !drng_cb) ++ return -EINVAL; ++ if (!IS_ERR_OR_NULL(drng->drng)) ++ return 0; ++ ++ drng->drng_cb = drng_cb; ++ drng->drng = drng_cb->drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES); ++ if (IS_ERR(drng->drng)) ++ return -PTR_ERR(drng->drng); ++ ++ lrng_drng_reset(drng); ++ return 0; ++} ++ ++/* Initialize the default DRNG during boot and perform its seeding */ ++int lrng_drng_initalize(void) ++{ ++ int ret; ++ ++ if (lrng_get_available()) ++ return 0; ++ ++ /* Catch programming error */ ++ WARN_ON(lrng_drng_init.hash_cb != lrng_default_hash_cb); ++ ++ mutex_lock(&lrng_drng_init.lock); ++ if (lrng_get_available()) { ++ mutex_unlock(&lrng_drng_init.lock); ++ return 0; ++ } ++ ++ /* Initialize the PR DRNG inside init lock as it guards lrng_avail. */ ++ mutex_lock(&lrng_drng_pr.lock); ++ ret = lrng_drng_alloc_common(&lrng_drng_pr, lrng_default_drng_cb); ++ mutex_unlock(&lrng_drng_pr.lock); ++ ++ if (!ret) { ++ ret = lrng_drng_alloc_common(&lrng_drng_init, ++ lrng_default_drng_cb); ++ if (!ret) ++ atomic_set(&lrng_avail, 1); ++ } ++ mutex_unlock(&lrng_drng_init.lock); ++ if (ret) ++ return ret; ++ ++ pr_debug("LRNG for general use is available\n"); ++ ++ /* Seed the DRNG with any entropy available */ ++ if (lrng_pool_trylock()) { ++ pr_info("Initial DRNG initialized triggering first seeding\n"); ++ lrng_drng_seed_work(NULL); ++ } else { ++ pr_info("Initial DRNG initialized without seeding\n"); ++ } ++ ++ return 0; ++} ++ ++static int __init lrng_drng_make_available(void) ++{ ++ return lrng_drng_initalize(); ++} ++late_initcall(lrng_drng_make_available); ++ ++bool lrng_sp80090c_compliant(void) ++{ ++ /* SP800-90C compliant oversampling is only requested in FIPS mode */ ++ return fips_enabled; ++} ++ ++/************************* Random Number Generation ***************************/ ++ ++/* Inject a data buffer into the DRNG - caller must hold its lock */ ++void lrng_drng_inject(struct lrng_drng *drng, const u8 *inbuf, u32 inbuflen, ++ bool fully_seeded, const char *drng_type) ++{ ++ BUILD_BUG_ON(LRNG_DRNG_RESEED_THRESH > INT_MAX); ++ pr_debug("seeding %s DRNG with %u bytes\n", drng_type, inbuflen); ++ if (drng->drng_cb->drng_seed(drng->drng, inbuf, inbuflen) < 0) { ++ pr_warn("seeding of %s DRNG failed\n", drng_type); ++ drng->force_reseed = true; ++ } else { ++ int gc = LRNG_DRNG_RESEED_THRESH - atomic_read(&drng->requests); ++ ++ pr_debug("%s DRNG stats since last seeding: %lu secs; generate calls: %d\n", ++ drng_type, ++ (time_after(jiffies, drng->last_seeded) ? ++ (jiffies - drng->last_seeded) : 0) / HZ, gc); ++ ++ /* Count the numbers of generate ops since last fully seeded */ ++ if (fully_seeded) ++ atomic_set(&drng->requests_since_fully_seeded, 0); ++ else ++ atomic_add(gc, &drng->requests_since_fully_seeded); ++ ++ drng->last_seeded = jiffies; ++ atomic_set(&drng->requests, LRNG_DRNG_RESEED_THRESH); ++ drng->force_reseed = false; ++ ++ if (!drng->fully_seeded) { ++ drng->fully_seeded = fully_seeded; ++ if (drng->fully_seeded) ++ pr_debug("%s DRNG fully seeded\n", drng_type); ++ } ++ } ++} ++ ++/* ++ * Perform the seeding of the DRNG with data from entropy source. ++ * The function returns the entropy injected into the DRNG in bits. ++ */ ++static u32 lrng_drng_seed_es_nolock(struct lrng_drng *drng, bool init_ops, ++ const char *drng_type) ++{ ++ struct entropy_buf seedbuf __aligned(LRNG_KCAPI_ALIGN), ++ collected_seedbuf; ++ u32 collected_entropy = 0; ++ unsigned int i, num_es_delivered = 0; ++ bool forced = drng->force_reseed; ++ ++ for_each_lrng_es(i) ++ collected_seedbuf.e_bits[i] = 0; ++ ++ do { ++ /* Count the number of ES which delivered entropy */ ++ num_es_delivered = 0; ++ ++ if (collected_entropy) ++ pr_debug("Force fully seeding level for %s DRNG by repeatedly pull entropy from available entropy sources\n", ++ drng_type); ++ ++ lrng_fill_seed_buffer(&seedbuf, ++ lrng_get_seed_entropy_osr(drng->fully_seeded), ++ forced && !drng->fully_seeded); ++ ++ collected_entropy += lrng_entropy_rate_eb(&seedbuf); ++ ++ /* Sum iterations up. */ ++ for_each_lrng_es(i) { ++ collected_seedbuf.e_bits[i] += seedbuf.e_bits[i]; ++ num_es_delivered += !!seedbuf.e_bits[i]; ++ } ++ ++ lrng_drng_inject(drng, (u8 *)&seedbuf, sizeof(seedbuf), ++ lrng_fully_seeded(drng->fully_seeded, ++ collected_entropy, ++ &collected_seedbuf), ++ drng_type); ++ ++ /* ++ * Set the seeding state of the LRNG ++ * ++ * Do not call lrng_init_ops(seedbuf) here as the atomic DRNG ++ * does not serve common users. ++ */ ++ if (init_ops) ++ lrng_init_ops(&collected_seedbuf); ++ ++ /* ++ * Emergency reseeding: If we reached the min seed threshold now ++ * multiple times but never reached fully seeded level and we collect ++ * entropy, keep doing it until we reached fully seeded level for ++ * at least one DRNG. This operation is not continued if the ++ * ES do not deliver entropy such that we cannot reach the fully seeded ++ * level. ++ * ++ * The emergency reseeding implies that the consecutively injected ++ * entropy can be added up. This is applicable due to the fact that ++ * the entire operation is atomic which means that the DRNG is not ++ * producing data while this is ongoing. ++ */ ++ } while (force_seeding && forced && !drng->fully_seeded && ++ num_es_delivered >= (lrng_ntg1_2022_compliant() ? 2 : 1)); ++ ++ memzero_explicit(&seedbuf, sizeof(seedbuf)); ++ ++ return collected_entropy; ++} ++ ++static void lrng_drng_seed_es(struct lrng_drng *drng) ++{ ++ mutex_lock(&drng->lock); ++ lrng_drng_seed_es_nolock(drng, true, "regular"); ++ mutex_unlock(&drng->lock); ++} ++ ++static void lrng_drng_seed(struct lrng_drng *drng) ++{ ++ BUILD_BUG_ON(LRNG_MIN_SEED_ENTROPY_BITS > ++ LRNG_DRNG_SECURITY_STRENGTH_BITS); ++ ++ /* (Re-)Seed DRNG */ ++ lrng_drng_seed_es(drng); ++ /* (Re-)Seed atomic DRNG from regular DRNG */ ++ lrng_drng_atomic_seed_drng(drng); ++} ++ ++static void lrng_drng_seed_work_one(struct lrng_drng *drng, u32 node) ++{ ++ pr_debug("reseed triggered by system events for DRNG on NUMA node %d\n", ++ node); ++ lrng_drng_seed(drng); ++ if (drng->fully_seeded) { ++ /* Prevent reseed storm */ ++ drng->last_seeded += node * 100 * HZ; ++ } ++} ++ ++/* ++ * DRNG reseed trigger: Kernel thread handler triggered by the schedule_work() ++ */ ++static void __lrng_drng_seed_work(bool force) ++{ ++ struct lrng_drng **lrng_drng; ++ u32 node; ++ ++ /* ++ * If the DRNG is not yet initialized, let us try to seed the atomic ++ * DRNG. ++ */ ++ if (!lrng_get_available()) { ++ struct lrng_drng *atomic; ++ unsigned long flags; ++ ++ if (wq_has_sleeper(&lrng_init_wait)) { ++ lrng_init_ops(NULL); ++ return; ++ } ++ atomic = lrng_get_atomic(); ++ if (!atomic || atomic->fully_seeded) ++ return; ++ ++ atomic->force_reseed |= force; ++ spin_lock_irqsave(&atomic->spin_lock, flags); ++ lrng_drng_seed_es_nolock(atomic, false, "atomic"); ++ spin_unlock_irqrestore(&atomic->spin_lock, flags); ++ ++ return; ++ } ++ ++ lrng_drng = lrng_drng_instances(); ++ if (lrng_drng) { ++ for_each_online_node(node) { ++ struct lrng_drng *drng = lrng_drng[node]; ++ ++ if (drng && !drng->fully_seeded) { ++ drng->force_reseed |= force; ++ lrng_drng_seed_work_one(drng, node); ++ return; ++ } ++ } ++ } else { ++ if (!lrng_drng_init.fully_seeded) { ++ lrng_drng_init.force_reseed |= force; ++ lrng_drng_seed_work_one(&lrng_drng_init, 0); ++ return; ++ } ++ } ++ ++ if (!lrng_drng_pr.fully_seeded) { ++ lrng_drng_pr.force_reseed |= force; ++ lrng_drng_seed_work_one(&lrng_drng_pr, 0); ++ return; ++ } ++ ++ lrng_pool_all_numa_nodes_seeded(true); ++} ++ ++void lrng_drng_seed_work(struct work_struct *dummy) ++{ ++ __lrng_drng_seed_work(false); ++ ++ /* Allow the seeding operation to be called again */ ++ lrng_pool_unlock(); ++} ++ ++/* Force all DRNGs to reseed before next generation */ ++void lrng_drng_force_reseed(void) ++{ ++ struct lrng_drng **lrng_drng = lrng_drng_instances(); ++ u32 node; ++ ++ /* ++ * If the initial DRNG is over the reseed threshold, allow a forced ++ * reseed only for the initial DRNG as this is the fallback for all. It ++ * must be kept seeded before all others to keep the LRNG operational. ++ */ ++ if (!lrng_drng || ++ (atomic_read_u32(&lrng_drng_init.requests_since_fully_seeded) > ++ LRNG_DRNG_RESEED_THRESH)) { ++ lrng_drng_init.force_reseed = lrng_drng_init.fully_seeded; ++ pr_debug("force reseed of initial DRNG\n"); ++ return; ++ } ++ for_each_online_node(node) { ++ struct lrng_drng *drng = lrng_drng[node]; ++ ++ if (!drng) ++ continue; ++ ++ drng->force_reseed = drng->fully_seeded; ++ pr_debug("force reseed of DRNG on node %u\n", node); ++ } ++ lrng_drng_atomic_force_reseed(); ++} ++EXPORT_SYMBOL(lrng_drng_force_reseed); ++ ++static bool lrng_drng_must_reseed(struct lrng_drng *drng) ++{ ++ return (atomic_dec_and_test(&drng->requests) || ++ drng->force_reseed || ++ time_after(jiffies, ++ drng->last_seeded + lrng_drng_reseed_max_time * HZ)); ++} ++ ++/* ++ * lrng_drng_get() - Get random data out of the DRNG which is reseeded ++ * frequently. ++ * ++ * @drng: DRNG instance ++ * @outbuf: buffer for storing random data ++ * @outbuflen: length of outbuf ++ * ++ * Return: ++ * * < 0 in error case (DRNG generation or update failed) ++ * * >=0 returning the returned number of bytes ++ */ ++int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen) ++{ ++ u32 processed = 0; ++ bool pr = (drng == &lrng_drng_pr) ? true : false; ++ ++ if (!outbuf || !outbuflen) ++ return 0; ++ ++ if (!lrng_get_available()) ++ return -EOPNOTSUPP; ++ ++ outbuflen = min_t(size_t, outbuflen, INT_MAX); ++ ++ /* If DRNG operated without proper reseed for too long, block LRNG */ ++ BUILD_BUG_ON(LRNG_DRNG_MAX_WITHOUT_RESEED < LRNG_DRNG_RESEED_THRESH); ++ if (atomic_read_u32(&drng->requests_since_fully_seeded) > max_wo_reseed) ++ lrng_unset_fully_seeded(drng); ++ ++ while (outbuflen) { ++ u32 todo = min_t(u32, outbuflen, LRNG_DRNG_MAX_REQSIZE); ++ int ret; ++ ++ /* In normal operation, check whether to reseed */ ++ if (!pr && lrng_drng_must_reseed(drng)) { ++ if (!lrng_pool_trylock()) { ++ drng->force_reseed = true; ++ } else { ++ lrng_drng_seed(drng); ++ lrng_pool_unlock(); ++ } ++ } ++ ++ mutex_lock(&drng->lock); ++ ++ if (pr) { ++ /* If async reseed did not deliver entropy, try now */ ++ if (!drng->fully_seeded) { ++ u32 coll_ent_bits; ++ ++ /* If we cannot get the pool lock, try again. */ ++ if (!lrng_pool_trylock()) { ++ mutex_unlock(&drng->lock); ++ continue; ++ } ++ ++ coll_ent_bits = lrng_drng_seed_es_nolock( ++ drng, true, "regular"); ++ ++ lrng_pool_unlock(); ++ ++ /* If no new entropy was received, stop now. */ ++ if (!coll_ent_bits) { ++ mutex_unlock(&drng->lock); ++ goto out; ++ } ++ ++ /* Produce no more data than received entropy */ ++ todo = min_t(u32, todo, coll_ent_bits >> 3); ++ } ++ ++ /* Do not produce more than DRNG security strength */ ++ todo = min_t(u32, todo, lrng_security_strength() >> 3); ++ } ++ ret = drng->drng_cb->drng_generate(drng->drng, ++ outbuf + processed, todo); ++ ++ mutex_unlock(&drng->lock); ++ if (ret <= 0) { ++ pr_warn("getting random data from DRNG failed (%d)\n", ++ ret); ++ return -EFAULT; ++ } ++ processed += ret; ++ outbuflen -= ret; ++ ++ if (pr) { ++ /* Force the async reseed for PR DRNG */ ++ lrng_unset_fully_seeded(drng); ++ if (outbuflen) ++ cond_resched(); ++ } ++ } ++ ++out: ++ return processed; ++} ++ ++int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen, bool pr) ++{ ++ struct lrng_drng **lrng_drng = lrng_drng_instances(); ++ struct lrng_drng *drng = &lrng_drng_init; ++ int ret, node = numa_node_id(); ++ ++ might_sleep(); ++ ++ if (pr) ++ drng = &lrng_drng_pr; ++ else if (lrng_drng && lrng_drng[node] && lrng_drng[node]->fully_seeded) ++ drng = lrng_drng[node]; ++ ++ ret = lrng_drng_initalize(); ++ if (ret) ++ return ret; ++ ++ return lrng_drng_get(drng, outbuf, outbuflen); ++} ++ ++/* Reset LRNG such that all existing entropy is gone */ ++static void _lrng_reset(struct work_struct *work) ++{ ++ struct lrng_drng **lrng_drng = lrng_drng_instances(); ++ ++ if (!lrng_drng) { ++ mutex_lock(&lrng_drng_init.lock); ++ lrng_drng_reset(&lrng_drng_init); ++ mutex_unlock(&lrng_drng_init.lock); ++ } else { ++ u32 node; ++ ++ for_each_online_node(node) { ++ struct lrng_drng *drng = lrng_drng[node]; ++ ++ if (!drng) ++ continue; ++ mutex_lock(&drng->lock); ++ lrng_drng_reset(drng); ++ mutex_unlock(&drng->lock); ++ } ++ } ++ ++ mutex_lock(&lrng_drng_pr.lock); ++ lrng_drng_reset(&lrng_drng_pr); ++ mutex_unlock(&lrng_drng_pr.lock); ++ ++ lrng_drng_atomic_reset(); ++ lrng_set_entropy_thresh(LRNG_INIT_ENTROPY_BITS); ++ ++ lrng_reset_state(); ++} ++ ++static DECLARE_WORK(lrng_reset_work, _lrng_reset); ++ ++void lrng_reset(void) ++{ ++ schedule_work(&lrng_reset_work); ++} ++ ++/******************* Generic LRNG kernel output interfaces ********************/ ++ ++void lrng_force_fully_seeded(void) ++{ ++ if (lrng_pool_all_numa_nodes_seeded_get()) ++ return; ++ ++ lrng_pool_lock(); ++ __lrng_drng_seed_work(true); ++ lrng_pool_unlock(); ++} ++ ++static int lrng_drng_sleep_while_not_all_nodes_seeded(unsigned int nonblock) ++{ ++ lrng_force_fully_seeded(); ++ if (lrng_pool_all_numa_nodes_seeded_get()) ++ return 0; ++ if (nonblock) ++ return -EAGAIN; ++ wait_event_interruptible(lrng_init_wait, ++ lrng_pool_all_numa_nodes_seeded_get()); ++ return 0; ++} ++ ++int lrng_drng_sleep_while_nonoperational(int nonblock) ++{ ++ lrng_force_fully_seeded(); ++ if (likely(lrng_state_operational())) ++ return 0; ++ if (nonblock) ++ return -EAGAIN; ++ return wait_event_interruptible(lrng_init_wait, ++ lrng_state_operational()); ++} ++ ++int lrng_drng_sleep_while_non_min_seeded(void) ++{ ++ lrng_force_fully_seeded(); ++ if (likely(lrng_state_min_seeded())) ++ return 0; ++ return wait_event_interruptible(lrng_init_wait, ++ lrng_state_min_seeded()); ++} ++ ++ssize_t lrng_get_seed(u64 *buf, size_t nbytes, unsigned int flags) ++{ ++ struct entropy_buf *eb = (struct entropy_buf *)(buf + 2); ++ u64 buflen = sizeof(struct entropy_buf) + 2 * sizeof(u64); ++ u64 collected_bits = 0; ++ int ret; ++ ++ /* Ensure buffer is aligned as required */ ++ BUILD_BUG_ON(sizeof(buflen) > LRNG_KCAPI_ALIGN); ++ if (nbytes < sizeof(buflen)) ++ return -EINVAL; ++ ++ /* Write buffer size into first word */ ++ buf[0] = buflen; ++ if (nbytes < buflen) ++ return -EMSGSIZE; ++ ++ ret = lrng_drng_sleep_while_not_all_nodes_seeded( ++ flags & LRNG_GET_SEED_NONBLOCK); ++ if (ret) ++ return ret; ++ ++ /* Try to get the pool lock and sleep on it to get it. */ ++ lrng_pool_lock(); ++ ++ /* If an LRNG DRNG becomes unseeded, give this DRNG precedence. */ ++ if (!lrng_pool_all_numa_nodes_seeded_get()) { ++ lrng_pool_unlock(); ++ return 0; ++ } ++ ++ /* ++ * Try to get seed data - a rarely used busyloop is cheaper than a wait ++ * queue that is constantly woken up by the hot code path of ++ * lrng_init_ops. ++ */ ++ for (;;) { ++ lrng_fill_seed_buffer(eb, ++ lrng_get_seed_entropy_osr(flags & ++ LRNG_GET_SEED_FULLY_SEEDED), ++ false); ++ collected_bits = lrng_entropy_rate_eb(eb); ++ ++ /* Break the collection loop if we got entropy, ... */ ++ if (collected_bits || ++ /* ... a DRNG becomes unseeded, give DRNG precedence, ... */ ++ !lrng_pool_all_numa_nodes_seeded_get() || ++ /* ... if the caller does not want a blocking behavior. */ ++ (flags & LRNG_GET_SEED_NONBLOCK)) ++ break; ++ ++ schedule(); ++ } ++ ++ lrng_pool_unlock(); ++ ++ /* Write collected entropy size into second word */ ++ buf[1] = collected_bits; ++ ++ return (ssize_t)buflen; ++} ++ ++void lrng_get_random_bytes_full(void *buf, int nbytes) ++{ ++ lrng_drng_sleep_while_nonoperational(0); ++ lrng_drng_get_sleep((u8 *)buf, (u32)nbytes, false); ++} ++EXPORT_SYMBOL(lrng_get_random_bytes_full); ++ ++void lrng_get_random_bytes_min(void *buf, int nbytes) ++{ ++ lrng_drng_sleep_while_non_min_seeded(); ++ lrng_drng_get_sleep((u8 *)buf, (u32)nbytes, false); ++} ++EXPORT_SYMBOL(lrng_get_random_bytes_min); ++ ++int lrng_get_random_bytes_pr(void *buf, int nbytes) ++{ ++ lrng_drng_sleep_while_nonoperational(0); ++ return lrng_drng_get_sleep((u8 *)buf, (u32)nbytes, true); ++} ++EXPORT_SYMBOL(lrng_get_random_bytes_pr); +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_mgr.h +@@ -0,0 +1,86 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_DRNG_H ++#define _LRNG_DRNG_H ++ ++#include ++#include ++#include ++ ++#include "lrng_definitions.h" ++ ++extern struct wait_queue_head lrng_init_wait; ++extern int lrng_drng_reseed_max_time; ++extern struct mutex lrng_crypto_cb_update; ++extern const struct lrng_drng_cb *lrng_default_drng_cb; ++extern const struct lrng_hash_cb *lrng_default_hash_cb; ++ ++/* DRNG state handle */ ++struct lrng_drng { ++ void *drng; /* DRNG handle */ ++ void *hash; /* Hash handle */ ++ const struct lrng_drng_cb *drng_cb; /* DRNG callbacks */ ++ const struct lrng_hash_cb *hash_cb; /* Hash callbacks */ ++ atomic_t requests; /* Number of DRNG requests */ ++ atomic_t requests_since_fully_seeded; /* Number DRNG requests since ++ * last fully seeded ++ */ ++ unsigned long last_seeded; /* Last time it was seeded */ ++ bool fully_seeded; /* Is DRNG fully seeded? */ ++ bool force_reseed; /* Force a reseed */ ++ ++ rwlock_t hash_lock; /* Lock hash_cb replacement */ ++ /* Lock write operations on DRNG state, DRNG replacement of drng_cb */ ++ struct mutex lock; /* Non-atomic DRNG operation */ ++ spinlock_t spin_lock; /* Atomic DRNG operation */ ++}; ++ ++#define LRNG_DRNG_STATE_INIT(x, d, h, d_cb, h_cb) \ ++ .drng = d, \ ++ .hash = h, \ ++ .drng_cb = d_cb, \ ++ .hash_cb = h_cb, \ ++ .requests = ATOMIC_INIT(LRNG_DRNG_RESEED_THRESH),\ ++ .requests_since_fully_seeded = ATOMIC_INIT(0), \ ++ .last_seeded = 0, \ ++ .fully_seeded = false, \ ++ .force_reseed = true, \ ++ .hash_lock = __RW_LOCK_UNLOCKED(x.hash_lock) ++ ++struct lrng_drng *lrng_drng_init_instance(void); ++struct lrng_drng *lrng_drng_pr_instance(void); ++struct lrng_drng *lrng_drng_node_instance(void); ++ ++void lrng_reset(void); ++int lrng_drng_alloc_common(struct lrng_drng *drng, ++ const struct lrng_drng_cb *crypto_cb); ++int lrng_drng_initalize(void); ++bool lrng_sp80090c_compliant(void); ++bool lrng_get_available(void); ++void lrng_drng_reset(struct lrng_drng *drng); ++void lrng_drng_inject(struct lrng_drng *drng, const u8 *inbuf, u32 inbuflen, ++ bool fully_seeded, const char *drng_type); ++int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen); ++int lrng_drng_sleep_while_nonoperational(int nonblock); ++int lrng_drng_sleep_while_non_min_seeded(void); ++int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen, bool pr); ++void lrng_drng_seed_work(struct work_struct *dummy); ++void lrng_drng_force_reseed(void); ++void lrng_force_fully_seeded(void); ++ ++static inline u32 lrng_compress_osr(void) ++{ ++ return lrng_sp80090c_compliant() ? LRNG_OVERSAMPLE_ES_BITS : 0; ++} ++ ++static inline u32 lrng_reduce_by_osr(u32 entropy_bits) ++{ ++ u32 osr_bits = lrng_compress_osr(); ++ ++ return (entropy_bits >= osr_bits) ? (entropy_bits - osr_bits) : 0; ++} ++ ++#endif /* _LRNG_DRNG_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_aux.c +@@ -0,0 +1,335 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Slow Entropy Source: Auxiliary entropy pool ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++ ++#include "lrng_es_aux.h" ++#include "lrng_es_mgr.h" ++#include "lrng_sysctl.h" ++ ++/* ++ * This is the auxiliary pool ++ * ++ * The aux pool array is aligned to 8 bytes to comfort the kernel crypto API ++ * cipher implementations of the hash functions used to read the pool: for some ++ * accelerated implementations, we need an alignment to avoid a realignment ++ * which involves memcpy(). The alignment to 8 bytes should satisfy all crypto ++ * implementations. ++ */ ++struct lrng_pool { ++ u8 aux_pool[LRNG_POOL_SIZE]; /* Aux pool: digest state */ ++ atomic_t aux_entropy_bits; ++ atomic_t digestsize; /* Digest size of used hash */ ++ bool initialized; /* Aux pool initialized? */ ++ ++ /* Serialize read of entropy pool and update of aux pool */ ++ spinlock_t lock; ++}; ++ ++static struct lrng_pool lrng_pool __aligned(LRNG_KCAPI_ALIGN) = { ++ .aux_entropy_bits = ATOMIC_INIT(0), ++ .digestsize = ATOMIC_INIT(LRNG_ATOMIC_DIGEST_SIZE), ++ .initialized = false, ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_pool.lock) ++}; ++ ++/********************************** Helper ***********************************/ ++ ++/* Entropy in bits present in aux pool */ ++static u32 lrng_aux_avail_entropy(u32 __unused) ++{ ++ /* Cap available entropy with max entropy */ ++ u32 avail_bits = min_t(u32, lrng_get_digestsize(), ++ atomic_read_u32(&lrng_pool.aux_entropy_bits)); ++ ++ /* Consider oversampling rate due to aux pool conditioning */ ++ return lrng_reduce_by_osr(avail_bits); ++} ++ ++/* Set the digest size of the used hash in bytes */ ++static void lrng_set_digestsize(u32 digestsize) ++{ ++ struct lrng_pool *pool = &lrng_pool; ++ u32 ent_bits = atomic_xchg_relaxed(&pool->aux_entropy_bits, 0), ++ old_digestsize = lrng_get_digestsize(); ++ ++ atomic_set(&lrng_pool.digestsize, digestsize); ++ ++ /* ++ * Update the write wakeup threshold which must not be larger ++ * than the digest size of the current conditioning hash. ++ */ ++ digestsize = lrng_reduce_by_osr(digestsize << 3); ++ lrng_sysctl_update_max_write_thresh(digestsize); ++ lrng_write_wakeup_bits = digestsize; ++ ++ /* ++ * In case the new digest is larger than the old one, cap the available ++ * entropy to the old message digest used to process the existing data. ++ */ ++ ent_bits = min_t(u32, ent_bits, old_digestsize); ++ atomic_add(ent_bits, &pool->aux_entropy_bits); ++} ++ ++static int __init lrng_init_wakeup_bits(void) ++{ ++ u32 digestsize = lrng_reduce_by_osr(lrng_get_digestsize()); ++ ++ lrng_sysctl_update_max_write_thresh(digestsize); ++ lrng_write_wakeup_bits = digestsize; ++ return 0; ++} ++core_initcall(lrng_init_wakeup_bits); ++ ++/* Obtain the digest size provided by the used hash in bits */ ++u32 lrng_get_digestsize(void) ++{ ++ return atomic_read_u32(&lrng_pool.digestsize) << 3; ++} ++ ++/* Set entropy content in user-space controllable aux pool */ ++void lrng_pool_set_entropy(u32 entropy_bits) ++{ ++ atomic_set(&lrng_pool.aux_entropy_bits, entropy_bits); ++} ++ ++static void lrng_aux_reset(void) ++{ ++ lrng_pool_set_entropy(0); ++} ++ ++/* ++ * Replace old with new hash for auxiliary pool handling ++ * ++ * Assumption: the caller must guarantee that the new_cb is available during the ++ * entire operation (e.g. it must hold the write lock against pointer updating). ++ */ ++static int ++lrng_aux_switch_hash(struct lrng_drng *drng, int __unused, ++ const struct lrng_hash_cb *new_cb, void *new_hash, ++ const struct lrng_hash_cb *old_cb) ++{ ++ struct lrng_drng *init_drng = lrng_drng_init_instance(); ++ struct lrng_pool *pool = &lrng_pool; ++ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; ++ u8 digest[LRNG_MAX_DIGESTSIZE]; ++ int ret; ++ ++ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) ++ return -EOPNOTSUPP; ++ ++ if (unlikely(!pool->initialized)) ++ return 0; ++ ++ /* We only switch if the processed DRNG is the initial DRNG. */ ++ if (init_drng != drng) ++ return 0; ++ ++ /* Get the aux pool hash with old digest ... */ ++ ret = old_cb->hash_final(shash, digest) ?: ++ /* ... re-initialize the hash with the new digest ... */ ++ new_cb->hash_init(shash, new_hash) ?: ++ /* ++ * ... feed the old hash into the new state. We may feed ++ * uninitialized memory into the new state, but this is ++ * considered no issue and even good as we have some more ++ * uncertainty here. ++ */ ++ new_cb->hash_update(shash, digest, sizeof(digest)); ++ if (!ret) { ++ lrng_set_digestsize(new_cb->hash_digestsize(new_hash)); ++ pr_debug("Re-initialize aux entropy pool with hash %s\n", ++ new_cb->hash_name()); ++ } ++ ++ memzero_explicit(digest, sizeof(digest)); ++ return ret; ++} ++ ++/* Insert data into auxiliary pool by using the hash update function. */ ++static int ++lrng_aux_pool_insert_locked(const u8 *inbuf, u32 inbuflen, u32 entropy_bits) ++{ ++ struct lrng_pool *pool = &lrng_pool; ++ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; ++ struct lrng_drng *drng = lrng_drng_init_instance(); ++ const struct lrng_hash_cb *hash_cb; ++ unsigned long flags; ++ void *hash; ++ int ret; ++ ++ entropy_bits = min_t(u32, entropy_bits, inbuflen << 3); ++ ++ read_lock_irqsave(&drng->hash_lock, flags); ++ hash_cb = drng->hash_cb; ++ hash = drng->hash; ++ ++ if (unlikely(!pool->initialized)) { ++ ret = hash_cb->hash_init(shash, hash); ++ if (ret) ++ goto out; ++ pool->initialized = true; ++ } ++ ++ ret = hash_cb->hash_update(shash, inbuf, inbuflen); ++ if (ret) ++ goto out; ++ ++ /* ++ * Cap the available entropy to the hash output size compliant to ++ * SP800-90B section 3.1.5.1 table 1. ++ */ ++ entropy_bits += atomic_read_u32(&pool->aux_entropy_bits); ++ atomic_set(&pool->aux_entropy_bits, ++ min_t(u32, entropy_bits, ++ hash_cb->hash_digestsize(hash) << 3)); ++ ++out: ++ read_unlock_irqrestore(&drng->hash_lock, flags); ++ return ret; ++} ++ ++int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits) ++{ ++ struct lrng_pool *pool = &lrng_pool; ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&pool->lock, flags); ++ ret = lrng_aux_pool_insert_locked(inbuf, inbuflen, entropy_bits); ++ spin_unlock_irqrestore(&pool->lock, flags); ++ ++ lrng_es_add_entropy(); ++ ++ return ret; ++} ++EXPORT_SYMBOL(lrng_pool_insert_aux); ++ ++/************************* Get data from entropy pool *************************/ ++ ++/* ++ * Get auxiliary entropy pool and its entropy content for seed buffer. ++ * Caller must hold lrng_pool.pool->lock. ++ * @outbuf: buffer to store data in with size requested_bits ++ * @requested_bits: Requested amount of entropy ++ * @return: amount of entropy in outbuf in bits. ++ */ ++static u32 lrng_aux_get_pool(u8 *outbuf, u32 requested_bits) ++{ ++ struct lrng_pool *pool = &lrng_pool; ++ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; ++ struct lrng_drng *drng = lrng_drng_init_instance(); ++ const struct lrng_hash_cb *hash_cb; ++ unsigned long flags; ++ void *hash; ++ u32 collected_ent_bits, returned_ent_bits, unused_bits = 0, ++ digestsize, digestsize_bits, requested_bits_osr; ++ u8 aux_output[LRNG_MAX_DIGESTSIZE]; ++ ++ if (unlikely(!pool->initialized)) ++ return 0; ++ ++ read_lock_irqsave(&drng->hash_lock, flags); ++ ++ hash_cb = drng->hash_cb; ++ hash = drng->hash; ++ digestsize = hash_cb->hash_digestsize(hash); ++ digestsize_bits = digestsize << 3; ++ ++ /* Cap to maximum entropy that can ever be generated with given hash */ ++ lrng_cap_requested(digestsize_bits, requested_bits); ++ ++ /* Ensure that no more than the size of aux_pool can be requested */ ++ requested_bits = min_t(u32, requested_bits, (LRNG_MAX_DIGESTSIZE << 3)); ++ requested_bits_osr = requested_bits + lrng_compress_osr(); ++ ++ /* Cap entropy with entropy counter from aux pool and the used digest */ ++ collected_ent_bits = min_t(u32, digestsize_bits, ++ atomic_xchg_relaxed(&pool->aux_entropy_bits, 0)); ++ ++ /* We collected too much entropy and put the overflow back */ ++ if (collected_ent_bits > requested_bits_osr) { ++ /* Amount of bits we collected too much */ ++ unused_bits = collected_ent_bits - requested_bits_osr; ++ /* Put entropy back */ ++ atomic_add(unused_bits, &pool->aux_entropy_bits); ++ /* Fix collected entropy */ ++ collected_ent_bits = requested_bits_osr; ++ } ++ ++ /* Apply oversampling: discount requested oversampling rate */ ++ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits); ++ ++ pr_debug("obtained %u bits by collecting %u bits of entropy from aux pool, %u bits of entropy remaining\n", ++ returned_ent_bits, collected_ent_bits, unused_bits); ++ ++ /* Get the digest for the aux pool to be returned to the caller ... */ ++ if (hash_cb->hash_final(shash, aux_output) || ++ /* ++ * ... and re-initialize the aux state. Do not add the aux pool ++ * digest for backward secrecy as it will be added with the ++ * insertion of the complete seed buffer after it has been filled. ++ */ ++ hash_cb->hash_init(shash, hash)) { ++ returned_ent_bits = 0; ++ } else { ++ /* ++ * Do not truncate the output size exactly to collected_ent_bits ++ * as the aux pool may contain data that is not credited with ++ * entropy, but we want to use them to stir the DRNG state. ++ */ ++ memcpy(outbuf, aux_output, requested_bits >> 3); ++ } ++ ++ read_unlock_irqrestore(&drng->hash_lock, flags); ++ memzero_explicit(aux_output, digestsize); ++ return returned_ent_bits; ++} ++ ++static void lrng_aux_get_backtrack(struct entropy_buf *eb, u32 requested_bits, ++ bool __unused) ++{ ++ struct lrng_pool *pool = &lrng_pool; ++ unsigned long flags; ++ ++ /* Ensure aux pool extraction and backtracking op are atomic */ ++ spin_lock_irqsave(&pool->lock, flags); ++ ++ eb->e_bits[lrng_ext_es_aux] = lrng_aux_get_pool(eb->e[lrng_ext_es_aux], ++ requested_bits); ++ ++ /* Mix the extracted data back into pool for backtracking resistance */ ++ if (lrng_aux_pool_insert_locked((u8 *)eb, ++ sizeof(struct entropy_buf), 0)) ++ pr_warn("Backtracking resistance operation failed\n"); ++ ++ spin_unlock_irqrestore(&pool->lock, flags); ++} ++ ++static void lrng_aux_es_state(unsigned char *buf, size_t buflen) ++{ ++ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ ++ /* Assume the lrng_drng_init lock is taken by caller */ ++ snprintf(buf, buflen, ++ " Hash for operating entropy pool: %s\n" ++ " Available entropy: %u\n", ++ lrng_drng_init->hash_cb->hash_name(), ++ lrng_aux_avail_entropy(0)); ++} ++ ++struct lrng_es_cb lrng_es_aux = { ++ .name = "Auxiliary", ++ .get_ent = lrng_aux_get_backtrack, ++ .curr_entropy = lrng_aux_avail_entropy, ++ .max_entropy = lrng_get_digestsize, ++ .state = lrng_aux_es_state, ++ .reset = lrng_aux_reset, ++ .switch_hash = lrng_aux_switch_hash, ++}; +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_aux.h +@@ -0,0 +1,44 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_AUX_H ++#define _LRNG_ES_AUX_H ++ ++#include "lrng_drng_mgr.h" ++#include "lrng_es_mgr_cb.h" ++ ++u32 lrng_get_digestsize(void); ++void lrng_pool_set_entropy(u32 entropy_bits); ++int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits); ++ ++extern struct lrng_es_cb lrng_es_aux; ++ ++/****************************** Helper code ***********************************/ ++ ++/* Obtain the security strength of the LRNG in bits */ ++static inline u32 lrng_security_strength(void) ++{ ++ /* ++ * We use a hash to read the entropy in the entropy pool. According to ++ * SP800-90B table 1, the entropy can be at most the digest size. ++ * Considering this together with the last sentence in section 3.1.5.1.2 ++ * the security strength of a (approved) hash is equal to its output ++ * size. On the other hand the entropy cannot be larger than the ++ * security strength of the used DRBG. ++ */ ++ return min_t(u32, LRNG_FULL_SEED_ENTROPY_BITS, lrng_get_digestsize()); ++} ++ ++static inline u32 lrng_get_seed_entropy_osr(bool fully_seeded) ++{ ++ u32 requested_bits = lrng_security_strength(); ++ ++ /* Apply oversampling during initialization according to SP800-90C */ ++ if (lrng_sp80090c_compliant() && !fully_seeded) ++ requested_bits += LRNG_SEED_BUFFER_INIT_ADD_BITS; ++ return requested_bits; ++} ++ ++#endif /* _LRNG_ES_AUX_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_cpu.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_CPU_H ++#define _LRNG_ES_CPU_H ++ ++#include "lrng_es_mgr_cb.h" ++ ++#ifdef CONFIG_LRNG_CPU ++ ++extern struct lrng_es_cb lrng_es_cpu; ++ ++#endif /* CONFIG_LRNG_CPU */ ++ ++#endif /* _LRNG_ES_CPU_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_irq.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_IRQ_H ++#define _LRNG_ES_IRQ_H ++ ++#include ++ ++#include "lrng_es_mgr_cb.h" ++ ++#ifdef CONFIG_LRNG_IRQ ++void lrng_irq_es_init(bool highres_timer); ++void lrng_irq_array_add_u32(u32 data); ++ ++extern struct lrng_es_cb lrng_es_irq; ++ ++#else /* CONFIG_LRNG_IRQ */ ++static inline void lrng_irq_es_init(bool highres_timer) { } ++static inline void lrng_irq_array_add_u32(u32 data) { } ++#endif /* CONFIG_LRNG_IRQ */ ++ ++#endif /* _LRNG_ES_IRQ_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_jent.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_JENT_H ++#define _LRNG_ES_JENT_H ++ ++#include "lrng_es_mgr_cb.h" ++ ++#ifdef CONFIG_LRNG_JENT ++ ++extern struct lrng_es_cb lrng_es_jent; ++ ++#endif /* CONFIG_LRNG_JENT */ ++ ++#endif /* _LRNG_ES_JENT_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_krng.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_RANDOM_H ++#define _LRNG_ES_RANDOM_H ++ ++#include "lrng_es_mgr_cb.h" ++ ++#ifdef CONFIG_LRNG_KERNEL_RNG ++ ++extern struct lrng_es_cb lrng_es_krng; ++ ++#endif /* CONFIG_LRNG_KERNEL_RNG */ ++ ++#endif /* _LRNG_ES_RANDOM_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_mgr.c +@@ -0,0 +1,506 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Entropy sources management ++ * ++ * Copyright (C) 2022 - 2023, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_drng_atomic.h" ++#include "lrng_drng_mgr.h" ++#include "lrng_es_aux.h" ++#include "lrng_es_cpu.h" ++#include "lrng_es_irq.h" ++#include "lrng_es_jent.h" ++#include "lrng_es_krng.h" ++#include "lrng_es_mgr.h" ++#include "lrng_es_sched.h" ++#include "lrng_interface_dev_common.h" ++#include "lrng_interface_random_kernel.h" ++ ++struct lrng_state { ++ bool can_invalidate; /* Can invalidate batched entropy? */ ++ bool perform_seedwork; /* Can seed work be performed? */ ++ bool lrng_operational; /* Is DRNG operational? */ ++ bool lrng_fully_seeded; /* Is DRNG fully seeded? */ ++ bool lrng_min_seeded; /* Is DRNG minimally seeded? */ ++ bool all_online_numa_node_seeded;/* All NUMA DRNGs seeded? */ ++ ++ /* ++ * To ensure that external entropy providers cannot dominate the ++ * internal noise sources but yet cannot be dominated by internal ++ * noise sources, the following booleans are intended to allow ++ * external to provide seed once when a DRNG reseed occurs. This ++ * triggering of external noise source is performed even when the ++ * entropy pool has sufficient entropy. ++ */ ++ ++ atomic_t boot_entropy_thresh; /* Reseed threshold */ ++ struct mutex reseed_in_progress; /* Flag for on executing reseed */ ++ struct work_struct lrng_seed_work; /* (re)seed work queue */ ++}; ++ ++static struct lrng_state lrng_state = { ++ false, false, false, false, false, false, ++ .boot_entropy_thresh = ATOMIC_INIT(LRNG_INIT_ENTROPY_BITS), ++ .reseed_in_progress = ++ __MUTEX_INITIALIZER(lrng_state.reseed_in_progress), ++}; ++ ++/* ++ * If the entropy count falls under this number of bits, then we ++ * should wake up processes which are selecting or polling on write ++ * access to /dev/random. ++ */ ++u32 lrng_write_wakeup_bits = (LRNG_WRITE_WAKEUP_ENTROPY << 3); ++ ++/* ++ * The entries must be in the same order as defined by enum lrng_internal_es and ++ * enum lrng_external_es ++ */ ++struct lrng_es_cb *lrng_es[] = { ++#ifdef CONFIG_LRNG_IRQ ++ &lrng_es_irq, ++#endif ++#ifdef CONFIG_LRNG_SCHED ++ &lrng_es_sched, ++#endif ++#ifdef CONFIG_LRNG_JENT ++ &lrng_es_jent, ++#endif ++#ifdef CONFIG_LRNG_CPU ++ &lrng_es_cpu, ++#endif ++#ifdef CONFIG_LRNG_KERNEL_RNG ++ &lrng_es_krng, ++#endif ++ &lrng_es_aux ++}; ++ ++static bool ntg1 = false; ++#ifdef CONFIG_LRNG_AIS2031_NTG1_SEEDING_STRATEGY ++module_param(ntg1, bool, 0444); ++MODULE_PARM_DESC(ntg1, "Enable AIS20/31 NTG.1 compliant seeding strategy\n"); ++#endif ++ ++/* Only panic the kernel on permanent health failure if this variable is true */ ++static bool lrng_panic_on_permanent_health_failure = false; ++module_param(lrng_panic_on_permanent_health_failure, bool, 0444); ++MODULE_PARM_DESC(lrng_panic_on_permanent_health_failure, "Panic on reaching permanent health failure - only required if LRNG is part of a FIPS 140-3 module\n"); ++ ++/********************************** Helper ***********************************/ ++ ++bool lrng_enforce_panic_on_permanent_health_failure(void) ++{ ++ return lrng_panic_on_permanent_health_failure; ++} ++ ++bool lrng_ntg1_2022_compliant(void) ++{ ++ /* Implies use of /dev/random w/ O_SYNC / getrandom w/ GRND_RANDOM */ ++ return ntg1; ++} ++ ++void lrng_debug_report_seedlevel(const char *name) ++{ ++#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM ++ static void *previous = NULL; ++ void *caller = (void *) _RET_IP_; ++ struct lrng_drng *atomic = lrng_get_atomic(); ++ ++ if (READ_ONCE(previous) == caller) ++ return; ++ ++ if (atomic && !atomic->fully_seeded) ++ pr_notice("%pS %s called without reaching minimally seeded level (available entropy %u)\n", ++ caller, name, lrng_avail_entropy()); ++ ++ WRITE_ONCE(previous, caller); ++#endif ++} ++ ++/* ++ * Reading of the LRNG pool is only allowed by one caller. The reading is ++ * only performed to (re)seed DRNGs. Thus, if this "lock" is already taken, ++ * the reseeding operation is in progress. The caller is not intended to wait ++ * but continue with its other operation. ++ */ ++int lrng_pool_trylock(void) ++{ ++ return mutex_trylock(&lrng_state.reseed_in_progress); ++} ++ ++void lrng_pool_lock(void) ++{ ++ mutex_lock(&lrng_state.reseed_in_progress); ++} ++ ++void lrng_pool_unlock(void) ++{ ++ mutex_unlock(&lrng_state.reseed_in_progress); ++} ++ ++/* Set new entropy threshold for reseeding during boot */ ++void lrng_set_entropy_thresh(u32 new_entropy_bits) ++{ ++ atomic_set(&lrng_state.boot_entropy_thresh, new_entropy_bits); ++} ++ ++/* ++ * Reset LRNG state - the entropy counters are reset, but the data that may ++ * or may not have entropy remains in the pools as this data will not hurt. ++ */ ++void lrng_reset_state(void) ++{ ++ u32 i; ++ ++ for_each_lrng_es(i) { ++ if (lrng_es[i]->reset) ++ lrng_es[i]->reset(); ++ } ++ lrng_state.lrng_operational = false; ++ lrng_state.lrng_fully_seeded = false; ++ lrng_state.lrng_min_seeded = false; ++ lrng_state.all_online_numa_node_seeded = false; ++ pr_debug("reset LRNG\n"); ++} ++ ++/* Set flag that all DRNGs are fully seeded */ ++void lrng_pool_all_numa_nodes_seeded(bool set) ++{ ++ lrng_state.all_online_numa_node_seeded = set; ++ if (set) ++ wake_up_all(&lrng_init_wait); ++} ++ ++bool lrng_pool_all_numa_nodes_seeded_get(void) ++{ ++ return lrng_state.all_online_numa_node_seeded; ++} ++ ++/* Return boolean whether LRNG reached minimally seed level */ ++bool lrng_state_min_seeded(void) ++{ ++ return lrng_state.lrng_min_seeded; ++} ++ ++/* Return boolean whether LRNG reached fully seed level */ ++bool lrng_state_fully_seeded(void) ++{ ++ return lrng_state.lrng_fully_seeded; ++} ++ ++/* Return boolean whether LRNG is considered fully operational */ ++bool lrng_state_operational(void) ++{ ++ return lrng_state.lrng_operational; ++} ++ ++static void lrng_init_wakeup(void) ++{ ++ wake_up_all(&lrng_init_wait); ++ lrng_init_wakeup_dev(); ++ lrng_kick_random_ready(); ++} ++ ++static u32 lrng_avail_entropy_thresh(void) ++{ ++ u32 ent_thresh = lrng_security_strength(); ++ ++ /* ++ * Apply oversampling during initialization according to SP800-90C as ++ * we request a larger buffer from the ES. ++ */ ++ if (lrng_sp80090c_compliant() && ++ !lrng_state.all_online_numa_node_seeded) ++ ent_thresh += LRNG_SEED_BUFFER_INIT_ADD_BITS; ++ ++ return ent_thresh; ++} ++ ++bool lrng_fully_seeded(bool fully_seeded, u32 collected_entropy, ++ struct entropy_buf *eb) ++{ ++ /* AIS20/31 NTG.1: two entropy sources with each delivering 220 bits */ ++ if (ntg1) { ++ u32 i, result = 0, ent_thresh = lrng_avail_entropy_thresh(); ++ ++ for_each_lrng_es(i) { ++ result += (eb ? eb->e_bits[i] : ++ lrng_es[i]->curr_entropy(ent_thresh)) >= ++ LRNG_AIS2031_NPTRNG_MIN_ENTROPY; ++ } ++ ++ return (result >= 2); ++ } ++ ++ return (collected_entropy >= lrng_get_seed_entropy_osr(fully_seeded)); ++} ++ ++u32 lrng_entropy_rate_eb(struct entropy_buf *eb) ++{ ++ u32 i, collected_entropy = 0; ++ ++ for_each_lrng_es(i) ++ collected_entropy += eb->e_bits[i]; ++ ++ return collected_entropy; ++} ++ ++/* Mark one DRNG as not fully seeded */ ++void lrng_unset_fully_seeded(struct lrng_drng *drng) ++{ ++ drng->fully_seeded = false; ++ lrng_pool_all_numa_nodes_seeded(false); ++ ++ /* ++ * The init DRNG instance must always be fully seeded as this instance ++ * is the fall-back if any of the per-NUMA node DRNG instances is ++ * insufficiently seeded. Thus, we mark the entire LRNG as ++ * non-operational if the initial DRNG becomes not fully seeded. ++ */ ++ if (drng == lrng_drng_init_instance() && lrng_state_operational()) { ++ pr_debug("LRNG set to non-operational\n"); ++ lrng_state.lrng_operational = false; ++ lrng_state.lrng_fully_seeded = false; ++ ++ /* If sufficient entropy is available, reseed now. */ ++ lrng_es_add_entropy(); ++ } ++} ++ ++/* Policy to enable LRNG operational mode */ ++static void lrng_set_operational(void) ++{ ++ /* ++ * LRNG is operational if the initial DRNG is fully seeded. This state ++ * can only occur if either the external entropy sources provided ++ * sufficient entropy, or the SP800-90B startup test completed for ++ * the internal ES to supply also entropy data. ++ */ ++ if (lrng_state.lrng_fully_seeded) { ++ lrng_state.lrng_operational = true; ++ lrng_init_wakeup(); ++ pr_info("LRNG fully operational\n"); ++ } ++} ++ ++/* Available entropy in the entire LRNG considering all entropy sources */ ++u32 lrng_avail_entropy(void) ++{ ++ u32 i, ent = 0, ent_thresh = lrng_avail_entropy_thresh(); ++ ++ BUILD_BUG_ON(ARRAY_SIZE(lrng_es) != lrng_ext_es_last); ++ for_each_lrng_es(i) ++ ent += lrng_es[i]->curr_entropy(ent_thresh); ++ return ent; ++} ++ ++u32 lrng_avail_entropy_aux(void) ++{ ++ u32 ent_thresh = lrng_avail_entropy_thresh(); ++ ++ return lrng_es[lrng_ext_es_aux]->curr_entropy(ent_thresh); ++} ++ ++/* ++ * lrng_init_ops() - Set seed stages of LRNG ++ * ++ * Set the slow noise source reseed trigger threshold. The initial threshold ++ * is set to the minimum data size that can be read from the pool: a word. Upon ++ * reaching this value, the next seed threshold of 128 bits is set followed ++ * by 256 bits. ++ * ++ * @eb: buffer containing the size of entropy currently injected into DRNG - if ++ * NULL, the function obtains the available entropy from the ES. ++ */ ++void lrng_init_ops(struct entropy_buf *eb) ++{ ++ struct lrng_state *state = &lrng_state; ++ u32 i, requested_bits, seed_bits = 0; ++ ++ if (state->lrng_operational) ++ return; ++ ++ requested_bits = ntg1 ? ++ /* Approximation so that two ES should deliver 220 bits each */ ++ (lrng_avail_entropy() + LRNG_AIS2031_NPTRNG_MIN_ENTROPY) : ++ /* Apply SP800-90C oversampling if applicable */ ++ lrng_get_seed_entropy_osr(state->all_online_numa_node_seeded); ++ ++ if (eb) { ++ seed_bits = lrng_entropy_rate_eb(eb); ++ } else { ++ u32 ent_thresh = lrng_avail_entropy_thresh(); ++ ++ for_each_lrng_es(i) ++ seed_bits += lrng_es[i]->curr_entropy(ent_thresh); ++ } ++ ++ /* DRNG is seeded with full security strength */ ++ if (state->lrng_fully_seeded) { ++ lrng_set_operational(); ++ lrng_set_entropy_thresh(requested_bits); ++ } else if (lrng_fully_seeded(state->all_online_numa_node_seeded, ++ seed_bits, eb)) { ++ if (state->can_invalidate) ++ invalidate_batched_entropy(); ++ ++ state->lrng_fully_seeded = true; ++ lrng_set_operational(); ++ state->lrng_min_seeded = true; ++ pr_info("LRNG fully seeded with %u bits of entropy\n", ++ seed_bits); ++ lrng_set_entropy_thresh(requested_bits); ++ } else if (!state->lrng_min_seeded) { ++ ++ /* DRNG is seeded with at least 128 bits of entropy */ ++ if (seed_bits >= LRNG_MIN_SEED_ENTROPY_BITS) { ++ if (state->can_invalidate) ++ invalidate_batched_entropy(); ++ ++ state->lrng_min_seeded = true; ++ pr_info("LRNG minimally seeded with %u bits of entropy\n", ++ seed_bits); ++ lrng_set_entropy_thresh(requested_bits); ++ lrng_init_wakeup(); ++ ++ /* DRNG is seeded with at least LRNG_INIT_ENTROPY_BITS bits */ ++ } else if (seed_bits >= LRNG_INIT_ENTROPY_BITS) { ++ pr_info("LRNG initial entropy level %u bits of entropy\n", ++ seed_bits); ++ lrng_set_entropy_thresh(LRNG_MIN_SEED_ENTROPY_BITS); ++ } ++ } ++} ++ ++void __init lrng_rand_initialize_early(void) ++{ ++ struct seed { ++ unsigned long data[((LRNG_MAX_DIGESTSIZE + ++ sizeof(unsigned long) - 1) / ++ sizeof(unsigned long))]; ++ struct new_utsname utsname; ++ } seed __aligned(LRNG_KCAPI_ALIGN); ++ size_t longs = 0; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(seed.data); i += longs) { ++ longs = arch_get_random_seed_longs(seed.data + i, ++ ARRAY_SIZE(seed.data) - i); ++ if (longs) ++ continue; ++ longs = arch_get_random_longs(seed.data + i, ++ ARRAY_SIZE(seed.data) - i); ++ if (longs) ++ continue; ++ longs = 1; ++ } ++ memcpy(&seed.utsname, init_utsname(), sizeof(*(init_utsname()))); ++ ++ lrng_pool_insert_aux((u8 *)&seed, sizeof(seed), 0); ++ memzero_explicit(&seed, sizeof(seed)); ++ ++ lrng_force_fully_seeded(); ++} ++ ++void __init lrng_rand_initialize(void) ++{ ++ unsigned long entropy = random_get_entropy(); ++ ktime_t time = ktime_get_real(); ++ ++ lrng_pool_insert_aux((u8 *)&entropy, sizeof(entropy), 0); ++ lrng_pool_insert_aux((u8 *)&time, sizeof(time), 0); ++ ++ /* Initialize the seed work queue */ ++ INIT_WORK(&lrng_state.lrng_seed_work, lrng_drng_seed_work); ++ lrng_state.perform_seedwork = true; ++ ++ invalidate_batched_entropy(); ++ ++ lrng_state.can_invalidate = true; ++} ++ ++#ifndef CONFIG_LRNG_RANDOM_IF ++static int __init lrng_rand_initialize_call(void) ++{ ++ lrng_rand_initialize_early(); ++ lrng_rand_initialize(); ++ return 0; ++} ++ ++early_initcall(lrng_rand_initialize_call); ++#endif ++ ++/* Interface requesting a reseed of the DRNG */ ++void lrng_es_add_entropy(void) ++{ ++ /* ++ * Once all DRNGs are fully seeded, the system-triggered arrival of ++ * entropy will not cause any reseeding any more. ++ */ ++ if (likely(lrng_state.all_online_numa_node_seeded)) ++ return; ++ ++ /* Only trigger the DRNG reseed if we have collected entropy. */ ++ if (lrng_avail_entropy() < ++ atomic_read_u32(&lrng_state.boot_entropy_thresh)) ++ return; ++ ++ /* Ensure that the seeding only occurs once at any given time. */ ++ if (!lrng_pool_trylock()) ++ return; ++ ++ /* Seed the DRNG with any available noise. */ ++ if (lrng_state.perform_seedwork) ++ schedule_work(&lrng_state.lrng_seed_work); ++ else ++ lrng_drng_seed_work(NULL); ++} ++ ++/* Fill the seed buffer with data from the noise sources */ ++void lrng_fill_seed_buffer(struct entropy_buf *eb, u32 requested_bits, ++ bool force) ++{ ++ struct lrng_state *state = &lrng_state; ++ u32 i, req_ent = lrng_sp80090c_compliant() ? ++ lrng_security_strength() : LRNG_MIN_SEED_ENTROPY_BITS; ++ ++ /* Guarantee that requested bits is a multiple of bytes */ ++ BUILD_BUG_ON(LRNG_DRNG_SECURITY_STRENGTH_BITS % 8); ++ ++ /* always reseed the DRNG with the current time stamp */ ++ eb->now = random_get_entropy(); ++ ++ /* ++ * Require at least 128 bits of entropy for any reseed. If the LRNG is ++ * operated SP800-90C compliant we want to comply with SP800-90A section ++ * 9.2 mandating that DRNG is reseeded with the security strength. ++ */ ++ if (!force && ++ state->lrng_fully_seeded && (lrng_avail_entropy() < req_ent)) { ++ for_each_lrng_es(i) ++ eb->e_bits[i] = 0; ++ ++ goto wakeup; ++ } ++ ++ /* Concatenate the output of the entropy sources. */ ++ for_each_lrng_es(i) { ++ lrng_es[i]->get_ent(eb, requested_bits, ++ state->lrng_fully_seeded); ++ } ++ ++ /* allow external entropy provider to provide seed */ ++ lrng_state_exseed_allow_all(); ++ ++wakeup: ++ lrng_writer_wakeup(); ++} +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_mgr.h +@@ -0,0 +1,56 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_MGR_H ++#define _LRNG_ES_MGR_H ++ ++#include "lrng_es_mgr_cb.h" ++ ++/*************************** General LRNG parameter ***************************/ ++ ++#define LRNG_DRNG_BLOCKSIZE 64 /* Maximum of DRNG block sizes */ ++ ++/* Helper to concatenate a macro with an integer type */ ++#define LRNG_PASTER(x, y) x ## y ++#define LRNG_UINT32_C(x) LRNG_PASTER(x, U) ++ ++/************************* Entropy sources management *************************/ ++ ++extern struct lrng_es_cb *lrng_es[]; ++ ++#define for_each_lrng_es(ctr) \ ++ for ((ctr) = 0; (ctr) < lrng_ext_es_last; (ctr)++) ++ ++bool lrng_enforce_panic_on_permanent_health_failure(void); ++bool lrng_ntg1_2022_compliant(void); ++bool lrng_pool_all_numa_nodes_seeded_get(void); ++bool lrng_state_min_seeded(void); ++void lrng_debug_report_seedlevel(const char *name); ++void lrng_rand_initialize_early(void); ++void lrng_rand_initialize(void); ++bool lrng_state_operational(void); ++ ++extern u32 lrng_write_wakeup_bits; ++void lrng_set_entropy_thresh(u32 new); ++u32 lrng_avail_entropy(void); ++u32 lrng_avail_entropy_aux(void); ++void lrng_reset_state(void); ++ ++bool lrng_state_fully_seeded(void); ++ ++int lrng_pool_trylock(void); ++void lrng_pool_lock(void); ++void lrng_pool_unlock(void); ++void lrng_pool_all_numa_nodes_seeded(bool set); ++ ++bool lrng_fully_seeded(bool fully_seeded, u32 collected_entropy, ++ struct entropy_buf *eb); ++u32 lrng_entropy_rate_eb(struct entropy_buf *eb); ++void lrng_unset_fully_seeded(struct lrng_drng *drng); ++void lrng_fill_seed_buffer(struct entropy_buf *eb, u32 requested_bits, ++ bool force); ++void lrng_init_ops(struct entropy_buf *eb); ++ ++#endif /* _LRNG_ES_MGR_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_mgr_cb.h +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ * ++ * Definition of an entropy source. ++ */ ++ ++#ifndef _LRNG_ES_MGR_CB_H ++#define _LRNG_ES_MGR_CB_H ++ ++#include ++ ++#include "lrng_definitions.h" ++#include "lrng_drng_mgr.h" ++ ++enum lrng_internal_es { ++#ifdef CONFIG_LRNG_IRQ ++ lrng_int_es_irq, /* IRQ-based entropy source */ ++#endif ++#ifdef CONFIG_LRNG_SCHED ++ lrng_int_es_sched, /* Scheduler entropy source */ ++#endif ++ lrng_int_es_last, /* MUST be the last entry */ ++}; ++ ++enum lrng_external_es { ++ lrng_ext_link = lrng_int_es_last - 1, /* Link entry */ ++#ifdef CONFIG_LRNG_JENT ++ lrng_ext_es_jitter, /* Jitter RNG */ ++#endif ++#ifdef CONFIG_LRNG_CPU ++ lrng_ext_es_cpu, /* CPU-based, e.g. RDSEED */ ++#endif ++#ifdef CONFIG_LRNG_KERNEL_RNG ++ lrng_ext_es_krng, /* random.c */ ++#endif ++ lrng_ext_es_aux, /* MUST BE LAST ES! */ ++ lrng_ext_es_last /* MUST be the last entry */ ++}; ++ ++struct entropy_buf { ++ u8 e[lrng_ext_es_last][LRNG_DRNG_INIT_SEED_SIZE_BYTES]; ++ u32 now, e_bits[lrng_ext_es_last]; ++}; ++ ++/* ++ * struct lrng_es_cb - callback defining an entropy source ++ * @name: Name of the entropy source. ++ * @get_ent: Fetch entropy into the entropy_buf. The ES shall only deliver ++ * data if its internal initialization is complete, including any ++ * SP800-90B startup testing or similar. ++ * @curr_entropy: Return amount of currently available entropy. ++ * @max_entropy: Maximum amount of entropy the entropy source is able to ++ * maintain. ++ * @state: Buffer with human-readable ES state. ++ * @reset: Reset entropy source (drop all entropy and reinitialize). ++ * This callback may be NULL. ++ * @switch_hash: callback to switch from an old hash callback definition to ++ * a new one. This callback may be NULL. ++ */ ++struct lrng_es_cb { ++ const char *name; ++ void (*get_ent)(struct entropy_buf *eb, u32 requested_bits, ++ bool fully_seeded); ++ u32 (*curr_entropy)(u32 requested_bits); ++ u32 (*max_entropy)(void); ++ void (*state)(unsigned char *buf, size_t buflen); ++ void (*reset)(void); ++ int (*switch_hash)(struct lrng_drng *drng, int node, ++ const struct lrng_hash_cb *new_cb, void *new_hash, ++ const struct lrng_hash_cb *old_cb); ++}; ++ ++/* Allow entropy sources to tell the ES manager that new entropy is there */ ++void lrng_es_add_entropy(void); ++ ++/* Cap to maximum entropy that can ever be generated with given hash */ ++#define lrng_cap_requested(__digestsize_bits, __requested_bits) \ ++ do { \ ++ if (__digestsize_bits < __requested_bits) { \ ++ pr_debug("Cannot satisfy requested entropy %u due to insufficient hash size %u\n",\ ++ __requested_bits, __digestsize_bits); \ ++ __requested_bits = __digestsize_bits; \ ++ } \ ++ } while (0) ++ ++#endif /* _LRNG_ES_MGR_CB_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_sched.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_SCHED_H ++#define _LRNG_ES_SCHED_H ++ ++#include "lrng_es_mgr_cb.h" ++ ++#ifdef CONFIG_LRNG_SCHED ++void lrng_sched_es_init(bool highres_timer); ++ ++extern struct lrng_es_cb lrng_es_sched; ++ ++#else /* CONFIG_LRNG_SCHED */ ++static inline void lrng_sched_es_init(bool highres_timer) { } ++#endif /* CONFIG_LRNG_SCHED */ ++ ++#endif /* _LRNG_ES_SCHED_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_timer_common.h +@@ -0,0 +1,83 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * LRNG Slow Noise Source: Time stamp array handling ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_ES_TIMER_COMMON_H ++#define _LRNG_ES_TIMER_COMMON_H ++ ++bool lrng_gcd_tested(void); ++void lrng_gcd_set(u32 running_gcd); ++u32 lrng_gcd_get(void); ++u32 lrng_gcd_analyze(u32 *history, size_t nelem); ++void lrng_gcd_add_value(u32 time); ++bool lrng_highres_timer(void); ++ ++/* ++ * To limit the impact on the interrupt handling, the LRNG concatenates ++ * entropic LSB parts of the time stamps in a per-CPU array and only ++ * injects them into the entropy pool when the array is full. ++ */ ++ ++/* Store multiple integers in one u32 */ ++#define LRNG_DATA_SLOTSIZE_BITS (8) ++#define LRNG_DATA_SLOTSIZE_MASK ((1 << LRNG_DATA_SLOTSIZE_BITS) - 1) ++#define LRNG_DATA_ARRAY_MEMBER_BITS (4 << 3) /* ((sizeof(u32)) << 3) */ ++#define LRNG_DATA_SLOTS_PER_UINT (LRNG_DATA_ARRAY_MEMBER_BITS / \ ++ LRNG_DATA_SLOTSIZE_BITS) ++ ++/* ++ * Number of time values to store in the array - in small environments ++ * only one atomic_t variable per CPU is used. ++ */ ++#define LRNG_DATA_NUM_VALUES (CONFIG_LRNG_COLLECTION_SIZE) ++/* Mask of LSB of time stamp to store */ ++#define LRNG_DATA_WORD_MASK (LRNG_DATA_NUM_VALUES - 1) ++ ++#define LRNG_DATA_SLOTS_MASK (LRNG_DATA_SLOTS_PER_UINT - 1) ++#define LRNG_DATA_ARRAY_SIZE (LRNG_DATA_NUM_VALUES / \ ++ LRNG_DATA_SLOTS_PER_UINT) ++ ++/* Starting bit index of slot */ ++static inline unsigned int lrng_data_slot2bitindex(unsigned int slot) ++{ ++ return (LRNG_DATA_SLOTSIZE_BITS * slot); ++} ++ ++/* Convert index into the array index */ ++static inline unsigned int lrng_data_idx2array(unsigned int idx) ++{ ++ return idx / LRNG_DATA_SLOTS_PER_UINT; ++} ++ ++/* Convert index into the slot of a given array index */ ++static inline unsigned int lrng_data_idx2slot(unsigned int idx) ++{ ++ return idx & LRNG_DATA_SLOTS_MASK; ++} ++ ++/* Convert value into slot value */ ++static inline unsigned int lrng_data_slot_val(unsigned int val, ++ unsigned int slot) ++{ ++ return val << lrng_data_slot2bitindex(slot); ++} ++ ++/* ++ * Return the pointers for the previous and current units to inject a u32 into. ++ * Also return the mask which the u32 word is to be processed. ++ */ ++static inline void lrng_data_split_u32(u32 *ptr, u32 *pre_ptr, u32 *mask) ++{ ++ /* ptr to previous unit */ ++ *pre_ptr = (*ptr - LRNG_DATA_SLOTS_PER_UINT) & LRNG_DATA_WORD_MASK; ++ *ptr &= LRNG_DATA_WORD_MASK; ++ ++ /* mask to split data into the two parts for the two units */ ++ *mask = ((1 << (*pre_ptr & (LRNG_DATA_SLOTS_PER_UINT - 1)) * ++ LRNG_DATA_SLOTSIZE_BITS)) - 1; ++} ++ ++#endif /* _LRNG_ES_TIMER_COMMON_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_dev_common.h +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_INTERFACE_DEV_COMMON_H ++#define _LRNG_INTERFACE_DEV_COMMON_H ++ ++#include ++#include ++ ++/******************* Upstream functions hooked into the LRNG ******************/ ++enum lrng_external_noise_source { ++ lrng_noise_source_hw, ++ lrng_noise_source_user ++}; ++ ++#ifdef CONFIG_LRNG_COMMON_DEV_IF ++void lrng_writer_wakeup(void); ++void lrng_init_wakeup_dev(void); ++void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type); ++void lrng_state_exseed_allow_all(void); ++#else /* CONFIG_LRNG_COMMON_DEV_IF */ ++static inline void lrng_writer_wakeup(void) { } ++static inline void lrng_init_wakeup_dev(void) { } ++static inline void ++lrng_state_exseed_set(enum lrng_external_noise_source source, bool type) { } ++static inline void lrng_state_exseed_allow_all(void) { } ++#endif /* CONFIG_LRNG_COMMON_DEV_IF */ ++ ++/****** Downstream service functions to actual interface implementations ******/ ++ ++bool lrng_state_exseed_allow(enum lrng_external_noise_source source); ++int lrng_fasync(int fd, struct file *filp, int on); ++long lrng_ioctl(struct file *f, unsigned int cmd, unsigned long arg); ++ssize_t lrng_drng_write(struct file *file, const char __user *buffer, ++ size_t count, loff_t *ppos); ++ssize_t lrng_drng_write_common(const char __user *buffer, size_t count, ++ u32 entropy_bits); ++__poll_t lrng_random_poll(struct file *file, poll_table *wait); ++ssize_t lrng_read_common_block(int nonblock, int pr, ++ char __user *buf, size_t nbytes); ++ssize_t lrng_drng_read_block(struct file *file, char __user *buf, size_t nbytes, ++ loff_t *ppos); ++ssize_t lrng_read_seed(char __user *buf, size_t nbytes, unsigned int flags); ++ssize_t lrng_read_common(char __user *buf, size_t nbytes, bool pr); ++bool lrng_need_entropy(void); ++ ++extern struct wait_queue_head lrng_write_wait; ++ ++#endif /* _LRNG_INTERFACE_DEV_COMMON_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_random_kernel.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_INTERFACE_RANDOM_H ++#define _LRNG_INTERFACE_RANDOM_H ++ ++#ifdef CONFIG_LRNG_RANDOM_IF ++void invalidate_batched_entropy(void); ++void lrng_kick_random_ready(void); ++#else /* CONFIG_LRNG_RANDOM_IF */ ++static inline void invalidate_batched_entropy(void) { } ++static inline void lrng_kick_random_ready(void) { } ++#endif /* CONFIG_LRNG_RANDOM_IF */ ++ ++#endif /* _LRNG_INTERFACE_RANDOM_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_numa.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_NUMA_H ++#define _LRNG_NUMA_H ++ ++static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; } ++ ++#endif /* _LRNG_NUMA_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_sha.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * LRNG SHA definition usable in atomic contexts right from the start of the ++ * kernel. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_SHA_H ++#define _LRNG_SHA_H ++ ++extern const struct lrng_hash_cb lrng_sha_hash_cb; ++ ++#endif /* _LRNG_SHA_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_sha1.c +@@ -0,0 +1,88 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * Backend for the LRNG providing the SHA-1 implementation that can be used ++ * without the kernel crypto API available including during early boot and in ++ * atomic contexts. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++ ++#include "lrng_sha.h" ++ ++/* ++ * If the SHA-256 support is not compiled, we fall back to SHA-1 that is always ++ * compiled and present in the kernel. ++ */ ++static u32 lrng_sha1_hash_digestsize(void *hash) ++{ ++ return SHA1_DIGEST_SIZE; ++} ++ ++static void lrng_sha1_block_fn(struct sha1_state *sctx, const u8 *src, ++ int blocks) ++{ ++ u32 temp[SHA1_WORKSPACE_WORDS]; ++ ++ while (blocks--) { ++ sha1_transform(sctx->state, src, temp); ++ src += SHA1_BLOCK_SIZE; ++ } ++ memzero_explicit(temp, sizeof(temp)); ++} ++ ++static int lrng_sha1_hash_init(struct shash_desc *shash, void *hash) ++{ ++ /* ++ * We do not need a TFM - we only need sufficient space for ++ * struct sha1_state on the stack. ++ */ ++ sha1_base_init(shash); ++ return 0; ++} ++ ++static int lrng_sha1_hash_update(struct shash_desc *shash, ++ const u8 *inbuf, u32 inbuflen) ++{ ++ return sha1_base_do_update(shash, inbuf, inbuflen, lrng_sha1_block_fn); ++} ++ ++static int lrng_sha1_hash_final(struct shash_desc *shash, u8 *digest) ++{ ++ return sha1_base_do_finalize(shash, lrng_sha1_block_fn) ?: ++ sha1_base_finish(shash, digest); ++} ++ ++static const char *lrng_sha1_hash_name(void) ++{ ++ return "SHA-1"; ++} ++ ++static void lrng_sha1_hash_desc_zero(struct shash_desc *shash) ++{ ++ memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha1_state)); ++} ++ ++static void *lrng_sha1_hash_alloc(void) ++{ ++ pr_info("Hash %s allocated\n", lrng_sha1_hash_name()); ++ return NULL; ++} ++ ++static void lrng_sha1_hash_dealloc(void *hash) { } ++ ++const struct lrng_hash_cb lrng_sha_hash_cb = { ++ .hash_name = lrng_sha1_hash_name, ++ .hash_alloc = lrng_sha1_hash_alloc, ++ .hash_dealloc = lrng_sha1_hash_dealloc, ++ .hash_digestsize = lrng_sha1_hash_digestsize, ++ .hash_init = lrng_sha1_hash_init, ++ .hash_update = lrng_sha1_hash_update, ++ .hash_final = lrng_sha1_hash_final, ++ .hash_desc_zero = lrng_sha1_hash_desc_zero, ++}; +--- /dev/null ++++ b/drivers/char/lrng/lrng_sha256.c +@@ -0,0 +1,72 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * Backend for the LRNG providing the SHA-256 implementation that can be used ++ * without the kernel crypto API available including during early boot and in ++ * atomic contexts. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++ ++#include "lrng_sha.h" ++ ++static u32 lrng_sha256_hash_digestsize(void *hash) ++{ ++ return SHA256_DIGEST_SIZE; ++} ++ ++static int lrng_sha256_hash_init(struct shash_desc *shash, void *hash) ++{ ++ /* ++ * We do not need a TFM - we only need sufficient space for ++ * struct sha256_state on the stack. ++ */ ++ sha256_init(shash_desc_ctx(shash)); ++ return 0; ++} ++ ++static int lrng_sha256_hash_update(struct shash_desc *shash, ++ const u8 *inbuf, u32 inbuflen) ++{ ++ sha256_update(shash_desc_ctx(shash), inbuf, inbuflen); ++ return 0; ++} ++ ++static int lrng_sha256_hash_final(struct shash_desc *shash, u8 *digest) ++{ ++ sha256_final(shash_desc_ctx(shash), digest); ++ return 0; ++} ++ ++static const char *lrng_sha256_hash_name(void) ++{ ++ return "SHA-256"; ++} ++ ++static void lrng_sha256_hash_desc_zero(struct shash_desc *shash) ++{ ++ memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha256_state)); ++} ++ ++static void *lrng_sha256_hash_alloc(void) ++{ ++ pr_info("Hash %s allocated\n", lrng_sha256_hash_name()); ++ return NULL; ++} ++ ++static void lrng_sha256_hash_dealloc(void *hash) { } ++ ++const struct lrng_hash_cb lrng_sha_hash_cb = { ++ .hash_name = lrng_sha256_hash_name, ++ .hash_alloc = lrng_sha256_hash_alloc, ++ .hash_dealloc = lrng_sha256_hash_dealloc, ++ .hash_digestsize = lrng_sha256_hash_digestsize, ++ .hash_init = lrng_sha256_hash_init, ++ .hash_update = lrng_sha256_hash_update, ++ .hash_final = lrng_sha256_hash_final, ++ .hash_desc_zero = lrng_sha256_hash_desc_zero, ++}; +--- /dev/null ++++ b/drivers/char/lrng/lrng_sysctl.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_SYSCTL_H ++#define _LRNG_SYSCTL_H ++ ++#ifdef CONFIG_LRNG_SYSCTL ++void lrng_sysctl_update_max_write_thresh(u32 new_digestsize); ++#else ++static inline void lrng_sysctl_update_max_write_thresh(u32 new_digestsize) { } ++#endif ++ ++#endif /* _LRNG_SYSCTL_H */ +--- /dev/null ++++ b/include/linux/lrng.h +@@ -0,0 +1,251 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_H ++#define _LRNG_H ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * struct lrng_drng_cb - cryptographic callback functions defining a DRNG ++ * @drng_name Name of DRNG ++ * @drng_alloc: Allocate DRNG -- the provided integer should be used for ++ * sanity checks. ++ * return: allocated data structure or PTR_ERR on error ++ * @drng_dealloc: Deallocate DRNG ++ * @drng_seed: Seed the DRNG with data of arbitrary length drng: is ++ * pointer to data structure allocated with drng_alloc ++ * return: >= 0 on success, < 0 on error ++ * @drng_generate: Generate random numbers from the DRNG with arbitrary ++ * length ++ */ ++struct lrng_drng_cb { ++ const char *(*drng_name)(void); ++ void *(*drng_alloc)(u32 sec_strength); ++ void (*drng_dealloc)(void *drng); ++ int (*drng_seed)(void *drng, const u8 *inbuf, u32 inbuflen); ++ int (*drng_generate)(void *drng, u8 *outbuf, u32 outbuflen); ++}; ++ ++/* ++ * struct lrng_hash_cb - cryptographic callback functions defining a hash ++ * @hash_name Name of Hash used for reading entropy pool arbitrary ++ * length ++ * @hash_alloc: Allocate the hash for reading the entropy pool ++ * return: allocated data structure (NULL is success too) ++ * or ERR_PTR on error ++ * @hash_dealloc: Deallocate Hash ++ * @hash_digestsize: Return the digestsize for the used hash to read out ++ * entropy pool ++ * hash: is pointer to data structure allocated with ++ * hash_alloc ++ * return: size of digest of hash in bytes ++ * @hash_init: Initialize hash ++ * hash: is pointer to data structure allocated with ++ * hash_alloc ++ * return: 0 on success, < 0 on error ++ * @hash_update: Update hash operation ++ * hash: is pointer to data structure allocated with ++ * hash_alloc ++ * return: 0 on success, < 0 on error ++ * @hash_final Final hash operation ++ * hash: is pointer to data structure allocated with ++ * hash_alloc ++ * return: 0 on success, < 0 on error ++ * @hash_desc_zero Zeroization of hash state buffer ++ * ++ * Assumptions: ++ * ++ * 1. Hash operation will not sleep ++ * 2. The hash' volatile state information is provided with *shash by caller. ++ */ ++struct lrng_hash_cb { ++ const char *(*hash_name)(void); ++ void *(*hash_alloc)(void); ++ void (*hash_dealloc)(void *hash); ++ u32 (*hash_digestsize)(void *hash); ++ int (*hash_init)(struct shash_desc *shash, void *hash); ++ int (*hash_update)(struct shash_desc *shash, const u8 *inbuf, ++ u32 inbuflen); ++ int (*hash_final)(struct shash_desc *shash, u8 *digest); ++ void (*hash_desc_zero)(struct shash_desc *shash); ++}; ++ ++/* Register cryptographic backend */ ++#ifdef CONFIG_LRNG_SWITCH ++int lrng_set_drng_cb(const struct lrng_drng_cb *cb); ++int lrng_set_hash_cb(const struct lrng_hash_cb *cb); ++#else /* CONFIG_LRNG_SWITCH */ ++static inline int ++lrng_set_drng_cb(const struct lrng_drng_cb *cb) { return -EOPNOTSUPP; } ++static inline int ++lrng_set_hash_cb(const struct lrng_hash_cb *cb) { return -EOPNOTSUPP; } ++#endif /* CONFIG_LRNG_SWITCH */ ++ ++/* Callback to feed events to the scheduler entropy source */ ++#ifdef CONFIG_LRNG_SCHED ++extern void add_sched_randomness(const struct task_struct *p, int cpu); ++#else ++static inline void ++add_sched_randomness(const struct task_struct *p, int cpu) { } ++#endif ++ ++/* ++ * lrng_get_random_bytes() - Provider of cryptographic strong random numbers ++ * for kernel-internal usage. ++ * ++ * This function is appropriate for in-kernel use cases operating in atomic ++ * contexts. It will always use the ChaCha20 DRNG and it may be the case that ++ * it is not fully seeded when being used. ++ * ++ * @buf: buffer to store the random bytes ++ * @nbytes: size of the buffer ++ */ ++#ifdef CONFIG_LRNG_DRNG_ATOMIC ++void lrng_get_random_bytes(void *buf, int nbytes); ++#endif ++ ++/* ++ * lrng_get_random_bytes_full() - Provider of cryptographic strong ++ * random numbers for kernel-internal usage from a fully initialized LRNG. ++ * ++ * This function will always return random numbers from a fully seeded and ++ * fully initialized LRNG. ++ * ++ * This function is appropriate only for non-atomic use cases as this ++ * function may sleep. It provides access to the full functionality of LRNG ++ * including the switchable DRNG support, that may support other DRNGs such ++ * as the SP800-90A DRBG. ++ * ++ * @buf: buffer to store the random bytes ++ * @nbytes: size of the buffer ++ */ ++#ifdef CONFIG_LRNG ++void lrng_get_random_bytes_full(void *buf, int nbytes); ++#endif ++ ++/* ++ * lrng_get_random_bytes_min() - Provider of cryptographic strong ++ * random numbers for kernel-internal usage from at least a minimally seeded ++ * LRNG, which is not necessarily fully initialized yet (e.g. SP800-90C ++ * oversampling applied in FIPS mode is not applied yet). ++ * ++ * This function is appropriate only for non-atomic use cases as this ++ * function may sleep. It provides access to the full functionality of LRNG ++ * including the switchable DRNG support, that may support other DRNGs such ++ * as the SP800-90A DRBG. ++ * ++ * @buf: buffer to store the random bytes ++ * @nbytes: size of the buffer ++ */ ++#ifdef CONFIG_LRNG ++void lrng_get_random_bytes_min(void *buf, int nbytes); ++#endif ++ ++/* ++ * lrng_get_random_bytes_pr() - Provider of cryptographic strong ++ * random numbers for kernel-internal usage from a fully initialized LRNG and ++ * requiring a reseed from the entropy sources before. ++ * ++ * This function will always return random numbers from a fully seeded and ++ * fully initialized LRNG. ++ * ++ * This function is appropriate only for non-atomic use cases as this ++ * function may sleep. It provides access to the full functionality of LRNG ++ * including the switchable DRNG support, that may support other DRNGs such ++ * as the SP800-90A DRBG. ++ * ++ * This call only returns no more data than entropy was pulled from the ++ * entropy sources. Thus, it is likely that this call returns less data ++ * than requested by the caller. Also, the caller MUST be prepared that this ++ * call returns 0 bytes, i.e. it did not generate data. ++ * ++ * @buf: buffer to store the random bytes ++ * @nbytes: size of the buffer ++ * ++ * @return: positive number indicates amount of generated bytes, < 0 on error ++ */ ++#ifdef CONFIG_LRNG ++int lrng_get_random_bytes_pr(void *buf, int nbytes); ++#endif ++ ++/* ++ * lrng_get_seed() - Fill buffer with data from entropy sources ++ * ++ * This call allows accessing the entropy sources directly and fill the buffer ++ * with data from all available entropy sources. This filled buffer is ++ * identical to the temporary seed buffer used by the LRNG to seed its DRNGs. ++ * ++ * The call is to allows users to seed their DRNG directly from the entropy ++ * sources in case the caller does not want to use the LRNG's DRNGs. This ++ * buffer can be directly used to seed the caller's DRNG from. ++ * ++ * The call blocks as long as one LRNG DRNG is not yet fully seeded. If ++ * LRNG_GET_SEED_NONBLOCK is specified, it does not block in this case, but ++ * returns with an error. ++ * ++ * Considering SP800-90C, there is a differentiation between the seeding ++ * requirements during instantiating a DRNG and at runtime of the DRNG. When ++ * specifying LRNG_GET_SEED_FULLY_SEEDED the caller indicates the DRNG was ++ * already fully seeded and the regular amount of entropy is requested. ++ * Otherwise, the LRNG will obtain the entropy rate required for initial ++ * seeding. The following minimum entropy rates will be obtained: ++ * ++ * * FIPS mode: ++ * * Initial seeding: 384 bits of entropy ++ * * Runtime seeding: 256 bits of entropy ++ * * Non-FIPS mode: ++ * * 128 bits of entropy in any case ++ * ++ * Albeit these are minimum entropy rates, the LRNG tries to request the ++ * given amount of entropy from each entropy source individually. If the ++ * minimum amount of entropy cannot be obtained collectively by all entropy ++ * sources, the LRNG will not fill the buffer. ++ * ++ * The return data in buf is structurally equivalent to the following ++ * definition: ++ * ++ * struct { ++ * u64 seedlen; ++ * u64 entropy_rate; ++ * struct entropy_buf seed; ++ * } __attribute((__packed__)); ++ * ++ * As struct entropy_buf is not known outsize of the LRNG, the LRNG fills ++ * seedlen first with the size of struct entropy_buf. If the caller-provided ++ * buffer buf is smaller than u64, then -EINVAL is returned ++ * and buf is not touched. If it is u64 or larger but smaller ++ * than the size of the structure above, -EMSGSIZE is returned and seedlen ++ * is filled with the size of the buffer. Finally, if buf is large ++ * enough to hold all data, it is filled with the seed data and the seedlen ++ * is set to sizeof(struct entropy_buf). The entropy rate is returned with ++ * the variable entropy_rate and provides the value in bits. ++ * ++ * The seed buffer is the data that should be handed to the caller's DRNG as ++ * seed data. ++ * ++ * @buf [out] Buffer to be filled with data from the entropy sources - note, the ++ * buffer is marked as u64 to ensure it is aligned to 64 bits. ++ * @nbytes [in] Size of the buffer allocated by the caller - this value ++ * provides size of @param buf in bytes. ++ * @flags [in] Flags field to adjust the behavior ++ * ++ * @return -EINVAL or -EMSGSIZE indicating the buffer is too small, -EAGAIN when ++ * the call would block, but NONBLOCK is specified, > 0 the size of ++ * the filled buffer. ++ */ ++#ifdef CONFIG_LRNG ++enum lrng_get_seed_flags { ++ LRNG_GET_SEED_NONBLOCK = 0x0001, /**< Do not block the call */ ++ LRNG_GET_SEED_FULLY_SEEDED = 0x0002, /**< DRNG is fully seeded */ ++}; ++ ++ssize_t lrng_get_seed(u64 *buf, size_t nbytes, unsigned int flags); ++#endif ++ ++#endif /* _LRNG_H */ diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch new file mode 100644 index 000000000..1ced3e297 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch @@ -0,0 +1,194 @@ +From c214eec976715ae46ed8e6eee5a2147c8fd155eb Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 15:40:46 +0200 +Subject: [PATCH 02/25] LRNG - allocate one DRNG instance per NUMA node + +In order to improve NUMA-locality when serving getrandom(2) requests, +allocate one DRNG instance per node. + +The DRNG instance that is present right from the start of the kernel is +reused as the first per-NUMA-node DRNG. For all remaining online NUMA +nodes a new DRNG instance is allocated. + +During boot time, the multiple DRNG instances are seeded sequentially. +With this, the first DRNG instance (referenced as the initial DRNG +in the code) is completely seeded with 256 bits of entropy before the +next DRNG instance is completely seeded. + +When random numbers are requested, the NUMA-node-local DRNG is checked +whether it has been already fully seeded. If this is not the case, the +initial DRNG is used to serve the request. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Makefile | 2 + + drivers/char/lrng/lrng_numa.c | 124 ++++++++++++++++++++++++++++++++++ + drivers/char/lrng/lrng_numa.h | 4 ++ + drivers/char/lrng/lrng_proc.h | 11 +++ + 4 files changed, 141 insertions(+) + create mode 100644 drivers/char/lrng/lrng_numa.c + create mode 100644 drivers/char/lrng/lrng_proc.h + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -8,4 +8,6 @@ obj-y += lrng_es_mgr.o lrng_drng_mgr + obj-$(CONFIG_LRNG_SHA256) += lrng_sha256.o + obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o + ++obj-$(CONFIG_NUMA) += lrng_numa.o ++ + obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_numa.c +@@ -0,0 +1,124 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG NUMA support ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++ ++#include "lrng_drng_mgr.h" ++#include "lrng_es_irq.h" ++#include "lrng_es_mgr.h" ++#include "lrng_numa.h" ++#include "lrng_proc.h" ++ ++static struct lrng_drng **lrng_drng __read_mostly = NULL; ++ ++struct lrng_drng **lrng_drng_instances(void) ++{ ++ /* counterpart to cmpxchg_release in _lrng_drngs_numa_alloc */ ++ return READ_ONCE(lrng_drng); ++} ++ ++/* Allocate the data structures for the per-NUMA node DRNGs */ ++static void _lrng_drngs_numa_alloc(struct work_struct *work) ++{ ++ struct lrng_drng **drngs; ++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ u32 node; ++ bool init_drng_used = false; ++ ++ mutex_lock(&lrng_crypto_cb_update); ++ ++ /* per-NUMA-node DRNGs are already present */ ++ if (lrng_drng) ++ goto unlock; ++ ++ /* Make sure the initial DRNG is initialized and its drng_cb is set */ ++ if (lrng_drng_initalize()) ++ goto err; ++ ++ drngs = kcalloc(nr_node_ids, sizeof(void *), GFP_KERNEL|__GFP_NOFAIL); ++ for_each_online_node(node) { ++ struct lrng_drng *drng; ++ ++ if (!init_drng_used) { ++ drngs[node] = lrng_drng_init; ++ init_drng_used = true; ++ continue; ++ } ++ ++ drng = kmalloc_node(sizeof(struct lrng_drng), ++ GFP_KERNEL|__GFP_NOFAIL, node); ++ memset(drng, 0, sizeof(lrng_drng)); ++ ++ if (lrng_drng_alloc_common(drng, lrng_drng_init->drng_cb)) { ++ kfree(drng); ++ goto err; ++ } ++ ++ drng->hash_cb = lrng_drng_init->hash_cb; ++ drng->hash = lrng_drng_init->hash_cb->hash_alloc(); ++ if (IS_ERR(drng->hash)) { ++ lrng_drng_init->drng_cb->drng_dealloc(drng->drng); ++ kfree(drng); ++ goto err; ++ } ++ ++ mutex_init(&drng->lock); ++ rwlock_init(&drng->hash_lock); ++ ++ /* ++ * No reseeding of NUMA DRNGs from previous DRNGs as this ++ * would complicate the code. Let it simply reseed. ++ */ ++ drngs[node] = drng; ++ ++ lrng_pool_inc_numa_node(); ++ pr_info("DRNG and entropy pool read hash for NUMA node %d allocated\n", ++ node); ++ } ++ ++ /* counterpart to READ_ONCE in lrng_drng_instances */ ++ if (!cmpxchg_release(&lrng_drng, NULL, drngs)) { ++ lrng_pool_all_numa_nodes_seeded(false); ++ goto unlock; ++ } ++ ++err: ++ for_each_online_node(node) { ++ struct lrng_drng *drng = drngs[node]; ++ ++ if (drng == lrng_drng_init) ++ continue; ++ ++ if (drng) { ++ drng->hash_cb->hash_dealloc(drng->hash); ++ drng->drng_cb->drng_dealloc(drng->drng); ++ kfree(drng); ++ } ++ } ++ kfree(drngs); ++ ++unlock: ++ mutex_unlock(&lrng_crypto_cb_update); ++} ++ ++static DECLARE_WORK(lrng_drngs_numa_alloc_work, _lrng_drngs_numa_alloc); ++ ++static void lrng_drngs_numa_alloc(void) ++{ ++ schedule_work(&lrng_drngs_numa_alloc_work); ++} ++ ++static int __init lrng_numa_init(void) ++{ ++ lrng_drngs_numa_alloc(); ++ return 0; ++} ++ ++late_initcall(lrng_numa_init); +--- a/drivers/char/lrng/lrng_numa.h ++++ b/drivers/char/lrng/lrng_numa.h +@@ -6,6 +6,10 @@ + #ifndef _LRNG_NUMA_H + #define _LRNG_NUMA_H + ++#ifdef CONFIG_NUMA ++struct lrng_drng **lrng_drng_instances(void); ++#else /* CONFIG_NUMA */ + static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; } ++#endif /* CONFIG_NUMA */ + + #endif /* _LRNG_NUMA_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_proc.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_PROC_H ++#define _LRNG_PROC_H ++ ++static inline void lrng_pool_inc_numa_node(void) { } ++ ++#endif /* _LRNG_PROC_H */ diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0003-LRNG-proc-interface.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0003-LRNG-proc-interface.patch new file mode 100644 index 000000000..826bfcf24 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0003-LRNG-proc-interface.patch @@ -0,0 +1,135 @@ +From b97aca849edc371e2586ab0a2f12908910cfa500 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 18 Dec 2022 21:12:42 +0100 +Subject: [PATCH 03/25] LRNG - /proc interface + +The patch adds the file lrng_type which provides details about +the LRNG: + +- the name of the DRNG that produces the random numbers for /dev/random, +/dev/urandom, getrandom(2) + +- the hash used to produce random numbers from the entropy pool + +- the number of secondary DRNG instances + +- indicator whether the LRNG operates SP800-90B compliant + +- indicator whether a high-resolution timer is identified - only with a +high-resolution timer the interrupt noise source will deliver sufficient +entropy + +- indicator whether the LRNG has been minimally seeded (i.e. is the +secondary DRNG seeded with at least 128 bits of entropy) + +- indicator whether the LRNG has been fully seeded (i.e. is the +secondary DRNG seeded with at least 256 bits of entropy) + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_proc.c | 74 +++++++++++++++++++++++++++++++++++ + drivers/char/lrng/lrng_proc.h | 4 ++ + 3 files changed, 79 insertions(+) + create mode 100644 drivers/char/lrng/lrng_proc.c + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -8,6 +8,7 @@ obj-y += lrng_es_mgr.o lrng_drng_mgr + obj-$(CONFIG_LRNG_SHA256) += lrng_sha256.o + obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o + ++obj-$(CONFIG_SYSCTL) += lrng_proc.o + obj-$(CONFIG_NUMA) += lrng_numa.o + + obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_proc.c +@@ -0,0 +1,74 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG proc interfaces ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "lrng_drng_mgr.h" ++#include "lrng_es_aux.h" ++#include "lrng_es_mgr.h" ++#include "lrng_proc.h" ++ ++/* Number of online DRNGs */ ++static u32 numa_drngs = 1; ++ ++void lrng_pool_inc_numa_node(void) ++{ ++ numa_drngs++; ++} ++ ++static int lrng_proc_type_show(struct seq_file *m, void *v) ++{ ++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ unsigned char buf[270]; ++ u32 i; ++ ++ mutex_lock(&lrng_drng_init->lock); ++ snprintf(buf, sizeof(buf), ++ "DRNG name: %s\n" ++ "LRNG security strength in bits: %d\n" ++ "Number of DRNG instances: %u\n" ++ "Standards compliance: %sNTG.1 (2011%s)\n" ++ "LRNG minimally seeded: %s\n" ++ "LRNG fully seeded: %s\n" ++ "LRNG entropy level: %u\n", ++ lrng_drng_init->drng_cb->drng_name(), ++ lrng_security_strength(), ++ numa_drngs, ++ lrng_sp80090c_compliant() ? "SP800-90C, " : "", ++ lrng_ntg1_2022_compliant() ? " / 2022" : "", ++ lrng_state_min_seeded() ? "true" : "false", ++ lrng_state_fully_seeded() ? "true" : "false", ++ lrng_avail_entropy()); ++ seq_write(m, buf, strlen(buf)); ++ ++ for_each_lrng_es(i) { ++ snprintf(buf, sizeof(buf), ++ "Entropy Source %u properties:\n" ++ " Name: %s\n", ++ i, lrng_es[i]->name); ++ seq_write(m, buf, strlen(buf)); ++ ++ buf[0] = '\0'; ++ lrng_es[i]->state(buf, sizeof(buf)); ++ seq_write(m, buf, strlen(buf)); ++ } ++ ++ mutex_unlock(&lrng_drng_init->lock); ++ ++ return 0; ++} ++ ++static int __init lrng_proc_type_init(void) ++{ ++ proc_create_single("lrng_type", 0444, NULL, &lrng_proc_type_show); ++ return 0; ++} ++ ++module_init(lrng_proc_type_init); +--- a/drivers/char/lrng/lrng_proc.h ++++ b/drivers/char/lrng/lrng_proc.h +@@ -6,6 +6,10 @@ + #ifndef _LRNG_PROC_H + #define _LRNG_PROC_H + ++#ifdef CONFIG_SYSCTL ++void lrng_pool_inc_numa_node(void); ++#else + static inline void lrng_pool_inc_numa_node(void) { } ++#endif + + #endif /* _LRNG_PROC_H */ diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch new file mode 100644 index 000000000..1dc9c7d10 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch @@ -0,0 +1,363 @@ +From 074dffdaefb5398b95a733f38aa58c973f918e20 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Mon, 20 Feb 2023 22:02:06 +0100 +Subject: [PATCH 04/25] LRNG - add switchable DRNG support + +The DRNG switch support allows replacing the DRNG mechanism of the +LRNG. The switching support rests on the interface definition of +include/linux/lrng.h. A new DRNG is implemented by filling in the +interface defined in this header file. + +In addition to the DRNG, the extension also has to provide a hash +implementation that is used to hash the entropy pool for random number +extraction. + +Note: It is permissible to implement a DRNG whose operations may sleep. +However, the hash function must not sleep. + +The switchable DRNG support allows replacing the DRNG at runtime. +However, only one DRNG extension is allowed to be loaded at any given +time. Before replacing it with another DRNG implementation, the possibly +existing DRNG extension must be unloaded. + +The switchable DRNG extension activates the new DRNG during load time. +It is expected, however, that such a DRNG switch would be done only once +by an administrator to load the intended DRNG implementation. + +It is permissible to compile DRNG extensions either as kernel modules or +statically. The initialization of the DRNG extension should be performed +with a late_initcall to ensure the extension is available when user +space starts but after all other initialization completed. +The initialization is performed by registering the function call data +structure with the lrng_set_drng_cb function. In order to unload the +DRNG extension, lrng_set_drng_cb must be invoked with the NULL +parameter. + +The DRNG extension should always provide a security strength that is at +least as strong as LRNG_DRNG_SECURITY_STRENGTH_BITS. + +The hash extension must not sleep and must not maintain a separate +state. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 8 +- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_switch.c | 286 ++++++++++++++++++++++++++++++++ + 3 files changed, 291 insertions(+), 4 deletions(-) + create mode 100644 drivers/char/lrng/lrng_switch.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -629,10 +629,10 @@ config LRNG_DRNG_CHACHA20 + # tristate + # depends on CRYPTO + # select CRYPTO_RNG +-# +-# config LRNG_SWITCH +-# bool +-# ++ ++config LRNG_SWITCH ++ bool ++ + # menuconfig LRNG_SWITCH_HASH + # bool "Support conditioning hash runtime switching" + # select LRNG_SWITCH +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -11,4 +11,5 @@ obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o + obj-$(CONFIG_SYSCTL) += lrng_proc.o + obj-$(CONFIG_NUMA) += lrng_numa.o + ++obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o + obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_switch.c +@@ -0,0 +1,286 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG DRNG switching support ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++ ++#include "lrng_es_aux.h" ++#include "lrng_es_mgr.h" ++#include "lrng_interface_dev_common.h" ++#include "lrng_numa.h" ++ ++static int __maybe_unused ++lrng_hash_switch(struct lrng_drng *drng_store, const void *cb, int node) ++{ ++ const struct lrng_hash_cb *new_cb = (const struct lrng_hash_cb *)cb; ++ const struct lrng_hash_cb *old_cb = drng_store->hash_cb; ++ unsigned long flags; ++ u32 i; ++ void *new_hash, *old_hash; ++ int ret; ++ ++ if (node == -1) ++ return 0; ++ ++ new_hash = new_cb->hash_alloc(); ++ old_hash = drng_store->hash; ++ ++ if (IS_ERR(new_hash)) { ++ pr_warn("could not allocate new LRNG pool hash (%ld)\n", ++ PTR_ERR(new_hash)); ++ return PTR_ERR(new_hash); ++ } ++ ++ if (new_cb->hash_digestsize(new_hash) > LRNG_MAX_DIGESTSIZE) { ++ pr_warn("digest size of newly requested hash too large\n"); ++ new_cb->hash_dealloc(new_hash); ++ return -EINVAL; ++ } ++ ++ write_lock_irqsave(&drng_store->hash_lock, flags); ++ ++ /* Trigger the switch for each entropy source */ ++ for_each_lrng_es(i) { ++ if (!lrng_es[i]->switch_hash) ++ continue; ++ ret = lrng_es[i]->switch_hash(drng_store, node, new_cb, ++ new_hash, old_cb); ++ if (ret) { ++ u32 j; ++ ++ /* Revert all already executed operations */ ++ for (j = 0; j < i; j++) { ++ if (!lrng_es[j]->switch_hash) ++ continue; ++ WARN_ON(lrng_es[j]->switch_hash(drng_store, ++ node, old_cb, ++ old_hash, ++ new_cb)); ++ } ++ goto err; ++ } ++ } ++ ++ drng_store->hash = new_hash; ++ drng_store->hash_cb = new_cb; ++ old_cb->hash_dealloc(old_hash); ++ pr_info("Conditioning function allocated for DRNG for NUMA node %d\n", ++ node); ++ ++err: ++ write_unlock_irqrestore(&drng_store->hash_lock, flags); ++ return ret; ++} ++ ++static int __maybe_unused ++lrng_drng_switch(struct lrng_drng *drng_store, const void *cb, int node) ++{ ++ const struct lrng_drng_cb *new_cb = (const struct lrng_drng_cb *)cb; ++ const struct lrng_drng_cb *old_cb = drng_store->drng_cb; ++ int ret; ++ u8 seed[LRNG_DRNG_SECURITY_STRENGTH_BYTES]; ++ void *new_drng = new_cb->drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES); ++ void *old_drng = drng_store->drng; ++ u32 current_security_strength; ++ bool reset_drng = !lrng_get_available(); ++ ++ if (IS_ERR(new_drng)) { ++ pr_warn("could not allocate new DRNG for NUMA node %d (%ld)\n", ++ node, PTR_ERR(new_drng)); ++ return PTR_ERR(new_drng); ++ } ++ ++ current_security_strength = lrng_security_strength(); ++ mutex_lock(&drng_store->lock); ++ ++ /* ++ * Pull from existing DRNG to seed new DRNG regardless of seed status ++ * of old DRNG -- the entropy state for the DRNG is left unchanged which ++ * implies that als the new DRNG is reseeded when deemed necessary. This ++ * seeding of the new DRNG shall only ensure that the new DRNG has the ++ * same entropy as the old DRNG. ++ */ ++ ret = old_cb->drng_generate(old_drng, seed, sizeof(seed)); ++ mutex_unlock(&drng_store->lock); ++ ++ if (ret < 0) { ++ reset_drng = true; ++ pr_warn("getting random data from DRNG failed for NUMA node %d (%d)\n", ++ node, ret); ++ } else { ++ /* seed new DRNG with data */ ++ ret = new_cb->drng_seed(new_drng, seed, ret); ++ memzero_explicit(seed, sizeof(seed)); ++ if (ret < 0) { ++ reset_drng = true; ++ pr_warn("seeding of new DRNG failed for NUMA node %d (%d)\n", ++ node, ret); ++ } else { ++ pr_debug("seeded new DRNG of NUMA node %d instance from old DRNG instance\n", ++ node); ++ } ++ } ++ ++ mutex_lock(&drng_store->lock); ++ ++ if (reset_drng) ++ lrng_drng_reset(drng_store); ++ ++ drng_store->drng = new_drng; ++ drng_store->drng_cb = new_cb; ++ ++ /* Reseed if previous LRNG security strength was insufficient */ ++ if (current_security_strength < lrng_security_strength()) ++ drng_store->force_reseed = true; ++ ++ /* Force oversampling seeding as we initialize DRNG */ ++ if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) ++ lrng_unset_fully_seeded(drng_store); ++ ++ if (lrng_state_min_seeded()) ++ lrng_set_entropy_thresh(lrng_get_seed_entropy_osr( ++ drng_store->fully_seeded)); ++ ++ old_cb->drng_dealloc(old_drng); ++ ++ pr_info("DRNG of NUMA node %d switched\n", node); ++ ++ mutex_unlock(&drng_store->lock); ++ return ret; ++} ++ ++/* ++ * Switch the existing DRNG and hash instances with new using the new crypto ++ * callbacks. The caller must hold the lrng_crypto_cb_update lock. ++ */ ++static int lrng_switch(const void *cb, ++ int (*switcher)(struct lrng_drng *drng_store, ++ const void *cb, int node)) ++{ ++ struct lrng_drng **lrng_drng = lrng_drng_instances(); ++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ struct lrng_drng *lrng_drng_pr = lrng_drng_pr_instance(); ++ int ret = 0; ++ ++ if (lrng_drng) { ++ u32 node; ++ ++ for_each_online_node(node) { ++ if (lrng_drng[node]) ++ ret |= switcher(lrng_drng[node], cb, node); ++ } ++ } else { ++ ret |= switcher(lrng_drng_init, cb, 0); ++ } ++ ++ ret |= switcher(lrng_drng_pr, cb, -1); ++ ++ return ret; ++} ++ ++/* ++ * lrng_set_drng_cb - Register new cryptographic callback functions for DRNG ++ * The registering implies that all old DRNG states are replaced with new ++ * DRNG states. ++ * ++ * drng_cb: Callback functions to be registered -- if NULL, use the default ++ * callbacks defined at compile time. ++ * ++ * Return: ++ * * 0 on success ++ * * < 0 on error ++ */ ++int lrng_set_drng_cb(const struct lrng_drng_cb *drng_cb) ++{ ++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ int ret; ++ ++ if (!IS_ENABLED(CONFIG_LRNG_SWITCH_DRNG)) ++ return -EOPNOTSUPP; ++ ++ if (!drng_cb) ++ drng_cb = lrng_default_drng_cb; ++ ++ mutex_lock(&lrng_crypto_cb_update); ++ ++ /* ++ * If a callback other than the default is set, allow it only to be ++ * set back to the default callback. This ensures that multiple ++ * different callbacks can be registered at the same time. If a ++ * callback different from the current callback and the default ++ * callback shall be set, the current callback must be deregistered ++ * (e.g. the kernel module providing it must be unloaded) and the new ++ * implementation can be registered. ++ */ ++ if ((drng_cb != lrng_default_drng_cb) && ++ (lrng_drng_init->drng_cb != lrng_default_drng_cb)) { ++ pr_warn("disallow setting new DRNG callbacks, unload the old callbacks first!\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ ret = lrng_switch(drng_cb, lrng_drng_switch); ++ /* The switch may imply new entropy due to larger DRNG sec strength. */ ++ if (!ret) ++ lrng_es_add_entropy(); ++ ++out: ++ mutex_unlock(&lrng_crypto_cb_update); ++ return ret; ++} ++EXPORT_SYMBOL(lrng_set_drng_cb); ++ ++/* ++ * lrng_set_hash_cb - Register new cryptographic callback functions for hash ++ * The registering implies that all old hash states are replaced with new ++ * hash states. ++ * ++ * @hash_cb: Callback functions to be registered -- if NULL, use the default ++ * callbacks defined at compile time. ++ * ++ * Return: ++ * * 0 on success ++ * * < 0 on error ++ */ ++int lrng_set_hash_cb(const struct lrng_hash_cb *hash_cb) ++{ ++ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ int ret; ++ ++ if (!IS_ENABLED(CONFIG_LRNG_SWITCH_HASH)) ++ return -EOPNOTSUPP; ++ ++ if (!hash_cb) ++ hash_cb = lrng_default_hash_cb; ++ ++ mutex_lock(&lrng_crypto_cb_update); ++ ++ /* Comment from lrng_set_drng_cb applies. */ ++ if ((hash_cb != lrng_default_hash_cb) && ++ (lrng_drng_init->hash_cb != lrng_default_hash_cb)) { ++ pr_warn("disallow setting new hash callbacks, unload the old callbacks first!\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ ret = lrng_switch(hash_cb, lrng_hash_switch); ++ /* ++ * The switch may imply new entropy due to larger digest size. But ++ * it may also offer more room in the aux pool which means we ping ++ * any waiting entropy providers. ++ */ ++ if (!ret) { ++ lrng_es_add_entropy(); ++ lrng_writer_wakeup(); ++ } ++ ++out: ++ mutex_unlock(&lrng_crypto_cb_update); ++ return ret; ++} ++EXPORT_SYMBOL(lrng_set_hash_cb); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch new file mode 100644 index 000000000..bb3ce8740 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch @@ -0,0 +1,221 @@ +From 6db232ea9ebcca23650d15e3606a8f4d48c09ca1 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 16:01:44 +0200 +Subject: [PATCH 05/25] LRNG - add common generic hash support + +The LRNG switchable DRNG support also allows the replacement of the hash +implementation used as conditioning component. The common generic hash +support code provides the required callbacks using the synchronous hash +implementations of the kernel crypto API. + +All synchronous hash implementations supported by the kernel crypto API +can be used as part of the LRNG with this generic support. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 40 ++++---- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_hash_kcapi.c | 140 ++++++++++++++++++++++++++++ + 3 files changed, 161 insertions(+), 20 deletions(-) + create mode 100644 drivers/char/lrng/lrng_hash_kcapi.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -633,26 +633,26 @@ config LRNG_DRNG_CHACHA20 + config LRNG_SWITCH + bool + +-# menuconfig LRNG_SWITCH_HASH +-# bool "Support conditioning hash runtime switching" +-# select LRNG_SWITCH +-# help +-# The LRNG uses a default message digest. With this +-# configuration option other message digests can be selected +-# and loaded at runtime. +-# +-# if LRNG_SWITCH_HASH +-# +-# config LRNG_HASH_KCAPI +-# tristate "Kernel crypto API hashing support for LRNG" +-# select CRYPTO_HASH +-# select CRYPTO_SHA512 +-# help +-# Enable the kernel crypto API support for entropy compression +-# and conditioning functions. +-# +-# endif # LRNG_SWITCH_HASH +-# ++menuconfig LRNG_SWITCH_HASH ++ bool "Support conditioning hash runtime switching" ++ select LRNG_SWITCH ++ help ++ The LRNG uses a default message digest. With this ++ configuration option other message digests can be selected ++ and loaded at runtime. ++ ++if LRNG_SWITCH_HASH ++ ++config LRNG_HASH_KCAPI ++ tristate "Kernel crypto API hashing support for LRNG" ++ select CRYPTO_HASH ++ select CRYPTO_SHA512 ++ help ++ Enable the kernel crypto API support for entropy compression ++ and conditioning functions. ++ ++endif # LRNG_SWITCH_HASH ++ + # menuconfig LRNG_SWITCH_DRNG + # bool "Support DRNG runtime switching" + # select LRNG_SWITCH +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -12,4 +12,5 @@ obj-$(CONFIG_SYSCTL) += lrng_proc.o + obj-$(CONFIG_NUMA) += lrng_numa.o + + obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o ++obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_hash_kcapi.o + obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_hash_kcapi.c +@@ -0,0 +1,140 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * Backend for providing the hash primitive using the kernel crypto API. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++ ++ ++static char *lrng_hash_name = "sha512"; ++ ++/* The parameter must be r/o in sysfs as otherwise races appear. */ ++module_param(lrng_hash_name, charp, 0444); ++MODULE_PARM_DESC(lrng_hash_name, "Kernel crypto API hash name"); ++ ++struct lrng_hash_info { ++ struct crypto_shash *tfm; ++}; ++ ++static const char *lrng_kcapi_hash_name(void) ++{ ++ return lrng_hash_name; ++} ++ ++static void _lrng_kcapi_hash_free(struct lrng_hash_info *lrng_hash) ++{ ++ struct crypto_shash *tfm = lrng_hash->tfm; ++ ++ crypto_free_shash(tfm); ++ kfree(lrng_hash); ++} ++ ++static void *lrng_kcapi_hash_alloc(const char *name) ++{ ++ struct lrng_hash_info *lrng_hash; ++ struct crypto_shash *tfm; ++ int ret; ++ ++ if (!name) { ++ pr_err("Hash name missing\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ tfm = crypto_alloc_shash(name, 0, 0); ++ if (IS_ERR(tfm)) { ++ pr_err("could not allocate hash %s\n", name); ++ return ERR_CAST(tfm); ++ } ++ ++ ret = sizeof(struct lrng_hash_info); ++ lrng_hash = kmalloc(ret, GFP_KERNEL); ++ if (!lrng_hash) { ++ crypto_free_shash(tfm); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ lrng_hash->tfm = tfm; ++ ++ pr_info("Hash %s allocated\n", name); ++ ++ return lrng_hash; ++} ++ ++static void *lrng_kcapi_hash_name_alloc(void) ++{ ++ return lrng_kcapi_hash_alloc(lrng_kcapi_hash_name()); ++} ++ ++static u32 lrng_kcapi_hash_digestsize(void *hash) ++{ ++ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; ++ struct crypto_shash *tfm = lrng_hash->tfm; ++ ++ return crypto_shash_digestsize(tfm); ++} ++ ++static void lrng_kcapi_hash_dealloc(void *hash) ++{ ++ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; ++ ++ _lrng_kcapi_hash_free(lrng_hash); ++ pr_info("Hash deallocated\n"); ++} ++ ++static int lrng_kcapi_hash_init(struct shash_desc *shash, void *hash) ++{ ++ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; ++ struct crypto_shash *tfm = lrng_hash->tfm; ++ ++ shash->tfm = tfm; ++ return crypto_shash_init(shash); ++} ++ ++static int lrng_kcapi_hash_update(struct shash_desc *shash, const u8 *inbuf, ++ u32 inbuflen) ++{ ++ return crypto_shash_update(shash, inbuf, inbuflen); ++} ++ ++static int lrng_kcapi_hash_final(struct shash_desc *shash, u8 *digest) ++{ ++ return crypto_shash_final(shash, digest); ++} ++ ++static void lrng_kcapi_hash_zero(struct shash_desc *shash) ++{ ++ shash_desc_zero(shash); ++} ++ ++static const struct lrng_hash_cb lrng_kcapi_hash_cb = { ++ .hash_name = lrng_kcapi_hash_name, ++ .hash_alloc = lrng_kcapi_hash_name_alloc, ++ .hash_dealloc = lrng_kcapi_hash_dealloc, ++ .hash_digestsize = lrng_kcapi_hash_digestsize, ++ .hash_init = lrng_kcapi_hash_init, ++ .hash_update = lrng_kcapi_hash_update, ++ .hash_final = lrng_kcapi_hash_final, ++ .hash_desc_zero = lrng_kcapi_hash_zero, ++}; ++ ++static int __init lrng_kcapi_init(void) ++{ ++ return lrng_set_hash_cb(&lrng_kcapi_hash_cb); ++} ++ ++static void __exit lrng_kcapi_exit(void) ++{ ++ lrng_set_hash_cb(NULL); ++} ++ ++late_initcall(lrng_kcapi_init); ++module_exit(lrng_kcapi_exit); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Stephan Mueller "); ++MODULE_DESCRIPTION("Entropy Source and DRNG Manager - Kernel crypto API hash backend"); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch new file mode 100644 index 000000000..0ce584cb5 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch @@ -0,0 +1,114 @@ +From b59bd03bfd2776058531dc6f9573a0e0a46a23d2 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Thu, 21 Mar 2024 14:17:33 +0100 +Subject: [PATCH 06/25] crypto: DRBG - externalize DRBG functions for LRNG + +This patch allows several DRBG functions to be called by the LRNG kernel +code paths outside the drbg.c file. + +Signed-off-by: Stephan Mueller +--- + crypto/drbg.c | 16 ++++++++++------ + include/crypto/drbg.h | 7 +++++++ + 2 files changed, 17 insertions(+), 6 deletions(-) + +--- a/crypto/drbg.c ++++ b/crypto/drbg.c +@@ -115,7 +115,7 @@ + * HMAC-SHA512 / SHA256 / AES 256 over other ciphers. Thus, the + * favored DRBGs are the latest entries in this array. + */ +-static const struct drbg_core drbg_cores[] = { ++const struct drbg_core drbg_cores[] = { + #ifdef CONFIG_CRYPTO_DRBG_CTR + { + .flags = DRBG_CTR | DRBG_STRENGTH128, +@@ -180,6 +180,7 @@ static const struct drbg_core drbg_cores + }, + #endif /* CONFIG_CRYPTO_DRBG_HMAC */ + }; ++EXPORT_SYMBOL(drbg_cores); + + static int drbg_uninstantiate(struct drbg_state *drbg); + +@@ -195,7 +196,7 @@ static int drbg_uninstantiate(struct drb + * Return: normalized strength in *bytes* value or 32 as default + * to counter programming errors + */ +-static inline unsigned short drbg_sec_strength(drbg_flag_t flags) ++unsigned short drbg_sec_strength(drbg_flag_t flags) + { + switch (flags & DRBG_STRENGTH_MASK) { + case DRBG_STRENGTH128: +@@ -208,6 +209,7 @@ static inline unsigned short drbg_sec_st + return 32; + } + } ++EXPORT_SYMBOL(drbg_sec_strength); + + /* + * FIPS 140-2 continuous self test for the noise source +@@ -1236,7 +1238,7 @@ out: + } + + /* Free all substructures in a DRBG state without the DRBG state structure */ +-static inline void drbg_dealloc_state(struct drbg_state *drbg) ++void drbg_dealloc_state(struct drbg_state *drbg) + { + if (!drbg) + return; +@@ -1257,12 +1259,13 @@ static inline void drbg_dealloc_state(st + drbg->fips_primed = false; + } + } ++EXPORT_SYMBOL(drbg_dealloc_state); + + /* + * Allocate all sub-structures for a DRBG state. + * The DRBG state structure must already be allocated. + */ +-static inline int drbg_alloc_state(struct drbg_state *drbg) ++int drbg_alloc_state(struct drbg_state *drbg) + { + int ret = -ENOMEM; + unsigned int sb_size = 0; +@@ -1343,6 +1346,7 @@ err: + drbg_dealloc_state(drbg); + return ret; + } ++EXPORT_SYMBOL(drbg_alloc_state); + + /************************************************************************* + * DRBG interface functions +@@ -1877,8 +1881,7 @@ out: + * + * return: flags + */ +-static inline void drbg_convert_tfm_core(const char *cra_driver_name, +- int *coreref, bool *pr) ++void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, bool *pr) + { + int i = 0; + size_t start = 0; +@@ -1905,6 +1908,7 @@ static inline void drbg_convert_tfm_core + } + } + } ++EXPORT_SYMBOL(drbg_convert_tfm_core); + + static int drbg_kcapi_init(struct crypto_tfm *tfm) + { +--- a/include/crypto/drbg.h ++++ b/include/crypto/drbg.h +@@ -283,4 +283,11 @@ enum drbg_prefixes { + DRBG_PREFIX3 + }; + ++extern int drbg_alloc_state(struct drbg_state *drbg); ++extern void drbg_dealloc_state(struct drbg_state *drbg); ++extern void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, ++ bool *pr); ++extern const struct drbg_core drbg_cores[]; ++extern unsigned short drbg_sec_strength(drbg_flag_t flags); ++ + #endif /* _DRBG_H */ diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch new file mode 100644 index 000000000..b1c024ae4 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch @@ -0,0 +1,363 @@ +From ed6c12a2aeac7927392151adcbf947c3c0865988 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 28 Jul 2024 21:39:01 +0200 +Subject: [PATCH 07/25] LRNG - add SP800-90A DRBG extension + +Using the LRNG switchable DRNG support, the SP800-90A DRBG extension is +implemented. + +The DRBG uses the kernel crypto API DRBG implementation. In addition, it +uses the kernel crypto API SHASH support to provide the hashing +operation. + +The DRBG supports the choice of either a CTR DRBG using AES-256, HMAC +DRBG with SHA-512 core or Hash DRBG with SHA-512 core. The used core can +be selected with the module parameter lrng_drbg_type. The default is the +CTR DRBG. + +When compiling the DRBG extension statically, the DRBG is loaded at +late_initcall stage which implies that with the start of user space, the +user space interfaces of getrandom(2), /dev/random and /dev/urandom +provide random data produced by an SP800-90A DRBG. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 78 +++++------ + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_drng_drbg.c | 215 +++++++++++++++++++++++++++++ + 3 files changed, 255 insertions(+), 39 deletions(-) + create mode 100644 drivers/char/lrng/lrng_drng_drbg.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -620,11 +620,11 @@ endmenu # "Specific DRNG seeding strateg + config LRNG_DRNG_CHACHA20 + tristate + +-# config LRNG_DRBG +-# tristate +-# depends on CRYPTO +-# select CRYPTO_DRBG_MENU +-# ++config LRNG_DRBG ++ tristate ++ depends on CRYPTO ++ select CRYPTO_DRBG_MENU ++ + # config LRNG_DRNG_KCAPI + # tristate + # depends on CRYPTO +@@ -653,33 +653,33 @@ config LRNG_HASH_KCAPI + + endif # LRNG_SWITCH_HASH + +-# menuconfig LRNG_SWITCH_DRNG +-# bool "Support DRNG runtime switching" +-# select LRNG_SWITCH +-# help +-# The LRNG uses a default DRNG With this configuration +-# option other DRNGs or message digests can be selected and +-# loaded at runtime. +-# +-# if LRNG_SWITCH_DRNG +-# +-# config LRNG_SWITCH_DRNG_CHACHA20 +-# tristate "ChaCha20-based DRNG support for LRNG" +-# depends on !LRNG_DFLT_DRNG_CHACHA20 +-# select LRNG_DRNG_CHACHA20 +-# help +-# Enable the ChaCha20-based DRNG. This DRNG implementation +-# does not depend on the kernel crypto API presence. +-# +-# config LRNG_SWITCH_DRBG +-# tristate "SP800-90A support for the LRNG" +-# depends on !LRNG_DFLT_DRNG_DRBG +-# select LRNG_DRBG +-# help +-# Enable the SP800-90A DRBG support for the LRNG. Once the +-# module is loaded, output from /dev/random, /dev/urandom, +-# getrandom(2), or get_random_bytes_full is provided by a DRBG. +-# ++menuconfig LRNG_SWITCH_DRNG ++ bool "Support DRNG runtime switching" ++ select LRNG_SWITCH ++ help ++ The LRNG uses a default DRNG With this configuration ++ option other DRNGs or message digests can be selected and ++ loaded at runtime. ++ ++if LRNG_SWITCH_DRNG ++ ++config LRNG_SWITCH_DRNG_CHACHA20 ++ tristate "ChaCha20-based DRNG support for LRNG" ++ depends on !LRNG_DFLT_DRNG_CHACHA20 ++ select LRNG_DRNG_CHACHA20 ++ help ++ Enable the ChaCha20-based DRNG. This DRNG implementation ++ does not depend on the kernel crypto API presence. ++ ++config LRNG_SWITCH_DRBG ++ tristate "SP800-90A support for the LRNG" ++ depends on !LRNG_DFLT_DRNG_DRBG ++ select LRNG_DRBG ++ help ++ Enable the SP800-90A DRBG support for the LRNG. Once the ++ module is loaded, output from /dev/random, /dev/urandom, ++ getrandom(2), or get_random_bytes_full is provided by a DRBG. ++ + # config LRNG_SWITCH_DRNG_KCAPI + # tristate "Kernel Crypto API support for the LRNG" + # depends on !LRNG_DFLT_DRNG_KCAPI +@@ -691,8 +691,8 @@ endif # LRNG_SWITCH_HASH + # LRNG. Once the module is loaded, output from /dev/random, + # /dev/urandom, getrandom(2), or get_random_bytes is + # provided by the selected kernel crypto API RNG. +-# +-# endif # LRNG_SWITCH_DRNG ++ ++endif # LRNG_SWITCH_DRNG + + choice + prompt "LRNG Default DRNG" +@@ -707,11 +707,11 @@ choice + bool "ChaCha20-based DRNG" + select LRNG_DRNG_CHACHA20 + +-# config LRNG_DFLT_DRNG_DRBG +-# depends on RANDOM_DEFAULT_IMPL +-# bool "SP800-90A DRBG" +-# select LRNG_DRBG +-# ++ config LRNG_DFLT_DRNG_DRBG ++ depends on RANDOM_DEFAULT_IMPL ++ bool "SP800-90A DRBG" ++ select LRNG_DRBG ++ + # config LRNG_DFLT_DRNG_KCAPI + # depends on RANDOM_DEFAULT_IMPL + # bool "Kernel Crypto API DRNG" +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -14,3 +14,4 @@ obj-$(CONFIG_NUMA) += lrng_numa.o + obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o + obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_hash_kcapi.o + obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o ++obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_drbg.c +@@ -0,0 +1,215 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * Backend for the LRNG providing the cryptographic primitives using the ++ * kernel crypto API and its DRBG. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++ ++#include "lrng_drng_drbg.h" ++ ++/* ++ * Define a DRBG plus a hash / MAC used to extract data from the entropy pool. ++ * For LRNG_HASH_NAME you can use a hash or a MAC (HMAC or CMAC) of your choice ++ * (Note, you should use the suggested selections below -- using SHA-1 or MD5 ++ * is not wise). The idea is that the used cipher primitive can be selected to ++ * be the same as used for the DRBG. I.e. the LRNG only uses one cipher ++ * primitive using the same cipher implementation with the options offered in ++ * the following. This means, if the CTR DRBG is selected and AES-NI is present, ++ * both the CTR DRBG and the selected cmac(aes) use AES-NI. ++ * ++ * The security strengths of the DRBGs are all 256 bits according to ++ * SP800-57 section 5.6.1. ++ * ++ * This definition is allowed to be changed. ++ */ ++#ifdef CONFIG_CRYPTO_DRBG_CTR ++static unsigned int lrng_drbg_type = 0; ++#elif defined CONFIG_CRYPTO_DRBG_HMAC ++static unsigned int lrng_drbg_type = 1; ++#elif defined CONFIG_CRYPTO_DRBG_HASH ++static unsigned int lrng_drbg_type = 2; ++#else ++#error "Unknown DRBG in use" ++#endif ++ ++/* The parameter must be r/o in sysfs as otherwise races appear. */ ++module_param(lrng_drbg_type, uint, 0444); ++MODULE_PARM_DESC(lrng_drbg_type, "DRBG type used for LRNG (0->CTR_DRBG, 1->HMAC_DRBG, 2->Hash_DRBG)"); ++ ++struct lrng_drbg { ++ const char* hash_name; ++ const char* drbg_core; ++}; ++ ++static const struct lrng_drbg lrng_drbg_types[] = { ++ { ++ /* CTR_DRBG with AES-256 using derivation function */ ++ .drbg_core = "drbg_nopr_ctr_aes256", ++ }, { ++ /* HMAC_DRBG with SHA-512 */ ++ .drbg_core = "drbg_nopr_hmac_sha512", ++ }, { ++ /* Hash_DRBG with SHA-512 using derivation function */ ++ .drbg_core = "drbg_nopr_sha512" ++ } ++}; ++ ++static int lrng_drbg_drng_seed_helper(void* drng, const u8* inbuf, u32 inbuflen) ++{ ++ struct drbg_state* drbg = (struct drbg_state*)drng; ++ LIST_HEAD(seedlist); ++ struct drbg_string data; ++ int ret; ++ ++ drbg_string_fill(&data, inbuf, inbuflen); ++ list_add_tail(&data.list, &seedlist); ++ ret = drbg->d_ops->update(drbg, &seedlist, drbg->seeded); ++ ++ if (ret >= 0) ++ drbg->seeded = DRBG_SEED_STATE_FULL; ++ ++ return ret; ++} ++ ++static int lrng_drbg_drng_generate_helper(void* drng, u8* outbuf, u32 outbuflen) ++{ ++ struct drbg_state* drbg = (struct drbg_state*)drng; ++ ++ return drbg->d_ops->generate(drbg, outbuf, outbuflen, NULL); ++} ++ ++static void* lrng_drbg_drng_alloc(u32 sec_strength) ++{ ++ struct drbg_state* drbg; ++ int coreref = -1; ++ bool pr = false; ++ int ret; ++ ++ drbg_convert_tfm_core(lrng_drbg_types[lrng_drbg_type].drbg_core, ++ &coreref, &pr); ++ if (coreref < 0) ++ return ERR_PTR(-EFAULT); ++ ++ drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); ++ if (!drbg) ++ return ERR_PTR(-ENOMEM); ++ ++ drbg->core = &drbg_cores[coreref]; ++ drbg->seeded = DRBG_SEED_STATE_UNSEEDED; ++ ret = drbg_alloc_state(drbg); ++ if (ret) ++ goto err; ++ ++ if (sec_strength > drbg_sec_strength(drbg->core->flags)) { ++ pr_err("Security strength of DRBG (%u bits) lower than requested by LRNG (%u bits)\n", ++ drbg_sec_strength(drbg->core->flags) * 8, ++ sec_strength * 8); ++ goto dealloc; ++ } ++ ++ if (sec_strength < drbg_sec_strength(drbg->core->flags)) ++ pr_warn("Security strength of DRBG (%u bits) higher than requested by LRNG (%u bits)\n", ++ drbg_sec_strength(drbg->core->flags) * 8, ++ sec_strength * 8); ++ ++ pr_info("DRBG with %s core allocated\n", drbg->core->backend_cra_name); ++ ++ return drbg; ++ ++ dealloc: ++ if (drbg->d_ops) ++ drbg->d_ops->crypto_fini(drbg); ++ drbg_dealloc_state(drbg); ++ err: ++ kfree(drbg); ++ return ERR_PTR(-EINVAL); ++} ++ ++static void lrng_drbg_drng_dealloc(void* drng) ++{ ++ struct drbg_state* drbg = (struct drbg_state*)drng; ++ ++ if (drbg && drbg->d_ops) ++ drbg->d_ops->crypto_fini(drbg); ++ drbg_dealloc_state(drbg); ++ kfree_sensitive(drbg); ++ pr_info("DRBG deallocated\n"); ++} ++ ++static const char* lrng_drbg_name(void) ++{ ++ return lrng_drbg_types[lrng_drbg_type].drbg_core; ++} ++ ++const struct lrng_drng_cb lrng_drbg_cb = { ++ .drng_name = lrng_drbg_name, ++ .drng_alloc = lrng_drbg_drng_alloc, ++ .drng_dealloc = lrng_drbg_drng_dealloc, ++ .drng_seed = lrng_drbg_drng_seed_helper, ++ .drng_generate = lrng_drbg_drng_generate_helper, ++}; ++ ++static int __init lrng_drbg_selftest(void) ++{ ++ struct crypto_rng *drbg; ++ ++ /* Allocate the DRBG once to trigger the kernel crypto API self test */ ++ drbg = crypto_alloc_rng(lrng_drbg_types[lrng_drbg_type].drbg_core, 0, ++ 0); ++ if (IS_ERR(drbg)) { ++ pr_err("could not allocate DRBG and trigger self-test: %ld\n", ++ PTR_ERR(drbg)); ++ return PTR_ERR(drbg); ++ } ++ crypto_free_rng(drbg); ++ ++ return 0; ++} ++ ++#ifndef CONFIG_LRNG_DFLT_DRNG_DRBG ++static int __init lrng_drbg_init(void) ++{ ++ int ret = lrng_drbg_selftest(); ++ ++ if (ret) ++ return ret; ++ ++ if (lrng_drbg_type >= ARRAY_SIZE(lrng_drbg_types)) { ++ pr_err("lrng_drbg_type parameter too large (given %u - max: %lu)", ++ lrng_drbg_type, ++ (unsigned long)ARRAY_SIZE(lrng_drbg_types) - 1); ++ return -EAGAIN; ++ } ++ return lrng_set_drng_cb(&lrng_drbg_cb); ++} ++ ++static void __exit lrng_drbg_exit(void) ++{ ++ lrng_set_drng_cb(NULL); ++} ++ ++late_initcall(lrng_drbg_init); ++module_exit(lrng_drbg_exit); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Stephan Mueller "); ++MODULE_DESCRIPTION("Entropy Source and DRNG Manager - SP800-90A DRBG backend"); ++#else ++ ++/* ++ * Note, this call may result in the use of the DRBG before the self-test is ++ * run. However, that usage is not relevant to any FIPS-140 consideration as ++ * the data is used for non-cryptographic purposes. The call below guarantees ++ * that the self-tests are run before user space is started and thus callers ++ * with needs to comply with FIPS-140 appear. ++ */ ++late_initcall(lrng_drbg_selftest); ++ ++#endif /* CONFIG_LRNG_DFLT_DRNG_DRBG */ diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch new file mode 100644 index 000000000..6632e2ff8 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch @@ -0,0 +1,305 @@ +From abd4e08622156956150d80bf4e8cd4b4c31113ef Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Mon, 20 Feb 2023 22:23:59 +0100 +Subject: [PATCH 08/25] LRNG - add kernel crypto API PRNG extension + +Add runtime-pluggable support for all PRNGs that are accessible via +the kernel crypto API, including hardware PRNGs. The PRNG is selected +with the module parameter drng_name where the name must be one that the +kernel crypto API can resolve into an RNG. + +This allows using of the kernel crypto API PRNG implementations that +provide an interface to hardware PRNGs. Using this extension, +the LRNG uses the hardware PRNGs to generate random numbers. An +example is the S390 CPACF support providing such a PRNG. + +The hash is provided by a kernel crypto API SHASH whose digest size +complies with the seedsize of the PRNG. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 38 ++--- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_drng_kcapi.c | 208 ++++++++++++++++++++++++++++ + 3 files changed, 228 insertions(+), 19 deletions(-) + create mode 100644 drivers/char/lrng/lrng_drng_kcapi.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -625,10 +625,10 @@ config LRNG_DRBG + depends on CRYPTO + select CRYPTO_DRBG_MENU + +-# config LRNG_DRNG_KCAPI +-# tristate +-# depends on CRYPTO +-# select CRYPTO_RNG ++config LRNG_DRNG_KCAPI ++ tristate ++ depends on CRYPTO ++ select CRYPTO_RNG + + config LRNG_SWITCH + bool +@@ -680,17 +680,17 @@ config LRNG_SWITCH_DRBG + module is loaded, output from /dev/random, /dev/urandom, + getrandom(2), or get_random_bytes_full is provided by a DRBG. + +-# config LRNG_SWITCH_DRNG_KCAPI +-# tristate "Kernel Crypto API support for the LRNG" +-# depends on !LRNG_DFLT_DRNG_KCAPI +-# depends on !LRNG_SWITCH_DRBG +-# select LRNG_DRNG_KCAPI +-# help +-# Enable the support for generic pseudo-random number +-# generators offered by the kernel crypto API with the +-# LRNG. Once the module is loaded, output from /dev/random, +-# /dev/urandom, getrandom(2), or get_random_bytes is +-# provided by the selected kernel crypto API RNG. ++config LRNG_SWITCH_DRNG_KCAPI ++ tristate "Kernel Crypto API support for the LRNG" ++ depends on !LRNG_DFLT_DRNG_KCAPI ++ depends on !LRNG_SWITCH_DRBG ++ select LRNG_DRNG_KCAPI ++ help ++ Enable the support for generic pseudo-random number ++ generators offered by the kernel crypto API with the ++ LRNG. Once the module is loaded, output from /dev/random, ++ /dev/urandom, getrandom(2), or get_random_bytes is ++ provided by the selected kernel crypto API RNG. + + endif # LRNG_SWITCH_DRNG + +@@ -712,10 +712,10 @@ choice + bool "SP800-90A DRBG" + select LRNG_DRBG + +-# config LRNG_DFLT_DRNG_KCAPI +-# depends on RANDOM_DEFAULT_IMPL +-# bool "Kernel Crypto API DRNG" +-# select LRNG_DRNG_KCAPI ++ config LRNG_DFLT_DRNG_KCAPI ++ depends on RANDOM_DEFAULT_IMPL ++ bool "Kernel Crypto API DRNG" ++ select LRNG_DRNG_KCAPI + endchoice + + # menuconfig LRNG_TESTING_MENU +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -15,3 +15,4 @@ obj-$(CONFIG_LRNG_SWITCH) += lrng_switc + obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_hash_kcapi.o + obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o + obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o ++obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_drng_kcapi.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_kcapi.c +@@ -0,0 +1,208 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * Backend for the LRNG providing the cryptographic primitives using the ++ * kernel crypto API. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_drng_kcapi.h" ++ ++static char *drng_name = NULL; ++module_param(drng_name, charp, 0444); ++MODULE_PARM_DESC(drng_name, "Kernel crypto API name of DRNG"); ++ ++static char *seed_hash = NULL; ++module_param(seed_hash, charp, 0444); ++MODULE_PARM_DESC(seed_hash, ++ "Kernel crypto API name of hash with output size equal to seedsize of DRNG to bring seed string to the size required by the DRNG"); ++ ++struct lrng_drng_info { ++ struct crypto_rng *kcapi_rng; ++ struct crypto_shash *hash_tfm; ++}; ++ ++static int lrng_kcapi_drng_seed_helper(void *drng, const u8 *inbuf, ++ u32 inbuflen) ++{ ++ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng; ++ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; ++ struct crypto_shash *hash_tfm = lrng_drng_info->hash_tfm; ++ SHASH_DESC_ON_STACK(shash, hash_tfm); ++ u32 digestsize; ++ u8 digest[HASH_MAX_DIGESTSIZE] __aligned(8); ++ int ret; ++ ++ if (!hash_tfm) ++ return crypto_rng_reset(kcapi_rng, inbuf, inbuflen); ++ ++ shash->tfm = hash_tfm; ++ digestsize = crypto_shash_digestsize(hash_tfm); ++ ++ ret = crypto_shash_digest(shash, inbuf, inbuflen, digest); ++ shash_desc_zero(shash); ++ if (ret) ++ return ret; ++ ++ ret = crypto_rng_reset(kcapi_rng, digest, digestsize); ++ if (ret) ++ return ret; ++ ++ memzero_explicit(digest, digestsize); ++ return 0; ++} ++ ++static int lrng_kcapi_drng_generate_helper(void *drng, u8 *outbuf, ++ u32 outbuflen) ++{ ++ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng; ++ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; ++ int ret = crypto_rng_get_bytes(kcapi_rng, outbuf, outbuflen); ++ ++ if (ret < 0) ++ return ret; ++ ++ return outbuflen; ++} ++ ++static void *lrng_kcapi_drng_alloc(u32 sec_strength) ++{ ++ struct lrng_drng_info *lrng_drng_info; ++ struct crypto_rng *kcapi_rng; ++ u32 time = random_get_entropy(); ++ int seedsize, rv; ++ void *ret = ERR_PTR(-ENOMEM); ++ ++ if (!drng_name) { ++ pr_err("DRNG name missing\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (!memcmp(drng_name, "stdrng", 6) || ++ !memcmp(drng_name, "lrng", 4) || ++ !memcmp(drng_name, "drbg", 4) || ++ !memcmp(drng_name, "jitterentropy_rng", 17)) { ++ pr_err("Refusing to load the requested random number generator\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ lrng_drng_info = kzalloc(sizeof(*lrng_drng_info), GFP_KERNEL); ++ if (!lrng_drng_info) ++ return ERR_PTR(-ENOMEM); ++ ++ kcapi_rng = crypto_alloc_rng(drng_name, 0, 0); ++ if (IS_ERR(kcapi_rng)) { ++ pr_err("DRNG %s cannot be allocated\n", drng_name); ++ ret = ERR_CAST(kcapi_rng); ++ goto free; ++ } ++ ++ lrng_drng_info->kcapi_rng = kcapi_rng; ++ ++ seedsize = crypto_rng_seedsize(kcapi_rng); ++ if (seedsize) { ++ struct crypto_shash *hash_tfm; ++ ++ if (!seed_hash) { ++ switch (seedsize) { ++ case 32: ++ seed_hash = "sha256"; ++ break; ++ case 48: ++ seed_hash = "sha384"; ++ break; ++ case 64: ++ seed_hash = "sha512"; ++ break; ++ default: ++ pr_err("Seed size %d cannot be processed\n", ++ seedsize); ++ goto dealloc; ++ } ++ } ++ ++ hash_tfm = crypto_alloc_shash(seed_hash, 0, 0); ++ if (IS_ERR(hash_tfm)) { ++ ret = ERR_CAST(hash_tfm); ++ goto dealloc; ++ } ++ ++ if (seedsize != crypto_shash_digestsize(hash_tfm)) { ++ pr_err("Seed hash output size not equal to DRNG seed size\n"); ++ crypto_free_shash(hash_tfm); ++ ret = ERR_PTR(-EINVAL); ++ goto dealloc; ++ } ++ ++ lrng_drng_info->hash_tfm = hash_tfm; ++ ++ pr_info("Seed hash %s allocated\n", seed_hash); ++ } ++ ++ rv = lrng_kcapi_drng_seed_helper(lrng_drng_info, (u8 *)(&time), ++ sizeof(time)); ++ if (rv) { ++ ret = ERR_PTR(rv); ++ goto dealloc; ++ } ++ ++ pr_info("Kernel crypto API DRNG %s allocated\n", drng_name); ++ ++ return lrng_drng_info; ++ ++dealloc: ++ crypto_free_rng(kcapi_rng); ++free: ++ kfree(lrng_drng_info); ++ return ret; ++} ++ ++static void lrng_kcapi_drng_dealloc(void *drng) ++{ ++ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng; ++ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; ++ ++ crypto_free_rng(kcapi_rng); ++ if (lrng_drng_info->hash_tfm) ++ crypto_free_shash(lrng_drng_info->hash_tfm); ++ kfree(lrng_drng_info); ++ pr_info("DRNG %s deallocated\n", drng_name); ++} ++ ++static const char *lrng_kcapi_drng_name(void) ++{ ++ return drng_name; ++} ++ ++const struct lrng_drng_cb lrng_kcapi_drng_cb = { ++ .drng_name = lrng_kcapi_drng_name, ++ .drng_alloc = lrng_kcapi_drng_alloc, ++ .drng_dealloc = lrng_kcapi_drng_dealloc, ++ .drng_seed = lrng_kcapi_drng_seed_helper, ++ .drng_generate = lrng_kcapi_drng_generate_helper, ++}; ++ ++#ifndef CONFIG_LRNG_DFLT_DRNG_KCAPI ++static int __init lrng_kcapi_init(void) ++{ ++ return lrng_set_drng_cb(&lrng_kcapi_drng_cb); ++} ++static void __exit lrng_kcapi_exit(void) ++{ ++ lrng_set_drng_cb(NULL); ++} ++ ++late_initcall(lrng_kcapi_init); ++module_exit(lrng_kcapi_exit); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Stephan Mueller "); ++MODULE_DESCRIPTION("Entropy Source and DRNG Manager - kernel crypto API DRNG backend"); ++#endif /* CONFIG_LRNG_DFLT_DRNG_KCAPI */ diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch new file mode 100644 index 000000000..76dd6ec1a --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch @@ -0,0 +1,159 @@ +From 44fd5618cd312625394fc2cd0861b2ab44068148 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Mon, 20 Feb 2023 22:05:24 +0100 +Subject: [PATCH 09/25] LRNG - add atomic DRNG implementation + +The atomic DRNG implementation supports the in-kernel use cases which +request random numbers in atomic contexts. It uses the ChaCha20 DRNG +which is a code base that does not sleep and it provides an interface to +callers that does not sleep. This code will only be compiled when the +LRNG enables the in-kernel drop-in replacement APIs for the existing +random.c code base. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_drng_atomic.c | 130 +++++++++++++++++++++++++++ + 2 files changed, 131 insertions(+) + create mode 100644 drivers/char/lrng/lrng_drng_atomic.c + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_h + obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o + obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o + obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_drng_kcapi.o ++obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_drng_atomic.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_drng_atomic.c +@@ -0,0 +1,130 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG DRNG for atomic contexts ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++ ++#include "lrng_drng_atomic.h" ++#include "lrng_drng_chacha20.h" ++#include "lrng_es_aux.h" ++#include "lrng_es_mgr.h" ++#include "lrng_sha.h" ++ ++static struct chacha20_state chacha20_atomic = { ++ LRNG_CC20_INIT_RFC7539(.block) ++}; ++ ++/* ++ * DRNG usable in atomic context. This DRNG will always use the ChaCha20 ++ * DRNG. It will never benefit from a DRNG switch like the "regular" DRNG. If ++ * there was no DRNG switch, the atomic DRNG is identical to the "regular" DRNG. ++ * ++ * The reason for having this is due to the fact that DRNGs other than ++ * the ChaCha20 DRNG may sleep. ++ */ ++static struct lrng_drng lrng_drng_atomic = { ++ LRNG_DRNG_STATE_INIT(lrng_drng_atomic, ++ &chacha20_atomic, NULL, ++ &lrng_cc20_drng_cb, &lrng_sha_hash_cb), ++ .spin_lock = __SPIN_LOCK_UNLOCKED(lrng_drng_atomic.spin_lock) ++}; ++ ++struct lrng_drng *lrng_get_atomic(void) ++{ ++ return &lrng_drng_atomic; ++} ++ ++void lrng_drng_atomic_reset(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lrng_drng_atomic.spin_lock, flags); ++ lrng_drng_reset(&lrng_drng_atomic); ++ spin_unlock_irqrestore(&lrng_drng_atomic.spin_lock, flags); ++} ++ ++void lrng_drng_atomic_force_reseed(void) ++{ ++ lrng_drng_atomic.force_reseed = lrng_drng_atomic.fully_seeded; ++} ++ ++static bool lrng_drng_atomic_must_reseed(struct lrng_drng *drng) ++{ ++ return (!drng->fully_seeded || ++ atomic_read(&lrng_drng_atomic.requests) == 0 || ++ drng->force_reseed || ++ time_after(jiffies, ++ drng->last_seeded + lrng_drng_reseed_max_time * HZ)); ++} ++ ++void lrng_drng_atomic_seed_drng(struct lrng_drng *regular_drng) ++{ ++ u8 seedbuf[LRNG_DRNG_SECURITY_STRENGTH_BYTES] ++ __aligned(LRNG_KCAPI_ALIGN); ++ int ret; ++ ++ if (!lrng_drng_atomic_must_reseed(&lrng_drng_atomic)) ++ return; ++ ++ /* ++ * Reseed atomic DRNG another DRNG "regular" while this regular DRNG ++ * is reseeded. Therefore, this code operates in non-atomic context and ++ * thus can use the lrng_drng_get function to get random numbers from ++ * the just freshly seeded DRNG. ++ */ ++ ret = lrng_drng_get(regular_drng, seedbuf, sizeof(seedbuf)); ++ ++ if (ret < 0) { ++ pr_warn("Error generating random numbers for atomic DRNG: %d\n", ++ ret); ++ } else { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lrng_drng_atomic.spin_lock, flags); ++ lrng_drng_inject(&lrng_drng_atomic, seedbuf, ret, ++ regular_drng->fully_seeded, "atomic"); ++ spin_unlock_irqrestore(&lrng_drng_atomic.spin_lock, flags); ++ } ++ memzero_explicit(&seedbuf, sizeof(seedbuf)); ++} ++ ++static void lrng_drng_atomic_get(u8 *outbuf, u32 outbuflen) ++{ ++ struct lrng_drng *drng = &lrng_drng_atomic; ++ unsigned long flags; ++ ++ if (!outbuf || !outbuflen) ++ return; ++ ++ outbuflen = min_t(size_t, outbuflen, INT_MAX); ++ ++ while (outbuflen) { ++ u32 todo = min_t(u32, outbuflen, LRNG_DRNG_MAX_REQSIZE); ++ int ret; ++ ++ atomic_dec(&drng->requests); ++ ++ spin_lock_irqsave(&drng->spin_lock, flags); ++ ret = drng->drng_cb->drng_generate(drng->drng, outbuf, todo); ++ spin_unlock_irqrestore(&drng->spin_lock, flags); ++ if (ret <= 0) { ++ pr_warn("getting random data from DRNG failed (%d)\n", ++ ret); ++ return; ++ } ++ outbuflen -= ret; ++ outbuf += ret; ++ } ++} ++ ++void lrng_get_random_bytes(void *buf, int nbytes) ++{ ++ lrng_drng_atomic_get((u8 *)buf, (u32)nbytes); ++ lrng_debug_report_seedlevel("lrng_get_random_bytes"); ++} ++EXPORT_SYMBOL(lrng_get_random_bytes); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch new file mode 100644 index 000000000..9ba7f20c2 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch @@ -0,0 +1,197 @@ +From 23fcb6113f576df31763a698e8326c8d3bab57a6 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 16:21:44 +0200 +Subject: [PATCH 10/25] LRNG - add common timer-based entropy source code + +The code shared for timer-based entropy sources offers the following +support: + +* It calculates the greatest common divisor (GCD) during startup time. + This allows diving the time stamp by this divisor to eliminate static + low-order bits. With the GCD only timer bits that move are considered + by the entropy sources. + +* It contains the detector code base to identify the presence of a + high-resolution timer. + +This code is only compiled when an entropy source is present that +is based on high-resolution time stamps + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 6 +- + drivers/char/lrng/Makefile | 2 + + drivers/char/lrng/lrng_es_timer_common.c | 144 +++++++++++++++++++++++ + 3 files changed, 149 insertions(+), 3 deletions(-) + create mode 100644 drivers/char/lrng/lrng_es_timer_common.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -144,9 +144,9 @@ endmenu # "Specific DRNG seeding strateg + # config LRNG_SCHED_DFLT_TIMER_ES + # bool + # +-# config LRNG_TIMER_COMMON +-# bool +-# ++config LRNG_TIMER_COMMON ++ bool ++ + # choice + # prompt "Default Timer-based Entropy Source" + # default LRNG_IRQ_DFLT_TIMER_ES +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -17,3 +17,5 @@ obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng + obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o + obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_drng_kcapi.o + obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_drng_atomic.o ++ ++obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_timer_common.c +@@ -0,0 +1,144 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Slow Entropy Source: Interrupt data collection ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++ ++#include "lrng_es_irq.h" ++#include "lrng_es_sched.h" ++#include "lrng_es_timer_common.h" ++#include "lrng_health.h" ++ ++/* Is high-resolution timer present? */ ++static bool lrng_highres_timer_val = false; ++ ++/* Number of time stamps analyzed to calculate a GCD */ ++#define LRNG_GCD_WINDOW_SIZE 100 ++static u32 lrng_gcd_history[LRNG_GCD_WINDOW_SIZE]; ++static atomic_t lrng_gcd_history_ptr = ATOMIC_INIT(-1); ++ ++/* The common divisor for all timestamps */ ++static u32 lrng_gcd_timer = 0; ++ ++bool lrng_gcd_tested(void) ++{ ++ return (lrng_gcd_timer != 0); ++} ++ ++u32 lrng_gcd_get(void) ++{ ++ return lrng_gcd_timer; ++} ++ ++/* Set the GCD for use in IRQ ES - if 0, the GCD calculation is restarted. */ ++void lrng_gcd_set(u32 running_gcd) ++{ ++ lrng_gcd_timer = running_gcd; ++ /* Ensure that update to global variable lrng_gcd_timer is visible */ ++ mb(); ++} ++ ++static void lrng_gcd_set_check(u32 running_gcd) ++{ ++ if (!lrng_gcd_tested()) { ++ lrng_gcd_set(running_gcd); ++ pr_debug("Setting GCD to %u\n", running_gcd); ++ } ++} ++ ++u32 lrng_gcd_analyze(u32 *history, size_t nelem) ++{ ++ u32 running_gcd = 0; ++ size_t i; ++ ++ /* Now perform the analysis on the accumulated time data. */ ++ for (i = 0; i < nelem; i++) { ++ /* ++ * NOTE: this would be the place to add more analysis on the ++ * appropriateness of the timer like checking the presence ++ * of sufficient variations in the timer. ++ */ ++ ++ /* ++ * This calculates the gcd of all the time values. that is ++ * gcd(time_1, time_2, ..., time_nelem) ++ * ++ * Some timers increment by a fixed (non-1) amount each step. ++ * This code checks for such increments, and allows the library ++ * to output the number of such changes have occurred. ++ */ ++ running_gcd = (u32)gcd(history[i], running_gcd); ++ ++ /* Zeroize data */ ++ history[i] = 0; ++ } ++ ++ return running_gcd; ++} ++ ++void lrng_gcd_add_value(u32 time) ++{ ++ u32 ptr = (u32)atomic_inc_return_relaxed(&lrng_gcd_history_ptr); ++ ++ if (ptr < LRNG_GCD_WINDOW_SIZE) { ++ lrng_gcd_history[ptr] = time; ++ } else if (ptr == LRNG_GCD_WINDOW_SIZE) { ++ u32 gcd = lrng_gcd_analyze(lrng_gcd_history, ++ LRNG_GCD_WINDOW_SIZE); ++ ++ if (!gcd) ++ gcd = 1; ++ ++ /* ++ * Ensure that we have variations in the time stamp below the ++ * given value. This is just a safety measure to prevent the GCD ++ * becoming too large. ++ */ ++ if (gcd >= 1000) { ++ pr_warn("calculated GCD is larger than expected: %u\n", ++ gcd); ++ gcd = 1000; ++ } ++ ++ /* Adjust all deltas by the observed (small) common factor. */ ++ lrng_gcd_set_check(gcd); ++ atomic_set(&lrng_gcd_history_ptr, 0); ++ } ++} ++ ++/* Return boolean whether LRNG identified presence of high-resolution timer */ ++bool lrng_highres_timer(void) ++{ ++ return lrng_highres_timer_val; ++} ++ ++static int __init lrng_init_time_source(void) ++{ ++ if ((random_get_entropy() & LRNG_DATA_SLOTSIZE_MASK) || ++ (random_get_entropy() & LRNG_DATA_SLOTSIZE_MASK)) { ++ /* ++ * As the highres timer is identified here, previous interrupts ++ * obtained during boot time are treated like a lowres-timer ++ * would have been present. ++ */ ++ lrng_highres_timer_val = true; ++ } else { ++ lrng_health_disable(); ++ lrng_highres_timer_val = false; ++ } ++ ++ lrng_irq_es_init(lrng_highres_timer_val); ++ lrng_sched_es_init(lrng_highres_timer_val); ++ ++ /* Ensure that changes to global variables are visible */ ++ mb(); ++ ++ return 0; ++} ++core_initcall(lrng_init_time_source); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch new file mode 100644 index 000000000..6e0d7a39c --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch @@ -0,0 +1,1218 @@ +From 7d4187b3588c7c0216ac82634493c30c1d5f28c7 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Tue, 25 Apr 2023 23:03:39 +0200 +Subject: [PATCH 11/25] LRNG - add interrupt entropy source + +The interrupt entropy source (ES) consumes the events triggered by the +kernel invoked with the add_interrupt_randomness. Its main goal is: + +- to be extremely fast in the interrupt handler - This is guaranteed by + only concatenating the least significant bits of a time stamp into + CPU-local entropy pools. Thus, the operation is quasi-lockless. Also, + the concatenation is a very trivial operation. Finally, by discarding + the high-order bits, attacker-observable timing values are discarded. + +- to use only cryptographic primitives for compression. + +The IRQ entropy pool collects noise data from interrupt timing. +Any data received by the LRNG from the interrupt noise sources is +inserted into a per-CPU entropy pool using a hash operation that can +be changed during runtime. Per default, SHA-256 is used. + + (a) When an interrupt occurs, the 8 least significant bits of the + high-resolution time stamp divided by the greatest common divisor (GCD) + is mixed into the per-CPU entropy pool. This time stamp is credited with + heuristically implied entropy. + + (b) HID event data like the key stroke or the mouse coordinates are + mixed into the per-CPU entropy pool. This data is not credited with + entropy by the LRNG. + +To speed up the interrupt handling code of the LRNG, the time stamp +collected for an interrupt event is divided by the greatest common +divisor to eliminate fixed low bits and then truncated to the 8 least +significant bits. 1024 truncated time stamps are concatenated and then +jointly inserted into the per-CPU entropy pool. During boot time, +until the fully seeded stage is reached, each time stamp with its +32 least significant bits is are concatenated. When 1024/32 = 32 such +events are received, they are injected into the per-CPU entropy pool. + +The IRQ ES is only enabled if the existing random number generator +(random.c) is not compiled. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 386 ++++++++--------- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_es_irq.c | 730 ++++++++++++++++++++++++++++++++ + 3 files changed, 924 insertions(+), 193 deletions(-) + create mode 100644 drivers/char/lrng/lrng_es_irq.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -122,8 +122,8 @@ endmenu # "Specific DRNG seeding strateg + # + # endmenu # "LRNG Interfaces" + +-# menu "Entropy Source Configuration" +-# ++menu "Entropy Source Configuration" ++ + # config LRNG_RUNTIME_ES_CONFIG + # bool "Enable runtime configuration of entropy sources" + # help +@@ -135,100 +135,100 @@ endmenu # "Specific DRNG seeding strateg + # a kernel command line option. When not providing any + # option, the default specified during kernel compilation + # is applied. +-# +-# comment "Common Timer-based Entropy Source Configuration" +-# +-# config LRNG_IRQ_DFLT_TIMER_ES +-# bool +-# ++ ++comment "Common Timer-based Entropy Source Configuration" ++ ++config LRNG_IRQ_DFLT_TIMER_ES ++ bool ++ + # config LRNG_SCHED_DFLT_TIMER_ES + # bool + # + config LRNG_TIMER_COMMON + bool + +-# choice +-# prompt "Default Timer-based Entropy Source" +-# default LRNG_IRQ_DFLT_TIMER_ES +-# depends on LRNG_TIMER_COMMON +-# help +-# Select the timer-based entropy source that is credited +-# with entropy. The other timer-based entropy sources may +-# be operational and provide data, but are credited with no +-# entropy. +-# +-# config LRNG_IRQ_DFLT_TIMER_ES +-# bool "Interrupt Entropy Source" +-# depends on LRNG_IRQ +-# help +-# The interrupt entropy source is selected as a timer-based +-# entropy source to provide entropy. +-# ++choice ++ prompt "Default Timer-based Entropy Source" ++ default LRNG_IRQ_DFLT_TIMER_ES ++ depends on LRNG_TIMER_COMMON ++ help ++ Select the timer-based entropy source that is credited ++ with entropy. The other timer-based entropy sources may ++ be operational and provide data, but are credited with no ++ entropy. ++ ++ config LRNG_IRQ_DFLT_TIMER_ES ++ bool "Interrupt Entropy Source" ++ depends on LRNG_IRQ ++ help ++ The interrupt entropy source is selected as a timer-based ++ entropy source to provide entropy. ++ + # config LRNG_SCHED_DFLT_TIMER_ES + # bool "Scheduler Entropy Source" + # depends on LRNG_SCHED + # help + # The scheduler entropy source is selected as timer-based + # entropy source to provide entropy. +-# endchoice +-# +-# choice +-# prompt "LRNG Entropy Collection Pool Size" +-# default LRNG_COLLECTION_SIZE_1024 +-# depends on LRNG_TIMER_COMMON +-# help +-# Select the size of the LRNG entropy collection pool +-# storing data for the interrupt as well as the scheduler +-# entropy sources without performing a compression +-# operation. The larger the collection size is, the faster +-# the average interrupt handling will be. The collection +-# size represents the number of bytes of the per-CPU memory +-# used to batch up entropy event data. +-# +-# The default value is good for regular operations. Choose +-# larger sizes for servers that have no memory limitations. +-# If runtime memory is precious, choose a smaller size. +-# +-# The collection size is unrelated to the entropy rate +-# or the amount of entropy the LRNG can process. +-# +-# config LRNG_COLLECTION_SIZE_32 +-# depends on LRNG_CONTINUOUS_COMPRESSION_ENABLED +-# depends on !LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION +-# depends on !CRYPTO_FIPS +-# bool "32 interrupt events" +-# +-# config LRNG_COLLECTION_SIZE_256 +-# depends on !CRYPTO_FIPS +-# bool "256 interrupt events" +-# +-# config LRNG_COLLECTION_SIZE_512 +-# bool "512 interrupt events" +-# +-# config LRNG_COLLECTION_SIZE_1024 +-# bool "1024 interrupt events (default)" +-# +-# config LRNG_COLLECTION_SIZE_2048 +-# bool "2048 interrupt events" +-# +-# config LRNG_COLLECTION_SIZE_4096 +-# bool "4096 interrupt events" +-# +-# config LRNG_COLLECTION_SIZE_8192 +-# bool "8192 interrupt events" +-# +-# endchoice +-# +-# config LRNG_COLLECTION_SIZE +-# int +-# default 32 if LRNG_COLLECTION_SIZE_32 +-# default 256 if LRNG_COLLECTION_SIZE_256 +-# default 512 if LRNG_COLLECTION_SIZE_512 +-# default 1024 if LRNG_COLLECTION_SIZE_1024 +-# default 2048 if LRNG_COLLECTION_SIZE_2048 +-# default 4096 if LRNG_COLLECTION_SIZE_4096 +-# default 8192 if LRNG_COLLECTION_SIZE_8192 +-# ++endchoice ++ ++choice ++ prompt "LRNG Entropy Collection Pool Size" ++ default LRNG_COLLECTION_SIZE_1024 ++ depends on LRNG_TIMER_COMMON ++ help ++ Select the size of the LRNG entropy collection pool ++ storing data for the interrupt as well as the scheduler ++ entropy sources without performing a compression ++ operation. The larger the collection size is, the faster ++ the average interrupt handling will be. The collection ++ size represents the number of bytes of the per-CPU memory ++ used to batch up entropy event data. ++ ++ The default value is good for regular operations. Choose ++ larger sizes for servers that have no memory limitations. ++ If runtime memory is precious, choose a smaller size. ++ ++ The collection size is unrelated to the entropy rate ++ or the amount of entropy the LRNG can process. ++ ++ config LRNG_COLLECTION_SIZE_32 ++ depends on LRNG_CONTINUOUS_COMPRESSION_ENABLED ++ depends on !LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION ++ depends on !CRYPTO_FIPS ++ bool "32 interrupt events" ++ ++ config LRNG_COLLECTION_SIZE_256 ++ depends on !CRYPTO_FIPS ++ bool "256 interrupt events" ++ ++ config LRNG_COLLECTION_SIZE_512 ++ bool "512 interrupt events" ++ ++ config LRNG_COLLECTION_SIZE_1024 ++ bool "1024 interrupt events (default)" ++ ++ config LRNG_COLLECTION_SIZE_2048 ++ bool "2048 interrupt events" ++ ++ config LRNG_COLLECTION_SIZE_4096 ++ bool "4096 interrupt events" ++ ++ config LRNG_COLLECTION_SIZE_8192 ++ bool "8192 interrupt events" ++ ++endchoice ++ ++config LRNG_COLLECTION_SIZE ++ int ++ default 32 if LRNG_COLLECTION_SIZE_32 ++ default 256 if LRNG_COLLECTION_SIZE_256 ++ default 512 if LRNG_COLLECTION_SIZE_512 ++ default 1024 if LRNG_COLLECTION_SIZE_1024 ++ default 2048 if LRNG_COLLECTION_SIZE_2048 ++ default 4096 if LRNG_COLLECTION_SIZE_4096 ++ default 8192 if LRNG_COLLECTION_SIZE_8192 ++ + # config LRNG_HEALTH_TESTS + # bool "Enable internal entropy source online health tests" + # depends on LRNG_TIMER_COMMON +@@ -303,113 +303,113 @@ config LRNG_TIMER_COMMON + # int + # default 371 if !LRNG_APT_BROKEN + # default 33 if LRNG_APT_BROKEN +-# +-# comment "Interrupt Entropy Source" +-# +-# config LRNG_IRQ +-# bool "Enable Interrupt Entropy Source as LRNG Seed Source" +-# default y +-# depends on !RANDOM_DEFAULT_IMPL +-# select LRNG_TIMER_COMMON +-# help +-# The LRNG models an entropy source based on the timing of the +-# occurrence of interrupts. Enable this option to enable this +-# IRQ entropy source. +-# +-# The IRQ entropy source is triggered every time an interrupt +-# arrives and thus causes the interrupt handler to execute +-# slightly longer. Disabling the IRQ entropy source implies +-# that the performance penalty on the interrupt handler added +-# by the LRNG is eliminated. Yet, this entropy source is +-# considered to be an internal entropy source of the LRNG. +-# Thus, only disable it if you ensured that other entropy +-# sources are available that supply the LRNG with entropy. +-# +-# If you disable the IRQ entropy source, you MUST ensure +-# one or more entropy sources collectively have the +-# capability to deliver sufficient entropy with one invocation +-# at a rate compliant to the security strength of the DRNG +-# (usually 256 bits of entropy). In addition, if those +-# entropy sources do not deliver sufficient entropy during +-# first request, the reseed must be triggered from user +-# space or kernel space when sufficient entropy is considered +-# to be present. +-# +-# If unsure, say Y. +-# +-# choice +-# prompt "Continuous entropy compression boot time setting" +-# default LRNG_CONTINUOUS_COMPRESSION_ENABLED +-# depends on LRNG_IRQ +-# help +-# Select the default behavior of the interrupt entropy source +-# continuous compression operation. +-# +-# The LRNG IRQ ES collects entropy data during each interrupt. +-# For performance reasons, a amount of entropy data defined by +-# the LRNG entropy collection pool size is concatenated into +-# an array. When that array is filled up, a hash is calculated +-# to compress the entropy. That hash is calculated in +-# interrupt context. +-# +-# In case such hash calculation in interrupt context is deemed +-# too time-consuming, the continuous compression operation +-# can be disabled. If disabled, the collection of entropy will +-# not trigger a hash compression operation in interrupt context. +-# The compression happens only when the DRNG is reseeded which is +-# in process context. This implies that old entropy data +-# collected after the last DRNG-reseed is overwritten with newer +-# entropy data once the collection pool is full instead of +-# retaining its entropy with the compression operation. +-# +-# config LRNG_CONTINUOUS_COMPRESSION_ENABLED +-# bool "Enable continuous compression (default)" +-# +-# config LRNG_CONTINUOUS_COMPRESSION_DISABLED +-# bool "Disable continuous compression" +-# +-# endchoice +-# +-# config LRNG_ENABLE_CONTINUOUS_COMPRESSION +-# bool +-# default y if LRNG_CONTINUOUS_COMPRESSION_ENABLED +-# default n if LRNG_CONTINUOUS_COMPRESSION_DISABLED +-# +-# config LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION +-# bool "Runtime-switchable continuous entropy compression" +-# depends on LRNG_IRQ +-# help +-# Per default, the interrupt entropy source continuous +-# compression operation behavior is hard-wired into the kernel. +-# Enable this option to allow it to be configurable at boot time. +-# +-# To modify the default behavior of the continuous +-# compression operation, use the kernel command line option +-# of lrng_sw_noise.lrng_pcpu_continuous_compression. +-# +-# If unsure, say N. +-# +-# config LRNG_IRQ_ENTROPY_RATE +-# int "Interrupt Entropy Source Entropy Rate" +-# depends on LRNG_IRQ +-# range 256 4294967295 if LRNG_IRQ_DFLT_TIMER_ES +-# range 4294967295 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES +-# default 256 if LRNG_IRQ_DFLT_TIMER_ES +-# default 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES +-# help +-# The LRNG will collect the configured number of interrupts to +-# obtain 256 bits of entropy. This value can be set to any between +-# 256 and 4294967295. The LRNG guarantees that this value is not +-# lower than 256. This lower limit implies that one interrupt event +-# is credited with one bit of entropy. This value is subject to the +-# increase by the oversampling factor, if no high-resolution timer +-# is found. +-# +-# In order to effectively disable the interrupt entropy source, +-# the option has to be set to 4294967295. In this case, the +-# interrupt entropy source will still deliver data but without +-# being credited with entropy. +-# ++ ++comment "Interrupt Entropy Source" ++ ++config LRNG_IRQ ++ bool "Enable Interrupt Entropy Source as LRNG Seed Source" ++ default y ++ depends on !RANDOM_DEFAULT_IMPL ++ select LRNG_TIMER_COMMON ++ help ++ The LRNG models an entropy source based on the timing of the ++ occurrence of interrupts. Enable this option to enable this ++ IRQ entropy source. ++ ++ The IRQ entropy source is triggered every time an interrupt ++ arrives and thus causes the interrupt handler to execute ++ slightly longer. Disabling the IRQ entropy source implies ++ that the performance penalty on the interrupt handler added ++ by the LRNG is eliminated. Yet, this entropy source is ++ considered to be an internal entropy source of the LRNG. ++ Thus, only disable it if you ensured that other entropy ++ sources are available that supply the LRNG with entropy. ++ ++ If you disable the IRQ entropy source, you MUST ensure ++ one or more entropy sources collectively have the ++ capability to deliver sufficient entropy with one invocation ++ at a rate compliant to the security strength of the DRNG ++ (usually 256 bits of entropy). In addition, if those ++ entropy sources do not deliver sufficient entropy during ++ first request, the reseed must be triggered from user ++ space or kernel space when sufficient entropy is considered ++ to be present. ++ ++ If unsure, say Y. ++ ++choice ++ prompt "Continuous entropy compression boot time setting" ++ default LRNG_CONTINUOUS_COMPRESSION_ENABLED ++ depends on LRNG_IRQ ++ help ++ Select the default behavior of the interrupt entropy source ++ continuous compression operation. ++ ++ The LRNG IRQ ES collects entropy data during each interrupt. ++ For performance reasons, a amount of entropy data defined by ++ the LRNG entropy collection pool size is concatenated into ++ an array. When that array is filled up, a hash is calculated ++ to compress the entropy. That hash is calculated in ++ interrupt context. ++ ++ In case such hash calculation in interrupt context is deemed ++ too time-consuming, the continuous compression operation ++ can be disabled. If disabled, the collection of entropy will ++ not trigger a hash compression operation in interrupt context. ++ The compression happens only when the DRNG is reseeded which is ++ in process context. This implies that old entropy data ++ collected after the last DRNG-reseed is overwritten with newer ++ entropy data once the collection pool is full instead of ++ retaining its entropy with the compression operation. ++ ++ config LRNG_CONTINUOUS_COMPRESSION_ENABLED ++ bool "Enable continuous compression (default)" ++ ++ config LRNG_CONTINUOUS_COMPRESSION_DISABLED ++ bool "Disable continuous compression" ++ ++endchoice ++ ++config LRNG_ENABLE_CONTINUOUS_COMPRESSION ++ bool ++ default y if LRNG_CONTINUOUS_COMPRESSION_ENABLED ++ default n if LRNG_CONTINUOUS_COMPRESSION_DISABLED ++ ++config LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION ++ bool "Runtime-switchable continuous entropy compression" ++ depends on LRNG_IRQ ++ help ++ Per default, the interrupt entropy source continuous ++ compression operation behavior is hard-wired into the kernel. ++ Enable this option to allow it to be configurable at boot time. ++ ++ To modify the default behavior of the continuous ++ compression operation, use the kernel command line option ++ of lrng_sw_noise.lrng_pcpu_continuous_compression. ++ ++ If unsure, say N. ++ ++config LRNG_IRQ_ENTROPY_RATE ++ int "Interrupt Entropy Source Entropy Rate" ++ depends on LRNG_IRQ ++ range 256 4294967295 if LRNG_IRQ_DFLT_TIMER_ES ++ range 4294967295 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES ++ default 256 if LRNG_IRQ_DFLT_TIMER_ES ++ default 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES ++ help ++ The LRNG will collect the configured number of interrupts to ++ obtain 256 bits of entropy. This value can be set to any between ++ 256 and 4294967295. The LRNG guarantees that this value is not ++ lower than 256. This lower limit implies that one interrupt event ++ is credited with one bit of entropy. This value is subject to the ++ increase by the oversampling factor, if no high-resolution timer ++ is found. ++ ++ In order to effectively disable the interrupt entropy source, ++ the option has to be set to 4294967295. In this case, the ++ interrupt entropy source will still deliver data but without ++ being credited with entropy. ++ + # comment "Jitter RNG Entropy Source" + # + # config LRNG_JENT +@@ -614,8 +614,8 @@ config LRNG_TIMER_COMMON + # kernel in FIPS mode (with fips=1 kernel command line option). + # This is due to the fact that random.c is not SP800-90B + # compliant. +-# +-# endmenu # "Entropy Source Configuration" ++ ++endmenu # "Entropy Source Configuration" + + config LRNG_DRNG_CHACHA20 + tristate +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -19,3 +19,4 @@ obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_d + obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_drng_atomic.o + + obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o ++obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_irq.c +@@ -0,0 +1,730 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Slow Entropy Source: Interrupt data collection ++ * ++ * Copyright (C) 2022 - 2023, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_es_aux.h" ++#include "lrng_es_irq.h" ++#include "lrng_es_timer_common.h" ++#include "lrng_health.h" ++#include "lrng_numa.h" ++#include "lrng_testing.h" ++ ++/* ++ * Number of interrupts to be recorded to assume that DRNG security strength ++ * bits of entropy are received. ++ * Note: a value below the DRNG security strength should not be defined as this ++ * may imply the DRNG can never be fully seeded in case other noise ++ * sources are unavailable. ++ */ ++#define LRNG_IRQ_ENTROPY_BITS LRNG_UINT32_C(CONFIG_LRNG_IRQ_ENTROPY_RATE) ++ ++ ++/* Number of interrupts required for LRNG_DRNG_SECURITY_STRENGTH_BITS entropy */ ++static u32 lrng_irq_entropy_bits = LRNG_IRQ_ENTROPY_BITS; ++ ++static u32 irq_entropy __read_mostly = LRNG_IRQ_ENTROPY_BITS; ++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG ++module_param(irq_entropy, uint, 0444); ++MODULE_PARM_DESC(irq_entropy, ++ "How many interrupts must be collected for obtaining 256 bits of entropy\n"); ++#endif ++ ++/* Per-CPU array holding concatenated IRQ entropy events */ ++static DEFINE_PER_CPU(u32 [LRNG_DATA_ARRAY_SIZE], lrng_irq_array) ++ __aligned(LRNG_KCAPI_ALIGN); ++static DEFINE_PER_CPU(u32, lrng_irq_array_ptr) = 0; ++static DEFINE_PER_CPU(atomic_t, lrng_irq_array_irqs) = ATOMIC_INIT(0); ++ ++/* ++ * The entropy collection is performed by executing the following steps: ++ * 1. fill up the per-CPU array holding the time stamps ++ * 2. once the per-CPU array is full, a compression of the data into ++ * the entropy pool is performed - this happens in interrupt context ++ * ++ * If step 2 is not desired in interrupt context, the following boolean ++ * needs to be set to false. This implies that old entropy data in the ++ * per-CPU array collected since the last DRNG reseed is overwritten with ++ * new entropy data instead of retaining the entropy with the compression ++ * operation. ++ * ++ * Impact on entropy: ++ * ++ * If continuous compression is enabled, the maximum entropy that is collected ++ * per CPU between DRNG reseeds is equal to the digest size of the used hash. ++ * ++ * If continuous compression is disabled, the maximum number of entropy events ++ * that can be collected per CPU is equal to LRNG_DATA_ARRAY_SIZE. This amount ++ * of events is converted into an entropy statement which then represents the ++ * maximum amount of entropy collectible per CPU between DRNG reseeds. ++ */ ++static bool lrng_irq_continuous_compression __read_mostly = ++ IS_ENABLED(CONFIG_LRNG_ENABLE_CONTINUOUS_COMPRESSION); ++ ++#ifdef CONFIG_LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION ++module_param(lrng_irq_continuous_compression, bool, 0444); ++MODULE_PARM_DESC(lrng_irq_continuous_compression, ++ "Perform entropy compression if per-CPU entropy data array is full\n"); ++#endif ++ ++/* ++ * Per-CPU entropy pool with compressed entropy event ++ * ++ * The per-CPU entropy pool is defined as the hash state. New data is simply ++ * inserted into the entropy pool by performing a hash update operation. ++ * To read the entropy pool, a hash final must be invoked. However, before ++ * the entropy pool is released again after a hash final, the hash init must ++ * be performed. ++ */ ++static DEFINE_PER_CPU(u8 [LRNG_POOL_SIZE], lrng_irq_pool) ++ __aligned(LRNG_KCAPI_ALIGN); ++/* ++ * Lock to allow other CPUs to read the pool - as this is only done during ++ * reseed which is infrequent, this lock is hardly contended. ++ */ ++static DEFINE_PER_CPU(spinlock_t, lrng_irq_lock); ++static DEFINE_PER_CPU(bool, lrng_irq_lock_init) = false; ++ ++static bool lrng_irq_pool_online(int cpu) ++{ ++ return per_cpu(lrng_irq_lock_init, cpu); ++} ++ ++static void __init lrng_irq_check_compression_state(void) ++{ ++ /* One pool must hold sufficient entropy for disabled compression */ ++ if (!lrng_irq_continuous_compression) { ++ u32 max_ent = min_t(u32, lrng_get_digestsize(), ++ lrng_data_to_entropy(LRNG_DATA_NUM_VALUES, ++ lrng_irq_entropy_bits)); ++ if (max_ent < lrng_security_strength()) { ++ pr_warn("Force continuous compression operation to ensure LRNG can hold enough entropy\n"); ++ lrng_irq_continuous_compression = true; ++ } ++ } ++} ++ ++void __init lrng_irq_es_init(bool highres_timer) ++{ ++ /* Set a minimum number of interrupts that must be collected */ ++ irq_entropy = max_t(u32, LRNG_IRQ_ENTROPY_BITS, irq_entropy); ++ ++ if (highres_timer) { ++ lrng_irq_entropy_bits = irq_entropy; ++ } else { ++ u32 new_entropy = irq_entropy * LRNG_ES_OVERSAMPLING_FACTOR; ++ ++ lrng_irq_entropy_bits = (irq_entropy < new_entropy) ? ++ new_entropy : irq_entropy; ++ pr_warn("operating without high-resolution timer and applying IRQ oversampling factor %u\n", ++ LRNG_ES_OVERSAMPLING_FACTOR); ++ } ++ ++ lrng_irq_check_compression_state(); ++} ++ ++/* ++ * Reset all per-CPU pools - reset entropy estimator but leave the pool data ++ * that may or may not have entropy unchanged. ++ */ ++static void lrng_irq_reset(void) ++{ ++ int cpu; ++ ++ /* Trigger GCD calculation anew. */ ++ lrng_gcd_set(0); ++ ++ for_each_online_cpu(cpu) ++ atomic_set(per_cpu_ptr(&lrng_irq_array_irqs, cpu), 0); ++} ++ ++static u32 lrng_irq_avail_pool_size(void) ++{ ++ u32 max_size = 0, max_pool = lrng_get_digestsize(); ++ int cpu; ++ ++ if (!lrng_irq_continuous_compression) ++ max_pool = min_t(u32, max_pool, LRNG_DATA_NUM_VALUES); ++ ++ for_each_online_cpu(cpu) { ++ if (lrng_irq_pool_online(cpu)) ++ max_size += max_pool; ++ } ++ ++ return max_size; ++} ++ ++/* Return entropy of unused IRQs present in all per-CPU pools. */ ++static u32 lrng_irq_avail_entropy(u32 __unused) ++{ ++ u32 digestsize_irqs, irq = 0; ++ int cpu; ++ ++ /* Only deliver entropy when SP800-90B self test is completed */ ++ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_irq)) ++ return 0; ++ ++ /* Obtain the cap of maximum numbers of IRQs we count */ ++ digestsize_irqs = lrng_entropy_to_data(lrng_get_digestsize(), ++ lrng_irq_entropy_bits); ++ if (!lrng_irq_continuous_compression) { ++ /* Cap to max. number of IRQs the array can hold */ ++ digestsize_irqs = min_t(u32, digestsize_irqs, ++ LRNG_DATA_NUM_VALUES); ++ } ++ ++ for_each_online_cpu(cpu) { ++ if (!lrng_irq_pool_online(cpu)) ++ continue; ++ irq += min_t(u32, digestsize_irqs, ++ atomic_read_u32(per_cpu_ptr(&lrng_irq_array_irqs, ++ cpu))); ++ } ++ ++ /* Consider oversampling rate */ ++ return lrng_reduce_by_osr(lrng_data_to_entropy(irq, ++ lrng_irq_entropy_bits)); ++} ++ ++/* ++ * Trigger a switch of the hash implementation for the per-CPU pool. ++ * ++ * For each per-CPU pool, obtain the message digest with the old hash ++ * implementation, initialize the per-CPU pool again with the new hash ++ * implementation and inject the message digest into the new state. ++ * ++ * Assumption: the caller must guarantee that the new_cb is available during the ++ * entire operation (e.g. it must hold the lock against pointer updating). ++ */ ++static int ++lrng_irq_switch_hash(struct lrng_drng *drng, int node, ++ const struct lrng_hash_cb *new_cb, void *new_hash, ++ const struct lrng_hash_cb *old_cb) ++{ ++ u8 digest[LRNG_MAX_DIGESTSIZE]; ++ u32 digestsize_irqs, found_irqs; ++ int ret = 0, cpu; ++ ++ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) ++ return -EOPNOTSUPP; ++ ++ for_each_online_cpu(cpu) { ++ struct shash_desc *pcpu_shash; ++ ++ /* ++ * Only switch the per-CPU pools for the current node because ++ * the hash_cb only applies NUMA-node-wide. ++ */ ++ if (cpu_to_node(cpu) != node || !lrng_irq_pool_online(cpu)) ++ continue; ++ ++ pcpu_shash = (struct shash_desc *)per_cpu_ptr(lrng_irq_pool, ++ cpu); ++ ++ digestsize_irqs = old_cb->hash_digestsize(pcpu_shash); ++ digestsize_irqs = lrng_entropy_to_data(digestsize_irqs << 3, ++ lrng_irq_entropy_bits); ++ ++ if (pcpu_shash->tfm == new_hash) ++ continue; ++ ++ /* Get the per-CPU pool hash with old digest ... */ ++ ret = old_cb->hash_final(pcpu_shash, digest) ?: ++ /* ... re-initialize the hash with the new digest ... */ ++ new_cb->hash_init(pcpu_shash, new_hash) ?: ++ /* ++ * ... feed the old hash into the new state. We may feed ++ * uninitialized memory into the new state, but this is ++ * considered no issue and even good as we have some more ++ * uncertainty here. ++ */ ++ new_cb->hash_update(pcpu_shash, digest, sizeof(digest)); ++ if (ret) ++ goto out; ++ ++ /* ++ * In case the new digest is larger than the old one, cap ++ * the available entropy to the old message digest used to ++ * process the existing data. ++ */ ++ found_irqs = atomic_xchg_relaxed( ++ per_cpu_ptr(&lrng_irq_array_irqs, cpu), 0); ++ found_irqs = min_t(u32, found_irqs, digestsize_irqs); ++ atomic_add_return_relaxed(found_irqs, ++ per_cpu_ptr(&lrng_irq_array_irqs, cpu)); ++ ++ pr_debug("Re-initialize per-CPU interrupt entropy pool for CPU %d on NUMA node %d with hash %s\n", ++ cpu, node, new_cb->hash_name()); ++ } ++ ++out: ++ memzero_explicit(digest, sizeof(digest)); ++ return ret; ++} ++ ++/* ++ * When reading the per-CPU message digest, make sure we use the crypto ++ * callbacks defined for the NUMA node the per-CPU pool is defined for because ++ * the LRNG crypto switch support is only atomic per NUMA node. ++ */ ++static u32 ++lrng_irq_pool_hash_one(const struct lrng_hash_cb *pcpu_hash_cb, ++ void *pcpu_hash, int cpu, u8 *digest, u32 *digestsize) ++{ ++ struct shash_desc *pcpu_shash = ++ (struct shash_desc *)per_cpu_ptr(lrng_irq_pool, cpu); ++ spinlock_t *lock = per_cpu_ptr(&lrng_irq_lock, cpu); ++ unsigned long flags; ++ u32 digestsize_irqs, found_irqs; ++ ++ /* Lock guarding against reading / writing to per-CPU pool */ ++ spin_lock_irqsave(lock, flags); ++ ++ *digestsize = pcpu_hash_cb->hash_digestsize(pcpu_hash); ++ digestsize_irqs = lrng_entropy_to_data(*digestsize << 3, ++ lrng_irq_entropy_bits); ++ ++ /* Obtain entropy statement like for the entropy pool */ ++ found_irqs = atomic_xchg_relaxed( ++ per_cpu_ptr(&lrng_irq_array_irqs, cpu), 0); ++ /* Cap to maximum amount of data we can hold in hash */ ++ found_irqs = min_t(u32, found_irqs, digestsize_irqs); ++ ++ /* Cap to maximum amount of data we can hold in array */ ++ if (!lrng_irq_continuous_compression) ++ found_irqs = min_t(u32, found_irqs, LRNG_DATA_NUM_VALUES); ++ ++ /* Store all not-yet compressed data in data array into hash, ... */ ++ if (pcpu_hash_cb->hash_update(pcpu_shash, ++ (u8 *)per_cpu_ptr(lrng_irq_array, cpu), ++ LRNG_DATA_ARRAY_SIZE * sizeof(u32)) ?: ++ /* ... get the per-CPU pool digest, ... */ ++ pcpu_hash_cb->hash_final(pcpu_shash, digest) ?: ++ /* ... re-initialize the hash, ... */ ++ pcpu_hash_cb->hash_init(pcpu_shash, pcpu_hash) ?: ++ /* ... feed the old hash into the new state. */ ++ pcpu_hash_cb->hash_update(pcpu_shash, digest, *digestsize)) ++ found_irqs = 0; ++ ++ spin_unlock_irqrestore(lock, flags); ++ return found_irqs; ++} ++ ++/* ++ * Hash all per-CPU pools and return the digest to be used as seed data for ++ * seeding a DRNG. The caller must guarantee backtracking resistance. ++ * The function will only copy as much data as entropy is available into the ++ * caller-provided output buffer. ++ * ++ * This function handles the translation from the number of received interrupts ++ * into an entropy statement. The conversion depends on LRNG_IRQ_ENTROPY_BITS ++ * which defines how many interrupts must be received to obtain 256 bits of ++ * entropy. With this value, the function lrng_data_to_entropy converts a given ++ * data size (received interrupts, requested amount of data, etc.) into an ++ * entropy statement. lrng_entropy_to_data does the reverse. ++ * ++ * @eb: entropy buffer to store entropy ++ * @requested_bits: Requested amount of entropy ++ * @fully_seeded: indicator whether LRNG is fully seeded ++ */ ++static void lrng_irq_pool_hash(struct entropy_buf *eb, u32 requested_bits, ++ bool fully_seeded) ++{ ++ SHASH_DESC_ON_STACK(shash, NULL); ++ const struct lrng_hash_cb *hash_cb; ++ struct lrng_drng **lrng_drng = lrng_drng_instances(); ++ struct lrng_drng *drng = lrng_drng_init_instance(); ++ u8 digest[LRNG_MAX_DIGESTSIZE]; ++ unsigned long flags, flags2; ++ u32 found_irqs, collected_irqs = 0, collected_ent_bits, requested_irqs, ++ returned_ent_bits; ++ int ret, cpu; ++ void *hash; ++ ++ /* Only deliver entropy when SP800-90B self test is completed */ ++ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_irq)) { ++ eb->e_bits[lrng_int_es_irq] = 0; ++ return; ++ } ++ ++ /* Lock guarding replacement of per-NUMA hash */ ++ read_lock_irqsave(&drng->hash_lock, flags); ++ ++ hash_cb = drng->hash_cb; ++ hash = drng->hash; ++ ++ /* The hash state of filled with all per-CPU pool hashes. */ ++ ret = hash_cb->hash_init(shash, hash); ++ if (ret) ++ goto err; ++ ++ /* Cap to maximum entropy that can ever be generated with given hash */ ++ lrng_cap_requested(hash_cb->hash_digestsize(hash) << 3, requested_bits); ++ requested_irqs = lrng_entropy_to_data(requested_bits + ++ lrng_compress_osr(), ++ lrng_irq_entropy_bits); ++ ++ /* ++ * Harvest entropy from each per-CPU hash state - even though we may ++ * have collected sufficient entropy, we will hash all per-CPU pools. ++ */ ++ for_each_online_cpu(cpu) { ++ struct lrng_drng *pcpu_drng = drng; ++ u32 digestsize, pcpu_unused_irqs = 0; ++ int node = cpu_to_node(cpu); ++ ++ /* If pool is not online, then no entropy is present. */ ++ if (!lrng_irq_pool_online(cpu)) ++ continue; ++ ++ if (lrng_drng && lrng_drng[node]) ++ pcpu_drng = lrng_drng[node]; ++ ++ if (pcpu_drng == drng) { ++ found_irqs = lrng_irq_pool_hash_one(hash_cb, hash, ++ cpu, digest, ++ &digestsize); ++ } else { ++ read_lock_irqsave(&pcpu_drng->hash_lock, flags2); ++ found_irqs = ++ lrng_irq_pool_hash_one(pcpu_drng->hash_cb, ++ pcpu_drng->hash, cpu, ++ digest, &digestsize); ++ read_unlock_irqrestore(&pcpu_drng->hash_lock, flags2); ++ } ++ ++ /* Inject the digest into the state of all per-CPU pools */ ++ ret = hash_cb->hash_update(shash, digest, digestsize); ++ if (ret) ++ goto err; ++ ++ collected_irqs += found_irqs; ++ if (collected_irqs > requested_irqs) { ++ pcpu_unused_irqs = collected_irqs - requested_irqs; ++ atomic_add_return_relaxed(pcpu_unused_irqs, ++ per_cpu_ptr(&lrng_irq_array_irqs, cpu)); ++ collected_irqs = requested_irqs; ++ } ++ pr_debug("%u interrupts used from entropy pool of CPU %d, %u interrupts remain unused\n", ++ found_irqs - pcpu_unused_irqs, cpu, pcpu_unused_irqs); ++ } ++ ++ ret = hash_cb->hash_final(shash, digest); ++ if (ret) ++ goto err; ++ ++ collected_ent_bits = lrng_data_to_entropy(collected_irqs, ++ lrng_irq_entropy_bits); ++ /* Apply oversampling: discount requested oversampling rate */ ++ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits); ++ ++ pr_debug("obtained %u bits by collecting %u bits of entropy from entropy pool noise source\n", ++ returned_ent_bits, collected_ent_bits); ++ ++ /* ++ * Truncate to available entropy as implicitly allowed by SP800-90B ++ * section 3.1.5.1.1 table 1 which awards truncated hashes full ++ * entropy. ++ * ++ * During boot time, we read requested_bits data with ++ * returned_ent_bits entropy. In case our conservative entropy ++ * estimate underestimates the available entropy we can transport as ++ * much available entropy as possible. ++ */ ++ memcpy(eb->e[lrng_int_es_irq], digest, ++ fully_seeded ? returned_ent_bits >> 3 : requested_bits >> 3); ++ eb->e_bits[lrng_int_es_irq] = returned_ent_bits; ++ ++out: ++ hash_cb->hash_desc_zero(shash); ++ read_unlock_irqrestore(&drng->hash_lock, flags); ++ memzero_explicit(digest, sizeof(digest)); ++ return; ++ ++err: ++ eb->e_bits[lrng_int_es_irq] = 0; ++ goto out; ++} ++ ++/* Compress the lrng_irq_array array into lrng_irq_pool */ ++static void lrng_irq_array_compress(void) ++{ ++ struct shash_desc *shash = ++ (struct shash_desc *)this_cpu_ptr(lrng_irq_pool); ++ struct lrng_drng *drng = lrng_drng_node_instance(); ++ const struct lrng_hash_cb *hash_cb; ++ spinlock_t *lock = this_cpu_ptr(&lrng_irq_lock); ++ unsigned long flags, flags2; ++ void *hash; ++ bool init = false; ++ ++ read_lock_irqsave(&drng->hash_lock, flags); ++ hash_cb = drng->hash_cb; ++ hash = drng->hash; ++ ++ if (unlikely(!this_cpu_read(lrng_irq_lock_init))) { ++ init = true; ++ spin_lock_init(lock); ++ this_cpu_write(lrng_irq_lock_init, true); ++ pr_debug("Initializing per-CPU entropy pool for CPU %d on NUMA node %d with hash %s\n", ++ raw_smp_processor_id(), numa_node_id(), ++ hash_cb->hash_name()); ++ } ++ ++ spin_lock_irqsave(lock, flags2); ++ ++ if (unlikely(init) && hash_cb->hash_init(shash, hash)) { ++ this_cpu_write(lrng_irq_lock_init, false); ++ pr_warn("Initialization of hash failed\n"); ++ } else if (lrng_irq_continuous_compression) { ++ /* Add entire per-CPU data array content into entropy pool. */ ++ if (hash_cb->hash_update(shash, ++ (u8 *)this_cpu_ptr(lrng_irq_array), ++ LRNG_DATA_ARRAY_SIZE * sizeof(u32))) ++ pr_warn_ratelimited("Hashing of entropy data failed\n"); ++ } ++ ++ spin_unlock_irqrestore(lock, flags2); ++ read_unlock_irqrestore(&drng->hash_lock, flags); ++} ++ ++/* Compress data array into hash */ ++static void lrng_irq_array_to_hash(u32 ptr) ++{ ++ u32 *array = this_cpu_ptr(lrng_irq_array); ++ ++ /* ++ * During boot time the hash operation is triggered more often than ++ * during regular operation. ++ */ ++ if (unlikely(!lrng_state_fully_seeded())) { ++ if ((ptr & 31) && (ptr < LRNG_DATA_WORD_MASK)) ++ return; ++ } else if (ptr < LRNG_DATA_WORD_MASK) { ++ return; ++ } ++ ++ if (lrng_raw_array_entropy_store(*array)) { ++ u32 i; ++ ++ /* ++ * If we fed even a part of the array to external analysis, we ++ * mark that the entire array and the per-CPU pool to have no ++ * entropy. This is due to the non-IID property of the data as ++ * we do not fully know whether the existing dependencies ++ * diminish the entropy beyond to what we expect it has. ++ */ ++ atomic_set(this_cpu_ptr(&lrng_irq_array_irqs), 0); ++ ++ for (i = 1; i < LRNG_DATA_ARRAY_SIZE; i++) ++ lrng_raw_array_entropy_store(*(array + i)); ++ } else { ++ lrng_irq_array_compress(); ++ /* Ping pool handler about received entropy */ ++ if (lrng_sp80090b_startup_complete_es(lrng_int_es_irq)) ++ lrng_es_add_entropy(); ++ } ++} ++ ++/* ++ * Concatenate full 32 bit word at the end of time array even when current ++ * ptr is not aligned to sizeof(data). ++ */ ++static void _lrng_irq_array_add_u32(u32 data) ++{ ++ /* Increment pointer by number of slots taken for input value */ ++ u32 pre_ptr, mask, ptr = this_cpu_add_return(lrng_irq_array_ptr, ++ LRNG_DATA_SLOTS_PER_UINT); ++ unsigned int pre_array; ++ ++ /* ++ * This function injects a unit into the array - guarantee that ++ * array unit size is equal to data type of input data. ++ */ ++ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS != (sizeof(data) << 3)); ++ ++ /* ++ * The following logic requires at least two units holding ++ * the data as otherwise the pointer would immediately wrap when ++ * injection an u32 word. ++ */ ++ BUILD_BUG_ON(LRNG_DATA_NUM_VALUES <= LRNG_DATA_SLOTS_PER_UINT); ++ ++ lrng_data_split_u32(&ptr, &pre_ptr, &mask); ++ ++ /* MSB of data go into previous unit */ ++ pre_array = lrng_data_idx2array(pre_ptr); ++ /* zeroization of slot to ensure the following OR adds the data */ ++ this_cpu_and(lrng_irq_array[pre_array], ~(0xffffffff & ~mask)); ++ this_cpu_or(lrng_irq_array[pre_array], data & ~mask); ++ ++ /* Invoke compression as we just filled data array completely */ ++ if (unlikely(pre_ptr > ptr)) ++ lrng_irq_array_to_hash(LRNG_DATA_WORD_MASK); ++ ++ /* LSB of data go into current unit */ ++ this_cpu_write(lrng_irq_array[lrng_data_idx2array(ptr)], ++ data & mask); ++ ++ if (likely(pre_ptr <= ptr)) ++ lrng_irq_array_to_hash(ptr); ++} ++ ++/* Concatenate a 32-bit word at the end of the per-CPU array */ ++void lrng_irq_array_add_u32(u32 data) ++{ ++ /* ++ * Disregard entropy-less data without continuous compression to ++ * avoid it overwriting data with entropy when array ptr wraps. ++ */ ++ if (lrng_irq_continuous_compression) ++ _lrng_irq_array_add_u32(data); ++} ++ ++/* Concatenate data of max LRNG_DATA_SLOTSIZE_MASK at the end of time array */ ++static void lrng_irq_array_add_slot(u32 data) ++{ ++ /* Get slot */ ++ u32 ptr = this_cpu_inc_return(lrng_irq_array_ptr) & ++ LRNG_DATA_WORD_MASK; ++ unsigned int array = lrng_data_idx2array(ptr); ++ unsigned int slot = lrng_data_idx2slot(ptr); ++ ++ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS % LRNG_DATA_SLOTSIZE_BITS); ++ /* Ensure consistency of values */ ++ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS != ++ sizeof(lrng_irq_array[0]) << 3); ++ ++ /* zeroization of slot to ensure the following OR adds the data */ ++ this_cpu_and(lrng_irq_array[array], ++ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK, ++ slot))); ++ /* Store data into slot */ ++ this_cpu_or(lrng_irq_array[array], lrng_data_slot_val(data, slot)); ++ ++ lrng_irq_array_to_hash(ptr); ++} ++ ++static void ++lrng_time_process_common(u32 time, void(*add_time)(u32 data)) ++{ ++ enum lrng_health_res health_test; ++ ++ if (lrng_raw_hires_entropy_store(time)) ++ return; ++ ++ health_test = lrng_health_test(time, lrng_int_es_irq); ++ if (health_test > lrng_health_fail_use) ++ return; ++ ++ if (health_test == lrng_health_pass) ++ atomic_inc_return(this_cpu_ptr(&lrng_irq_array_irqs)); ++ ++ add_time(time); ++} ++ ++/* ++ * Batching up of entropy in per-CPU array before injecting into entropy pool. ++ */ ++static void lrng_time_process(void) ++{ ++ u32 now_time = random_get_entropy(); ++ ++ if (unlikely(!lrng_gcd_tested())) { ++ /* When GCD is unknown, we process the full time stamp */ ++ lrng_time_process_common(now_time, _lrng_irq_array_add_u32); ++ lrng_gcd_add_value(now_time); ++ } else { ++ /* GCD is known and applied */ ++ lrng_time_process_common((now_time / lrng_gcd_get()) & ++ LRNG_DATA_SLOTSIZE_MASK, ++ lrng_irq_array_add_slot); ++ } ++ ++ lrng_perf_time(now_time); ++} ++ ++/* Hot code path - Callback for interrupt handler */ ++void add_interrupt_randomness(int irq) ++{ ++ if (lrng_highres_timer()) { ++ lrng_time_process(); ++ } else { ++ struct pt_regs *regs = get_irq_regs(); ++ static atomic_t reg_idx = ATOMIC_INIT(0); ++ u64 ip; ++ u32 tmp; ++ ++ if (regs) { ++ u32 *ptr = (u32 *)regs; ++ int reg_ptr = atomic_add_return_relaxed(1, ®_idx); ++ size_t n = (sizeof(struct pt_regs) / sizeof(u32)); ++ ++ ip = instruction_pointer(regs); ++ tmp = *(ptr + (reg_ptr % n)); ++ tmp = lrng_raw_regs_entropy_store(tmp) ? 0 : tmp; ++ _lrng_irq_array_add_u32(tmp); ++ } else { ++ ip = _RET_IP_; ++ } ++ ++ lrng_time_process(); ++ ++ /* ++ * The XOR operation combining the different values is not ++ * considered to destroy entropy since the entirety of all ++ * processed values delivers the entropy (and not each ++ * value separately of the other values). ++ */ ++ tmp = lrng_raw_jiffies_entropy_store(jiffies) ? 0 : jiffies; ++ tmp ^= lrng_raw_irq_entropy_store(irq) ? 0 : irq; ++ tmp ^= lrng_raw_retip_entropy_store(ip) ? 0 : ip; ++ tmp ^= ip >> 32; ++ _lrng_irq_array_add_u32(tmp); ++ } ++} ++EXPORT_SYMBOL(add_interrupt_randomness); ++ ++static void lrng_irq_es_state(unsigned char *buf, size_t buflen) ++{ ++ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ ++ /* Assume the lrng_drng_init lock is taken by caller */ ++ snprintf(buf, buflen, ++ " Hash for operating entropy pool: %s\n" ++ " Available entropy: %u\n" ++ " per-CPU interrupt collection size: %u\n" ++ " Standards compliance: %s\n" ++ " High-resolution timer: %s\n" ++ " Continuous compression: %s\n" ++ " Health test passed: %s\n", ++ lrng_drng_init->hash_cb->hash_name(), ++ lrng_irq_avail_entropy(0), ++ LRNG_DATA_NUM_VALUES, ++ lrng_sp80090b_compliant(lrng_int_es_irq) ? "SP800-90B " : "", ++ lrng_highres_timer() ? "true" : "false", ++ lrng_irq_continuous_compression ? "true" : "false", ++ lrng_sp80090b_startup_complete_es(lrng_int_es_irq) ? "true" : ++ "false"); ++} ++ ++struct lrng_es_cb lrng_es_irq = { ++ .name = "IRQ", ++ .get_ent = lrng_irq_pool_hash, ++ .curr_entropy = lrng_irq_avail_entropy, ++ .max_entropy = lrng_irq_avail_pool_size, ++ .state = lrng_irq_es_state, ++ .reset = lrng_irq_reset, ++ .switch_hash = lrng_irq_switch_hash, ++}; diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch new file mode 100644 index 000000000..cfe8ea407 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -0,0 +1,35 @@ +From 3f214277bf0fc706f883719b5f56a25955487e9c Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 16:39:02 +0200 +Subject: [PATCH 12/25] scheduler - add entropy sampling hook + +The scheduler can be used as a source of entropy. This requires the +presence of a hook that invokes the entropy source implementation. + +When the scheduler-based entropy source is not compiled, the hook is +folded into a noop which does not affect the scheduler in any way. + +Signed-off-by: Stephan Mueller +--- + kernel/sched/core.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -7,6 +7,7 @@ + * Copyright (C) 1991-2002 Linus Torvalds + * Copyright (C) 1998-2024 Ingo Molnar, Red Hat + */ ++#include + #include + #include + #include +@@ -3515,6 +3516,8 @@ ttwu_stat(struct task_struct *p, int cpu + { + struct rq *rq; + ++ add_sched_randomness(p, cpu); ++ + if (!schedstat_enabled()) + return; + diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch new file mode 100644 index 000000000..1b9fb3828 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch @@ -0,0 +1,914 @@ +From c83a2b55d00ccf38e9034664245a286ce5792be7 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Wed, 22 Feb 2023 07:05:59 +0100 +Subject: [PATCH 13/25] LRNG - add scheduler-based entropy source + +The scheduler-based entropy source (ES) consumes the events triggered by +the kernel invoked with the add_sched_randomness. Its main goal is: + +- to be extremely fast in the scheduler context - This is guaranteed by + only concatenating the least significant bits of a time stamp into + CPU-local entropy pools. Thus, the operation is quasi-lockless. Also, + the concatenation is a very trivial operation. Finally, by discarding + the high-order bits, attacker-observable timing values are discarded. + +- to use only cryptographic primitives for compression. + +The scheduler entropy pool collects noise data from context-switch +timing. Any data received by the LRNG from the interrupt noise sources +is inserted into a per-CPU entropy pool using a concatenation operation. +The following processing concept is applied + + (a) When an interrupt occurs, the 8 least significant bits of the + high-resolution time stamp divided by the greatest common divisor (GCD) + is mixed into the per-CPU entropy pool. This time stamp is credited with + heuristically implied entropy. + + (b) Only in process context when a reseed of the DRNG is requested, + the compression of the entropy pool data is performed using a hash. + When the entropy pool is full (i.e. sufficient scheduling event data + is received and yet no compression is performed), the oldest entropy + pool entries are overwritten with the current entry. Thus, the entropy + pool acts as a ring buffer. + +To speed up the scheduling operation code of the LRNG, the time stamp +collected for an interrupt event is divided by the greatest common +divisor to eliminate fixed low bits and then truncated to the 8 least +significant bits. 1024 truncated time stamps are concatenated and then +jointly inserted into the per-CPU entropy pool. During boot time, +until the fully seeded stage is reached, each time stamp with its +32 least significant bits is are concatenated. When 1024/32 = 32 such +events are received, they are injected into the per-CPU entropy pool. + +Considering the possibility that IRQ events cause at the same time +scheduling events (e.g. the IRQ tasklet is executed), only one of those +two entropy sources can ever be configured to deliver entropy. The +respective other ES may deliver data, but never increases the entropy +estimator of the LRNG. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 122 +++---- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_es_sched.c | 566 ++++++++++++++++++++++++++++++ + drivers/char/lrng/lrng_health.h | 42 +++ + drivers/char/lrng/lrng_testing.h | 85 +++++ + 5 files changed, 755 insertions(+), 61 deletions(-) + create mode 100644 drivers/char/lrng/lrng_es_sched.c + create mode 100644 drivers/char/lrng/lrng_health.h + create mode 100644 drivers/char/lrng/lrng_testing.h + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -141,9 +141,9 @@ comment "Common Timer-based Entropy Sour + config LRNG_IRQ_DFLT_TIMER_ES + bool + +-# config LRNG_SCHED_DFLT_TIMER_ES +-# bool +-# ++config LRNG_SCHED_DFLT_TIMER_ES ++ bool ++ + config LRNG_TIMER_COMMON + bool + +@@ -164,12 +164,12 @@ choice + The interrupt entropy source is selected as a timer-based + entropy source to provide entropy. + +-# config LRNG_SCHED_DFLT_TIMER_ES +-# bool "Scheduler Entropy Source" +-# depends on LRNG_SCHED +-# help +-# The scheduler entropy source is selected as timer-based +-# entropy source to provide entropy. ++ config LRNG_SCHED_DFLT_TIMER_ES ++ bool "Scheduler Entropy Source" ++ depends on LRNG_SCHED ++ help ++ The scheduler entropy source is selected as timer-based ++ entropy source to provide entropy. + endchoice + + choice +@@ -534,58 +534,58 @@ config LRNG_IRQ_ENTROPY_RATE + # Note, this option is overwritten when the option + # CONFIG_RANDOM_TRUST_CPU is set. + # +-# comment "Scheduler Entropy Source" +-# +-# config LRNG_SCHED +-# bool "Enable Scheduer Entropy Source as LRNG Seed Source" +-# select LRNG_TIMER_COMMON +-# help +-# The LRNG models an entropy source based on the timing of the +-# occurrence of scheduler-triggered context switches. Enable +-# this option to enable this scheduler entropy source. +-# +-# The scheduler entropy source is triggered every time a +-# context switch is triggered thus causes the scheduler to +-# execute slightly longer. Disabling the scheduler entropy +-# source implies that the performance penalty on the scheduler +-# added by the LRNG is eliminated. Yet, this entropy source is +-# considered to be an internal entropy source of the LRNG. +-# Thus, only disable it if you ensured that other entropy +-# sources are available that supply the LRNG with entropy. +-# +-# If you disable the scheduler entropy source, you MUST +-# ensure one or more entropy sources collectively have the +-# capability to deliver sufficient entropy with one invocation +-# at a rate compliant to the security strength of the DRNG +-# (usually 256 bits of entropy). In addition, if those +-# entropy sources do not deliver sufficient entropy during +-# first request, the reseed must be triggered from user +-# space or kernel space when sufficient entropy is considered +-# to be present. +-# +-# If unsure, say Y. +-# +-# config LRNG_SCHED_ENTROPY_RATE +-# int "Scheduler Entropy Source Entropy Rate" +-# depends on LRNG_SCHED +-# range 256 4294967295 if LRNG_SCHED_DFLT_TIMER_ES +-# range 4294967295 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES +-# default 256 if LRNG_SCHED_DFLT_TIMER_ES +-# default 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES +-# help +-# The LRNG will collect the configured number of context switches +-# triggered by the scheduler to obtain 256 bits of entropy. This +-# value can be set to any between 256 and 4294967295. The LRNG +-# guarantees that this value is not lower than 256. This lower +-# limit implies that one interrupt event is credited with one bit +-# of entropy. This value is subject to the increase by the +-# oversampling factor, if no high-resolution timer is found. +-# +-# In order to effectively disable the scheduler entropy source, +-# the option has to be set to 4294967295. In this case, the +-# scheduler entropy source will still deliver data but without +-# being credited with entropy. +-# ++comment "Scheduler Entropy Source" ++ ++config LRNG_SCHED ++ bool "Enable Scheduer Entropy Source as LRNG Seed Source" ++ select LRNG_TIMER_COMMON ++ help ++ The LRNG models an entropy source based on the timing of the ++ occurrence of scheduler-triggered context switches. Enable ++ this option to enable this scheduler entropy source. ++ ++ The scheduler entropy source is triggered every time a ++ context switch is triggered thus causes the scheduler to ++ execute slightly longer. Disabling the scheduler entropy ++ source implies that the performance penalty on the scheduler ++ added by the LRNG is eliminated. Yet, this entropy source is ++ considered to be an internal entropy source of the LRNG. ++ Thus, only disable it if you ensured that other entropy ++ sources are available that supply the LRNG with entropy. ++ ++ If you disable the scheduler entropy source, you MUST ++ ensure one or more entropy sources collectively have the ++ capability to deliver sufficient entropy with one invocation ++ at a rate compliant to the security strength of the DRNG ++ (usually 256 bits of entropy). In addition, if those ++ entropy sources do not deliver sufficient entropy during ++ first request, the reseed must be triggered from user ++ space or kernel space when sufficient entropy is considered ++ to be present. ++ ++ If unsure, say Y. ++ ++config LRNG_SCHED_ENTROPY_RATE ++ int "Scheduler Entropy Source Entropy Rate" ++ depends on LRNG_SCHED ++ range 256 4294967295 if LRNG_SCHED_DFLT_TIMER_ES ++ range 4294967295 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES ++ default 256 if LRNG_SCHED_DFLT_TIMER_ES ++ default 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES ++ help ++ The LRNG will collect the configured number of context switches ++ triggered by the scheduler to obtain 256 bits of entropy. This ++ value can be set to any between 256 and 4294967295. The LRNG ++ guarantees that this value is not lower than 256. This lower ++ limit implies that one interrupt event is credited with one bit ++ of entropy. This value is subject to the increase by the ++ oversampling factor, if no high-resolution timer is found. ++ ++ In order to effectively disable the scheduler entropy source, ++ the option has to be set to 4294967295. In this case, the ++ scheduler entropy source will still deliver data but without ++ being credited with entropy. ++ + # comment "Kernel RNG Entropy Source" + # + # config LRNG_KERNEL_RNG +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -20,3 +20,4 @@ obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_ + + obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o + obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o ++obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_sched.c +@@ -0,0 +1,566 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Slow Entropy Source: Scheduler-based data collection ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_es_aux.h" ++#include "lrng_es_sched.h" ++#include "lrng_es_timer_common.h" ++#include "lrng_health.h" ++#include "lrng_numa.h" ++#include "lrng_testing.h" ++ ++/* ++ * Number of scheduler-based context switches to be recorded to assume that ++ * DRNG security strength bits of entropy are received. ++ * Note: a value below the DRNG security strength should not be defined as this ++ * may imply the DRNG can never be fully seeded in case other noise ++ * sources are unavailable. ++ */ ++#define LRNG_SCHED_ENTROPY_BITS \ ++ LRNG_UINT32_C(CONFIG_LRNG_SCHED_ENTROPY_RATE) ++ ++/* Number of events required for LRNG_DRNG_SECURITY_STRENGTH_BITS entropy */ ++static u32 lrng_sched_entropy_bits = LRNG_SCHED_ENTROPY_BITS; ++ ++static u32 sched_entropy __read_mostly = LRNG_SCHED_ENTROPY_BITS; ++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG ++module_param(sched_entropy, uint, 0444); ++MODULE_PARM_DESC(sched_entropy, ++ "How many scheduler-based context switches must be collected for obtaining 256 bits of entropy\n"); ++#endif ++ ++/* Per-CPU array holding concatenated entropy events */ ++static DEFINE_PER_CPU(u32 [LRNG_DATA_ARRAY_SIZE], lrng_sched_array) ++ __aligned(LRNG_KCAPI_ALIGN); ++static DEFINE_PER_CPU(u32, lrng_sched_array_ptr) = 0; ++static DEFINE_PER_CPU(atomic_t, lrng_sched_array_events) = ATOMIC_INIT(0); ++ ++/* ++ * Per-CPU entropy pool with compressed entropy event ++ * ++ * The per-CPU entropy pool is defined as the hash state. New data is simply ++ * inserted into the entropy pool by performing a hash update operation. ++ * To read the entropy pool, a hash final must be invoked. However, before ++ * the entropy pool is released again after a hash final, the hash init must ++ * be performed. ++ */ ++static DEFINE_PER_CPU(u8 [LRNG_POOL_SIZE], lrng_sched_pool) ++ __aligned(LRNG_KCAPI_ALIGN); ++/* ++ * Lock to allow other CPUs to read the pool - as this is only done during ++ * reseed which is infrequent, this lock is hardly contended. ++ */ ++static DEFINE_PER_CPU(spinlock_t, lrng_sched_lock); ++static DEFINE_PER_CPU(bool, lrng_sched_lock_init) = false; ++ ++static bool lrng_sched_pool_online(int cpu) ++{ ++ return per_cpu(lrng_sched_lock_init, cpu); ++} ++ ++static void __init lrng_sched_check_compression_state(void) ++{ ++ /* One pool should hold sufficient entropy for disabled compression */ ++ u32 max_ent = min_t(u32, lrng_get_digestsize(), ++ lrng_data_to_entropy(LRNG_DATA_NUM_VALUES, ++ lrng_sched_entropy_bits)); ++ if (max_ent < lrng_security_strength()) { ++ pr_devel("Scheduler entropy source will never provide %u bits of entropy required for fully seeding the DRNG all by itself\n", ++ lrng_security_strength()); ++ } ++} ++ ++void __init lrng_sched_es_init(bool highres_timer) ++{ ++ /* Set a minimum number of scheduler events that must be collected */ ++ sched_entropy = max_t(u32, LRNG_SCHED_ENTROPY_BITS, sched_entropy); ++ ++ if (highres_timer) { ++ lrng_sched_entropy_bits = sched_entropy; ++ } else { ++ u32 new_entropy = sched_entropy * LRNG_ES_OVERSAMPLING_FACTOR; ++ ++ lrng_sched_entropy_bits = (sched_entropy < new_entropy) ? ++ new_entropy : sched_entropy; ++ pr_warn("operating without high-resolution timer and applying oversampling factor %u\n", ++ LRNG_ES_OVERSAMPLING_FACTOR); ++ } ++ ++ lrng_sched_check_compression_state(); ++} ++ ++static u32 lrng_sched_avail_pool_size(void) ++{ ++ u32 max_pool = lrng_get_digestsize(), ++ max_size = min_t(u32, max_pool, LRNG_DATA_NUM_VALUES); ++ int cpu; ++ ++ for_each_online_cpu(cpu) ++ max_size += max_pool; ++ ++ return max_size; ++} ++ ++/* Return entropy of unused scheduler events present in all per-CPU pools. */ ++static u32 lrng_sched_avail_entropy(u32 __unused) ++{ ++ u32 digestsize_events, events = 0; ++ int cpu; ++ ++ /* Only deliver entropy when SP800-90B self test is completed */ ++ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_sched)) ++ return 0; ++ ++ /* Obtain the cap of maximum numbers of scheduler events we count */ ++ digestsize_events = lrng_entropy_to_data(lrng_get_digestsize(), ++ lrng_sched_entropy_bits); ++ /* Cap to max. number of scheduler events the array can hold */ ++ digestsize_events = min_t(u32, digestsize_events, LRNG_DATA_NUM_VALUES); ++ ++ for_each_online_cpu(cpu) { ++ events += min_t(u32, digestsize_events, ++ atomic_read_u32(per_cpu_ptr(&lrng_sched_array_events, ++ cpu))); ++ } ++ ++ /* Consider oversampling rate */ ++ return lrng_reduce_by_osr( ++ lrng_data_to_entropy(events, lrng_sched_entropy_bits)); ++} ++ ++/* ++ * Reset all per-CPU pools - reset entropy estimator but leave the pool data ++ * that may or may not have entropy unchanged. ++ */ ++static void lrng_sched_reset(void) ++{ ++ int cpu; ++ ++ /* Trigger GCD calculation anew. */ ++ lrng_gcd_set(0); ++ ++ for_each_online_cpu(cpu) ++ atomic_set(per_cpu_ptr(&lrng_sched_array_events, cpu), 0); ++} ++ ++/* ++ * Trigger a switch of the hash implementation for the per-CPU pool. ++ * ++ * For each per-CPU pool, obtain the message digest with the old hash ++ * implementation, initialize the per-CPU pool again with the new hash ++ * implementation and inject the message digest into the new state. ++ * ++ * Assumption: the caller must guarantee that the new_cb is available during the ++ * entire operation (e.g. it must hold the lock against pointer updating). ++ */ ++static int ++lrng_sched_switch_hash(struct lrng_drng *drng, int node, ++ const struct lrng_hash_cb *new_cb, void *new_hash, ++ const struct lrng_hash_cb *old_cb) ++{ ++ u8 digest[LRNG_MAX_DIGESTSIZE]; ++ u32 digestsize_events, found_events; ++ int ret = 0, cpu; ++ ++ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) ++ return -EOPNOTSUPP; ++ ++ for_each_online_cpu(cpu) { ++ struct shash_desc *pcpu_shash; ++ ++ /* ++ * Only switch the per-CPU pools for the current node because ++ * the hash_cb only applies NUMA-node-wide. ++ */ ++ if (cpu_to_node(cpu) != node || !lrng_sched_pool_online(cpu)) ++ continue; ++ ++ pcpu_shash = (struct shash_desc *)per_cpu_ptr(lrng_sched_pool, ++ cpu); ++ ++ digestsize_events = old_cb->hash_digestsize(pcpu_shash); ++ digestsize_events = lrng_entropy_to_data(digestsize_events << 3, ++ lrng_sched_entropy_bits); ++ ++ if (pcpu_shash->tfm == new_hash) ++ continue; ++ ++ /* Get the per-CPU pool hash with old digest ... */ ++ ret = old_cb->hash_final(pcpu_shash, digest) ?: ++ /* ... re-initialize the hash with the new digest ... */ ++ new_cb->hash_init(pcpu_shash, new_hash) ?: ++ /* ++ * ... feed the old hash into the new state. We may feed ++ * uninitialized memory into the new state, but this is ++ * considered no issue and even good as we have some more ++ * uncertainty here. ++ */ ++ new_cb->hash_update(pcpu_shash, digest, sizeof(digest)); ++ if (ret) ++ goto out; ++ ++ /* ++ * In case the new digest is larger than the old one, cap ++ * the available entropy to the old message digest used to ++ * process the existing data. ++ */ ++ found_events = atomic_xchg_relaxed( ++ per_cpu_ptr(&lrng_sched_array_events, cpu), 0); ++ found_events = min_t(u32, found_events, digestsize_events); ++ atomic_add_return_relaxed(found_events, ++ per_cpu_ptr(&lrng_sched_array_events, cpu)); ++ ++ pr_debug("Re-initialize per-CPU scheduler entropy pool for CPU %d on NUMA node %d with hash %s\n", ++ cpu, node, new_cb->hash_name()); ++ } ++ ++out: ++ memzero_explicit(digest, sizeof(digest)); ++ return ret; ++} ++ ++static u32 ++lrng_sched_pool_hash_one(const struct lrng_hash_cb *pcpu_hash_cb, ++ void *pcpu_hash, int cpu, u8 *digest, u32 *digestsize) ++{ ++ struct shash_desc *pcpu_shash = ++ (struct shash_desc *)per_cpu_ptr(lrng_sched_pool, cpu); ++ spinlock_t *lock = per_cpu_ptr(&lrng_sched_lock, cpu); ++ unsigned long flags; ++ u32 digestsize_events, found_events; ++ ++ if (unlikely(!per_cpu(lrng_sched_lock_init, cpu))) { ++ if (pcpu_hash_cb->hash_init(pcpu_shash, pcpu_hash)) { ++ pr_warn("Initialization of hash failed\n"); ++ return 0; ++ } ++ spin_lock_init(lock); ++ per_cpu(lrng_sched_lock_init, cpu) = true; ++ pr_debug("Initializing per-CPU scheduler entropy pool for CPU %d with hash %s\n", ++ raw_smp_processor_id(), pcpu_hash_cb->hash_name()); ++ } ++ ++ /* Lock guarding against reading / writing to per-CPU pool */ ++ spin_lock_irqsave(lock, flags); ++ ++ *digestsize = pcpu_hash_cb->hash_digestsize(pcpu_hash); ++ digestsize_events = lrng_entropy_to_data(*digestsize << 3, ++ lrng_sched_entropy_bits); ++ ++ /* Obtain entropy statement like for the entropy pool */ ++ found_events = atomic_xchg_relaxed( ++ per_cpu_ptr(&lrng_sched_array_events, cpu), 0); ++ /* Cap to maximum amount of data we can hold in hash */ ++ found_events = min_t(u32, found_events, digestsize_events); ++ ++ /* Cap to maximum amount of data we can hold in array */ ++ found_events = min_t(u32, found_events, LRNG_DATA_NUM_VALUES); ++ ++ /* Store all not-yet compressed data in data array into hash, ... */ ++ if (pcpu_hash_cb->hash_update(pcpu_shash, ++ (u8 *)per_cpu_ptr(lrng_sched_array, cpu), ++ LRNG_DATA_ARRAY_SIZE * sizeof(u32)) ?: ++ /* ... get the per-CPU pool digest, ... */ ++ pcpu_hash_cb->hash_final(pcpu_shash, digest) ?: ++ /* ... re-initialize the hash, ... */ ++ pcpu_hash_cb->hash_init(pcpu_shash, pcpu_hash) ?: ++ /* ... feed the old hash into the new state. */ ++ pcpu_hash_cb->hash_update(pcpu_shash, digest, *digestsize)) ++ found_events = 0; ++ ++ spin_unlock_irqrestore(lock, flags); ++ return found_events; ++} ++ ++/* ++ * Hash all per-CPU arrays and return the digest to be used as seed data for ++ * seeding a DRNG. The caller must guarantee backtracking resistance. ++ * The function will only copy as much data as entropy is available into the ++ * caller-provided output buffer. ++ * ++ * This function handles the translation from the number of received scheduler ++ * events into an entropy statement. The conversion depends on ++ * LRNG_SCHED_ENTROPY_BITS which defines how many scheduler events must be ++ * received to obtain 256 bits of entropy. With this value, the function ++ * lrng_data_to_entropy converts a given data size (received scheduler events, ++ * requested amount of data, etc.) into an entropy statement. ++ * lrng_entropy_to_data does the reverse. ++ * ++ * @eb: entropy buffer to store entropy ++ * @requested_bits: Requested amount of entropy ++ * @fully_seeded: indicator whether LRNG is fully seeded ++ */ ++static void lrng_sched_pool_hash(struct entropy_buf *eb, u32 requested_bits, ++ bool fully_seeded) ++{ ++ SHASH_DESC_ON_STACK(shash, NULL); ++ const struct lrng_hash_cb *hash_cb; ++ struct lrng_drng **lrng_drng = lrng_drng_instances(); ++ struct lrng_drng *drng = lrng_drng_init_instance(); ++ u8 digest[LRNG_MAX_DIGESTSIZE]; ++ unsigned long flags, flags2; ++ u32 found_events, collected_events = 0, collected_ent_bits, ++ requested_events, returned_ent_bits; ++ int ret, cpu; ++ void *hash; ++ ++ /* Only deliver entropy when SP800-90B self test is completed */ ++ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_sched)) { ++ eb->e_bits[lrng_int_es_sched] = 0; ++ return; ++ } ++ ++ /* Lock guarding replacement of per-NUMA hash */ ++ read_lock_irqsave(&drng->hash_lock, flags); ++ ++ hash_cb = drng->hash_cb; ++ hash = drng->hash; ++ ++ /* The hash state of filled with all per-CPU pool hashes. */ ++ ret = hash_cb->hash_init(shash, hash); ++ if (ret) ++ goto err; ++ ++ /* Cap to maximum entropy that can ever be generated with given hash */ ++ lrng_cap_requested(hash_cb->hash_digestsize(hash) << 3, requested_bits); ++ requested_events = lrng_entropy_to_data(requested_bits + ++ lrng_compress_osr(), ++ lrng_sched_entropy_bits); ++ ++ /* ++ * Harvest entropy from each per-CPU hash state - even though we may ++ * have collected sufficient entropy, we will hash all per-CPU pools. ++ */ ++ for_each_online_cpu(cpu) { ++ struct lrng_drng *pcpu_drng = drng; ++ u32 digestsize, unused_events = 0; ++ int node = cpu_to_node(cpu); ++ ++ if (lrng_drng && lrng_drng[node]) ++ pcpu_drng = lrng_drng[node]; ++ ++ if (pcpu_drng == drng) { ++ found_events = lrng_sched_pool_hash_one(hash_cb, hash, ++ cpu, digest, ++ &digestsize); ++ } else { ++ read_lock_irqsave(&pcpu_drng->hash_lock, flags2); ++ found_events = ++ lrng_sched_pool_hash_one(pcpu_drng->hash_cb, ++ pcpu_drng->hash, cpu, ++ digest, &digestsize); ++ read_unlock_irqrestore(&pcpu_drng->hash_lock, flags2); ++ } ++ ++ /* Store all not-yet compressed data in data array into hash */ ++ ret = hash_cb->hash_update(shash, digest, digestsize); ++ if (ret) ++ goto err; ++ ++ collected_events += found_events; ++ if (collected_events > requested_events) { ++ unused_events = collected_events - requested_events; ++ atomic_add_return_relaxed(unused_events, ++ per_cpu_ptr(&lrng_sched_array_events, cpu)); ++ collected_events = requested_events; ++ } ++ pr_debug("%u scheduler-based events used from entropy array of CPU %d, %u scheduler-based events remain unused\n", ++ found_events - unused_events, cpu, unused_events); ++ } ++ ++ ret = hash_cb->hash_final(shash, digest); ++ if (ret) ++ goto err; ++ ++ collected_ent_bits = lrng_data_to_entropy(collected_events, ++ lrng_sched_entropy_bits); ++ /* Apply oversampling: discount requested oversampling rate */ ++ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits); ++ ++ pr_debug("obtained %u bits by collecting %u bits of entropy from scheduler-based noise source\n", ++ returned_ent_bits, collected_ent_bits); ++ ++ /* ++ * Truncate to available entropy as implicitly allowed by SP800-90B ++ * section 3.1.5.1.1 table 1 which awards truncated hashes full ++ * entropy. ++ * ++ * During boot time, we read requested_bits data with ++ * returned_ent_bits entropy. In case our conservative entropy ++ * estimate underestimates the available entropy we can transport as ++ * much available entropy as possible. ++ */ ++ memcpy(eb->e[lrng_int_es_sched], digest, ++ fully_seeded ? returned_ent_bits >> 3 : requested_bits >> 3); ++ eb->e_bits[lrng_int_es_sched] = returned_ent_bits; ++ ++out: ++ hash_cb->hash_desc_zero(shash); ++ read_unlock_irqrestore(&drng->hash_lock, flags); ++ memzero_explicit(digest, sizeof(digest)); ++ return; ++ ++err: ++ eb->e_bits[lrng_int_es_sched] = 0; ++ goto out; ++} ++ ++/* ++ * Concatenate full 32 bit word at the end of time array even when current ++ * ptr is not aligned to sizeof(data). ++ */ ++static void lrng_sched_array_add_u32(u32 data) ++{ ++ /* Increment pointer by number of slots taken for input value */ ++ u32 pre_ptr, mask, ptr = this_cpu_add_return(lrng_sched_array_ptr, ++ LRNG_DATA_SLOTS_PER_UINT); ++ unsigned int pre_array; ++ ++ lrng_data_split_u32(&ptr, &pre_ptr, &mask); ++ ++ /* MSB of data go into previous unit */ ++ pre_array = lrng_data_idx2array(pre_ptr); ++ /* zeroization of slot to ensure the following OR adds the data */ ++ this_cpu_and(lrng_sched_array[pre_array], ~(0xffffffff & ~mask)); ++ this_cpu_or(lrng_sched_array[pre_array], data & ~mask); ++ ++ /* ++ * Continuous compression is not allowed for scheduler noise source, ++ * so do not call lrng_sched_array_to_hash here. ++ */ ++ ++ /* LSB of data go into current unit */ ++ this_cpu_write(lrng_sched_array[lrng_data_idx2array(ptr)], ++ data & mask); ++} ++ ++/* Concatenate data of max LRNG_DATA_SLOTSIZE_MASK at the end of time array */ ++static void lrng_sched_array_add_slot(u32 data) ++{ ++ /* Get slot */ ++ u32 ptr = this_cpu_inc_return(lrng_sched_array_ptr) & ++ LRNG_DATA_WORD_MASK; ++ unsigned int array = lrng_data_idx2array(ptr); ++ unsigned int slot = lrng_data_idx2slot(ptr); ++ ++ /* zeroization of slot to ensure the following OR adds the data */ ++ this_cpu_and(lrng_sched_array[array], ++ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK, ++ slot))); ++ /* Store data into slot */ ++ this_cpu_or(lrng_sched_array[array], lrng_data_slot_val(data, slot)); ++ ++ /* ++ * Continuous compression is not allowed for scheduler noise source, ++ * so do not call lrng_sched_array_to_hash here. ++ */ ++} ++ ++static void ++lrng_time_process_common(u32 time, void(*add_time)(u32 data)) ++{ ++ enum lrng_health_res health_test; ++ ++ if (lrng_raw_sched_hires_entropy_store(time)) ++ return; ++ ++ health_test = lrng_health_test(time, lrng_int_es_sched); ++ if (health_test > lrng_health_fail_use) ++ return; ++ ++ if (health_test == lrng_health_pass) ++ atomic_inc_return(this_cpu_ptr(&lrng_sched_array_events)); ++ ++ add_time(time); ++ ++ /* ++ * We cannot call lrng_es_add_entropy() as this would call a schedule ++ * operation that is not permissible in scheduler context. ++ * As the scheduler ES provides a high bandwidth of entropy, we assume ++ * that other reseed triggers happen to pick up the scheduler ES ++ * entropy in due time. ++ */ ++} ++ ++/* Batching up of entropy in per-CPU array */ ++static void lrng_sched_time_process(void) ++{ ++ u32 now_time = random_get_entropy(); ++ ++ if (unlikely(!lrng_gcd_tested())) { ++ /* When GCD is unknown, we process the full time stamp */ ++ lrng_time_process_common(now_time, lrng_sched_array_add_u32); ++ lrng_gcd_add_value(now_time); ++ } else { ++ /* GCD is known and applied */ ++ lrng_time_process_common((now_time / lrng_gcd_get()) & ++ LRNG_DATA_SLOTSIZE_MASK, ++ lrng_sched_array_add_slot); ++ } ++ ++ lrng_sched_perf_time(now_time); ++} ++ ++void add_sched_randomness(const struct task_struct *p, int cpu) ++{ ++ if (lrng_highres_timer()) { ++ lrng_sched_time_process(); ++ } else { ++ u32 tmp = cpu; ++ ++ tmp ^= lrng_raw_sched_pid_entropy_store(p->pid) ? ++ 0 : (u32)p->pid; ++ tmp ^= lrng_raw_sched_starttime_entropy_store(p->start_time) ? ++ 0 : (u32)p->start_time; ++ tmp ^= lrng_raw_sched_nvcsw_entropy_store(p->nvcsw) ? ++ 0 : (u32)p->nvcsw; ++ ++ lrng_sched_time_process(); ++ lrng_sched_array_add_u32(tmp); ++ } ++} ++EXPORT_SYMBOL(add_sched_randomness); ++ ++static void lrng_sched_es_state(unsigned char *buf, size_t buflen) ++{ ++ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ ++ /* Assume the lrng_drng_init lock is taken by caller */ ++ snprintf(buf, buflen, ++ " Hash for operating entropy pool: %s\n" ++ " Available entropy: %u\n" ++ " per-CPU scheduler event collection size: %u\n" ++ " Standards compliance: %s\n" ++ " High-resolution timer: %s\n" ++ " Health test passed: %s\n", ++ lrng_drng_init->hash_cb->hash_name(), ++ lrng_sched_avail_entropy(0), ++ LRNG_DATA_NUM_VALUES, ++ lrng_sp80090b_compliant(lrng_int_es_sched) ? "SP800-90B " : "", ++ lrng_highres_timer() ? "true" : "false", ++ lrng_sp80090b_startup_complete_es(lrng_int_es_sched) ? ++ "true" : ++ "false"); ++} ++ ++struct lrng_es_cb lrng_es_sched = { ++ .name = "Scheduler", ++ .get_ent = lrng_sched_pool_hash, ++ .curr_entropy = lrng_sched_avail_entropy, ++ .max_entropy = lrng_sched_avail_pool_size, ++ .state = lrng_sched_es_state, ++ .reset = lrng_sched_reset, ++ .switch_hash = lrng_sched_switch_hash, ++}; +--- /dev/null ++++ b/drivers/char/lrng/lrng_health.h +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_HEALTH_H ++#define _LRNG_HEALTH_H ++ ++#include "lrng_es_mgr.h" ++ ++enum lrng_health_res { ++ lrng_health_pass, /* Health test passes on time stamp */ ++ lrng_health_fail_use, /* Time stamp unhealthy, but mix in */ ++ lrng_health_fail_drop /* Time stamp unhealthy, drop it */ ++}; ++ ++#ifdef CONFIG_LRNG_HEALTH_TESTS ++bool lrng_sp80090b_startup_complete_es(enum lrng_internal_es es); ++bool lrng_sp80090b_compliant(enum lrng_internal_es es); ++ ++enum lrng_health_res lrng_health_test(u32 now_time, enum lrng_internal_es es); ++void lrng_health_disable(void); ++#else /* CONFIG_LRNG_HEALTH_TESTS */ ++static inline bool lrng_sp80090b_startup_complete_es(enum lrng_internal_es es) ++{ ++ return true; ++} ++ ++static inline bool lrng_sp80090b_compliant(enum lrng_internal_es es) ++{ ++ return false; ++} ++ ++static inline enum lrng_health_res ++lrng_health_test(u32 now_time, enum lrng_internal_es es) ++{ ++ return lrng_health_pass; ++} ++static inline void lrng_health_disable(void) { } ++#endif /* CONFIG_LRNG_HEALTH_TESTS */ ++ ++#endif /* _LRNG_HEALTH_H */ +--- /dev/null ++++ b/drivers/char/lrng/lrng_testing.h +@@ -0,0 +1,85 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#ifndef _LRNG_TESTING_H ++#define _LRNG_TESTING_H ++ ++#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY ++bool lrng_raw_hires_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_HIRES_ENTROPY */ ++static inline bool lrng_raw_hires_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY ++bool lrng_raw_jiffies_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */ ++static inline bool lrng_raw_jiffies_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY ++bool lrng_raw_irq_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_IRQ_ENTROPY */ ++static inline bool lrng_raw_irq_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY ++bool lrng_raw_retip_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_RETIP_ENTROPY */ ++static inline bool lrng_raw_retip_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY ++bool lrng_raw_regs_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_REGS_ENTROPY */ ++static inline bool lrng_raw_regs_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_ARRAY ++bool lrng_raw_array_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_ARRAY */ ++static inline bool lrng_raw_array_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_ARRAY */ ++ ++#ifdef CONFIG_LRNG_IRQ_PERF ++bool lrng_perf_time(u32 start); ++#else /* CONFIG_LRNG_IRQ_PERF */ ++static inline bool lrng_perf_time(u32 start) { return false; } ++#endif /*CONFIG_LRNG_IRQ_PERF */ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY ++bool lrng_raw_sched_hires_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY */ ++static inline bool ++lrng_raw_sched_hires_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY ++bool lrng_raw_sched_pid_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_SCHED_PID_ENTROPY */ ++static inline bool ++lrng_raw_sched_pid_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_SCHED_PID_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY ++bool lrng_raw_sched_starttime_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY */ ++static inline bool ++lrng_raw_sched_starttime_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY ++bool lrng_raw_sched_nvcsw_entropy_store(u32 value); ++#else /* CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY */ ++static inline bool ++lrng_raw_sched_nvcsw_entropy_store(u32 value) { return false; } ++#endif /* CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY */ ++ ++#ifdef CONFIG_LRNG_SCHED_PERF ++bool lrng_sched_perf_time(u32 start); ++#else /* CONFIG_LRNG_SCHED_PERF */ ++static inline bool lrng_sched_perf_time(u32 start) { return false; } ++#endif /*CONFIG_LRNG_SCHED_PERF */ ++ ++#endif /* _LRNG_TESTING_H */ diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch new file mode 100644 index 000000000..19a9e974a --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch @@ -0,0 +1,731 @@ +From 77e3f8edebcba3cc3b60b654fa0ef12e73f4e378 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Tue, 25 Apr 2023 23:13:30 +0200 +Subject: [PATCH 14/25] LRNG - add SP800-90B compliant health tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implement health tests for LRNG's internal entropy sources as mandated +by SP-800-90B. These internal entropy sources (scheduler and IRQ ES) +both rest on high-resolution time stamps as their noise source. The patch +contains the following health tests which are independently enabled and +applied for the mentioned entropy sources.: + +- stuck test: The stuck test calculates the first, second and third + discrete derivative of the time stamp to be processed by the hash + for the per-CPU entropy pool. Only if all three values are non-zero, + the received time delta is considered to be non-stuck. + +- SP800-90B Repetition Count Test (RCT): The LRNG uses an enhanced + version of the RCT specified in SP800-90B section 4.4.1. Instead of + counting identical back-to-back values, the input to the RCT is the + counting of the stuck values during the processing of received + interrupt events. The RCT is applied with alpha=2^-30 compliant to + the recommendation of FIPS 140-2 IG 9.8. During the counting operation, + the LRNG always calculates the RCT cut-off value of C. If that value + exceeds the allowed cut-off value, the LRNG will trigger the health + test failure discussed below. An error is logged to the kernel log + that such RCT failure occurred. This test is only applied and + enforced in FIPS mode, i.e. when the kernel compiled with + CONFIG_CONFIG_FIPS is started with fips=1. + +- SP800-90B Adaptive Proportion Test (APT): The LRNG implements the + APT as defined in SP800-90B section 4.4.2. The applied significance + level again is alpha=2^-30 compliant to the recommendation of FIPS + 140-2 IG 9.8. + +The aforementioned health tests are applied to the first 1,024 time stamps +obtained from interrupt events. In case one error is identified for either +the RCT, or the APT, the collected entropy is invalidated and the +SP800-90B startup health test is restarted. + +As long as the SP800-90B startup health test is not completed, all LRNG +random number output interfaces that may block will block and not generate +any data. This implies that only those potentially blocking interfaces are +defined to provide random numbers that are seeded with the interrupt noise +source being SP800-90B compliant. All other output interfaces will not be +affected by the SP800-90B startup test and thus are not considered +SP800-90B compliant. + +At runtime, the SP800-90B APT and RCT are applied to each time stamp +generated for a received interrupt. When either the APT and RCT indicates +a noise source failure, the LRNG is reset to a state it has immediately +after boot: + +- all entropy counters are set to zero + +- the SP800-90B startup tests are re-performed which implies that +getrandom(2) would block again until new entropy was collected + +To summarize, the following rules apply: + +• SP800-90B compliant output interfaces + + - /dev/random + + - getrandom(2) system call + + - get_random_bytes kernel-internal interface when being triggered by + the callback registered with add_random_ready_callback + +• SP800-90B non-compliant output interfaces + + - /dev/urandom + + - get_random_bytes kernel-internal interface called directly + + - randomize_page kernel-internal interface + + - get_random_u32 and get_random_u64 kernel-internal interfaces + + - get_random_u32_wait, get_random_u64_wait, get_random_int_wait, and + get_random_long_wait kernel-internal interfaces + +If either the RCT, or the APT health test fails irrespective whether +during initialization or runtime, the following actions occur: + + 1. The entropy of the entire entropy pool is invalidated. + + 2. All DRNGs are reset which imply that they are treated as being + not seeded and require a reseed during next invocation. + + 3. The SP800-90B startup health test are initiated with all + implications of the startup tests. That implies that from that point + on, new events must be observed and its entropy must be inserted into + the entropy pool before random numbers are calculated from the + entropy pool. + +Further details on the SP800-90B compliance and the availability of all +test tools required to perform all tests mandated by SP800-90B are +provided at [1]. + +The entire health testing code is compile-time configurable. + +The patch provides a CONFIG_BROKEN configuration of the APT / RCT cutoff +values which have a high likelihood to trigger the health test failure. +The BROKEN APT cutoff is set to the exact mean of the expected value if +the time stamps are equally distributed (512 time stamps divided by 16 +possible values due to using the 4 LSB of the time stamp). The BROKEN +RCT cutoff value is set to 1 which is likely to be triggered during +regular operation. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 140 +++++----- + drivers/char/lrng/Makefile | 2 + + drivers/char/lrng/lrng_health.c | 447 ++++++++++++++++++++++++++++++++ + 3 files changed, 519 insertions(+), 70 deletions(-) + create mode 100644 drivers/char/lrng/lrng_health.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -229,80 +229,80 @@ config LRNG_COLLECTION_SIZE + default 4096 if LRNG_COLLECTION_SIZE_4096 + default 8192 if LRNG_COLLECTION_SIZE_8192 + +-# config LRNG_HEALTH_TESTS +-# bool "Enable internal entropy source online health tests" +-# depends on LRNG_TIMER_COMMON +-# help +-# The online health tests applied to the interrupt entropy +-# source and to the scheduler entropy source to validate +-# the noise source at runtime for fatal errors. These tests +-# include SP800-90B compliant tests which are invoked if +-# the system is booted with fips=1. In case of fatal errors +-# during active SP800-90B tests, the issue is logged and +-# the noise data is discarded. These tests are required for +-# full compliance of the interrupt entropy source with +-# SP800-90B. +-# +-# If both, the scheduler and the interrupt entropy sources, +-# are enabled, the health tests for both are applied +-# independent of each other. +-# +-# If unsure, say Y. +-# +-# config LRNG_RCT_BROKEN +-# bool "SP800-90B RCT with dangerous low cutoff value" +-# depends on LRNG_HEALTH_TESTS +-# depends on BROKEN +-# default n +-# help +-# This option enables a dangerously low SP800-90B repetitive +-# count test (RCT) cutoff value which makes it very likely +-# that the RCT is triggered to raise a self test failure. +-# +-# This option is ONLY intended for developers wanting to +-# test the effectiveness of the SP800-90B RCT health test. +-# +-# If unsure, say N. +-# +-# config LRNG_APT_BROKEN +-# bool "SP800-90B APT with dangerous low cutoff value" +-# depends on LRNG_HEALTH_TESTS +-# depends on BROKEN +-# default n +-# help +-# This option enables a dangerously low SP800-90B adaptive +-# proportion test (APT) cutoff value which makes it very +-# likely that the APT is triggered to raise a self test +-# failure. +-# +-# This option is ONLY intended for developers wanting to +-# test the effectiveness of the SP800-90B APT health test. +-# +-# If unsure, say N. +-# ++config LRNG_HEALTH_TESTS ++ bool "Enable internal entropy source online health tests" ++ depends on LRNG_TIMER_COMMON ++ help ++ The online health tests applied to the interrupt entropy ++ source and to the scheduler entropy source to validate ++ the noise source at runtime for fatal errors. These tests ++ include SP800-90B compliant tests which are invoked if ++ the system is booted with fips=1. In case of fatal errors ++ during active SP800-90B tests, the issue is logged and ++ the noise data is discarded. These tests are required for ++ full compliance of the interrupt entropy source with ++ SP800-90B. ++ ++ If both, the scheduler and the interrupt entropy sources, ++ are enabled, the health tests for both are applied ++ independent of each other. ++ ++ If unsure, say Y. ++ ++config LRNG_RCT_BROKEN ++ bool "SP800-90B RCT with dangerous low cutoff value" ++ depends on LRNG_HEALTH_TESTS ++ depends on BROKEN ++ default n ++ help ++ This option enables a dangerously low SP800-90B repetitive ++ count test (RCT) cutoff value which makes it very likely ++ that the RCT is triggered to raise a self test failure. ++ ++ This option is ONLY intended for developers wanting to ++ test the effectiveness of the SP800-90B RCT health test. ++ ++ If unsure, say N. ++ ++config LRNG_APT_BROKEN ++ bool "SP800-90B APT with dangerous low cutoff value" ++ depends on LRNG_HEALTH_TESTS ++ depends on BROKEN ++ default n ++ help ++ This option enables a dangerously low SP800-90B adaptive ++ proportion test (APT) cutoff value which makes it very ++ likely that the APT is triggered to raise a self test ++ failure. ++ ++ This option is ONLY intended for developers wanting to ++ test the effectiveness of the SP800-90B APT health test. ++ ++ If unsure, say N. ++ + # Default taken from SP800-90B sec 4.4.1 - significance level 2^-30 +-# config LRNG_RCT_CUTOFF +-# int +-# default 31 if !LRNG_RCT_BROKEN +-# default 1 if LRNG_RCT_BROKEN +-# ++config LRNG_RCT_CUTOFF ++ int ++ default 31 if !LRNG_RCT_BROKEN ++ default 1 if LRNG_RCT_BROKEN ++ + # Default taken from SP800-90B sec 4.4.1 - significance level 2^-80 +-# config LRNG_RCT_CUTOFF_PERMANENT +-# int +-# default 81 if !LRNG_RCT_BROKEN +-# default 2 if LRNG_RCT_BROKEN +-# ++config LRNG_RCT_CUTOFF_PERMANENT ++ int ++ default 81 if !LRNG_RCT_BROKEN ++ default 2 if LRNG_RCT_BROKEN ++ + # Default taken from SP800-90B sec 4.4.2 - significance level 2^-30 +-# config LRNG_APT_CUTOFF +-# int +-# default 325 if !LRNG_APT_BROKEN +-# default 32 if LRNG_APT_BROKEN +-# ++config LRNG_APT_CUTOFF ++ int ++ default 325 if !LRNG_APT_BROKEN ++ default 32 if LRNG_APT_BROKEN ++ + # Default taken from SP800-90B sec 4.4.2 - significance level 2^-80 +-# config LRNG_APT_CUTOFF_PERMANENT +-# int +-# default 371 if !LRNG_APT_BROKEN +-# default 33 if LRNG_APT_BROKEN ++config LRNG_APT_CUTOFF_PERMANENT ++ int ++ default 371 if !LRNG_APT_BROKEN ++ default 33 if LRNG_APT_BROKEN + + comment "Interrupt Entropy Source" + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -21,3 +21,5 @@ obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_ + obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o + obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o + obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o ++ ++obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_health.c +@@ -0,0 +1,447 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * Entropy Source and DRNG Manager (LRNG) Health Testing ++ * ++ * Copyright (C) 2022 - 2023, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++ ++#include "lrng_definitions.h" ++#include "lrng_es_mgr.h" ++#include "lrng_health.h" ++ ++/* Stuck Test */ ++struct lrng_stuck_test { ++ u32 last_time; /* Stuck test: time of previous IRQ */ ++ u32 last_delta; /* Stuck test: delta of previous IRQ */ ++ u32 last_delta2; /* Stuck test: 2. time derivation of prev IRQ */ ++}; ++ ++/* Repetition Count Test */ ++struct lrng_rct { ++ atomic_t rct_count; /* Number of stuck values */ ++}; ++ ++/* Adaptive Proportion Test */ ++struct lrng_apt { ++ /* Data window size */ ++#define LRNG_APT_WINDOW_SIZE 512 ++ /* LSB of time stamp to process */ ++#define LRNG_APT_LSB 16 ++#define LRNG_APT_WORD_MASK (LRNG_APT_LSB - 1) ++ atomic_t apt_count; /* APT counter */ ++ atomic_t apt_base; /* APT base reference */ ++ ++ atomic_t apt_trigger; ++ bool apt_base_set; /* Is APT base set? */ ++}; ++ ++/* Health data collected for one entropy source */ ++struct lrng_health_es_state { ++ struct lrng_rct rct; ++ struct lrng_apt apt; ++ ++ /* SP800-90B startup health tests */ ++#define LRNG_SP80090B_STARTUP_SAMPLES 1024 ++#define LRNG_SP80090B_STARTUP_BLOCKS ((LRNG_SP80090B_STARTUP_SAMPLES + \ ++ LRNG_APT_WINDOW_SIZE - 1) / \ ++ LRNG_APT_WINDOW_SIZE) ++ bool sp80090b_startup_done; ++ atomic_t sp80090b_startup_blocks; ++}; ++ ++#define LRNG_HEALTH_ES_INIT(x) \ ++ x.rct.rct_count = ATOMIC_INIT(0), \ ++ x.apt.apt_count = ATOMIC_INIT(0), \ ++ x.apt.apt_base = ATOMIC_INIT(-1), \ ++ x.apt.apt_trigger = ATOMIC_INIT(LRNG_APT_WINDOW_SIZE), \ ++ x.apt.apt_base_set = false, \ ++ x.sp80090b_startup_blocks = ATOMIC_INIT(LRNG_SP80090B_STARTUP_BLOCKS), \ ++ x.sp80090b_startup_done = false, ++ ++/* The health test code must operate lock-less */ ++struct lrng_health { ++ bool health_test_enabled; ++ struct lrng_health_es_state es_state[lrng_int_es_last]; ++}; ++ ++static struct lrng_health lrng_health = { ++ .health_test_enabled = true, ++ ++#ifdef CONFIG_LRNG_IRQ ++ LRNG_HEALTH_ES_INIT(.es_state[lrng_int_es_irq]) ++#endif ++#ifdef CONFIG_LRNG_SCHED ++ LRNG_HEALTH_ES_INIT(.es_state[lrng_int_es_sched]) ++#endif ++}; ++ ++static DEFINE_PER_CPU(struct lrng_stuck_test[lrng_int_es_last], ++ lrng_stuck_test_array); ++ ++static bool lrng_sp80090b_health_requested(void) ++{ ++ /* Health tests are only requested in FIPS mode */ ++ return fips_enabled; ++} ++ ++static bool lrng_sp80090b_health_enabled(void) ++{ ++ struct lrng_health *health = &lrng_health; ++ ++ return lrng_sp80090b_health_requested() && health->health_test_enabled; ++} ++ ++/*************************************************************************** ++ * SP800-90B Compliance ++ * ++ * If the Linux-RNG is booted into FIPS mode, the following interfaces ++ * provide an SP800-90B compliant noise source: ++ * ++ * * /dev/random ++ * * getrandom(2) ++ * * get_random_bytes_full ++ * ++ * All other interfaces, including /dev/urandom or get_random_bytes without ++ * the add_random_ready_callback cannot claim to use an SP800-90B compliant ++ * noise source. ++ ***************************************************************************/ ++ ++/* ++ * Perform SP800-90B startup testing ++ */ ++static void lrng_sp80090b_startup(struct lrng_health *health, ++ enum lrng_internal_es es) ++{ ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ ++ if (!es_state->sp80090b_startup_done && ++ atomic_dec_and_test(&es_state->sp80090b_startup_blocks)) { ++ es_state->sp80090b_startup_done = true; ++ pr_info("SP800-90B startup health tests for internal entropy source %u completed\n", ++ es); ++ lrng_drng_force_reseed(); ++ ++ /* ++ * We cannot call lrng_es_add_entropy() as this may cause a ++ * schedule operation while in scheduler context for the ++ * scheduler ES. ++ */ ++ } ++} ++ ++/* ++ * Handle failure of SP800-90B startup testing ++ */ ++static void lrng_sp80090b_startup_failure(struct lrng_health *health, ++ enum lrng_internal_es es) ++{ ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ ++ ++ /* Reset of LRNG and its entropy - NOTE: we are in atomic context */ ++ lrng_reset(); ++ ++ /* ++ * Reset the SP800-90B startup test. ++ * ++ * NOTE SP800-90B section 4.3 bullet 4 does not specify what ++ * exactly is to be done in case of failure! Thus, we do what ++ * makes sense, i.e. restarting the health test and thus gating ++ * the output function of /dev/random and getrandom(2). ++ */ ++ atomic_set(&es_state->sp80090b_startup_blocks, ++ LRNG_SP80090B_STARTUP_BLOCKS); ++} ++ ++/* ++ * Handle failure of SP800-90B runtime testing ++ */ ++static void lrng_sp80090b_runtime_failure(struct lrng_health *health, ++ enum lrng_internal_es es) ++{ ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ ++ lrng_sp80090b_startup_failure(health, es); ++ es_state->sp80090b_startup_done = false; ++} ++ ++static void lrng_rct_reset(struct lrng_rct *rct); ++static void lrng_apt_reset(struct lrng_apt *apt, unsigned int time_masked); ++static void lrng_apt_restart(struct lrng_apt *apt); ++static void lrng_sp80090b_permanent_failure(struct lrng_health *health, ++ enum lrng_internal_es es) ++{ ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ struct lrng_apt *apt = &es_state->apt; ++ struct lrng_rct *rct = &es_state->rct; ++ ++ if (lrng_enforce_panic_on_permanent_health_failure()) { ++ panic("SP800-90B permanent health test failure for internal entropy source %u\n", ++ es); ++ } ++ ++ pr_err("SP800-90B permanent health test failure for internal entropy source %u - invalidating all existing entropy and initiate SP800-90B startup\n", ++ es); ++ lrng_sp80090b_runtime_failure(health, es); ++ ++ lrng_rct_reset(rct); ++ lrng_apt_reset(apt, 0); ++ lrng_apt_restart(apt); ++} ++ ++static void lrng_sp80090b_failure(struct lrng_health *health, ++ enum lrng_internal_es es) ++{ ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ ++ if (es_state->sp80090b_startup_done) { ++ pr_warn("SP800-90B runtime health test failure for internal entropy source %u - invalidating all existing entropy and initiate SP800-90B startup\n", es); ++ lrng_sp80090b_runtime_failure(health, es); ++ } else { ++ pr_warn("SP800-90B startup test failure for internal entropy source %u - resetting\n", es); ++ lrng_sp80090b_startup_failure(health, es); ++ } ++} ++ ++bool lrng_sp80090b_startup_complete_es(enum lrng_internal_es es) ++{ ++ struct lrng_health *health = &lrng_health; ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ ++ if (!lrng_sp80090b_health_enabled()) ++ return true; ++ ++ return es_state->sp80090b_startup_done; ++} ++ ++bool lrng_sp80090b_compliant(enum lrng_internal_es es) ++{ ++ struct lrng_health *health = &lrng_health; ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ ++ return lrng_sp80090b_health_enabled() && ++ es_state->sp80090b_startup_done; ++} ++ ++/*************************************************************************** ++ * Adaptive Proportion Test ++ * ++ * This test complies with SP800-90B section 4.4.2. ++ ***************************************************************************/ ++ ++/* ++ * Reset the APT counter ++ * ++ * @health [in] Reference to health state ++ */ ++static void lrng_apt_reset(struct lrng_apt *apt, unsigned int time_masked) ++{ ++ /* Reset APT */ ++ atomic_set(&apt->apt_count, 0); ++ atomic_set(&apt->apt_base, time_masked); ++} ++ ++static void lrng_apt_restart(struct lrng_apt *apt) ++{ ++ atomic_set(&apt->apt_trigger, LRNG_APT_WINDOW_SIZE); ++} ++ ++/* ++ * Insert a new entropy event into APT ++ * ++ * This function does is void as it does not decide about the fate of a time ++ * stamp. An APT failure can only happen at the same time of a stuck test ++ * failure. Thus, the stuck failure will already decide how the time stamp ++ * is handled. ++ * ++ * @health [in] Reference to health state ++ * @now_time [in] Time stamp to process ++ */ ++static void lrng_apt_insert(struct lrng_health *health, ++ unsigned int now_time, enum lrng_internal_es es) ++{ ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ struct lrng_apt *apt = &es_state->apt; ++ ++ if (!lrng_sp80090b_health_requested()) ++ return; ++ ++ now_time &= LRNG_APT_WORD_MASK; ++ ++ /* Initialization of APT */ ++ if (!apt->apt_base_set) { ++ atomic_set(&apt->apt_base, now_time); ++ apt->apt_base_set = true; ++ return; ++ } ++ ++ if (now_time == (unsigned int)atomic_read(&apt->apt_base)) { ++ u32 apt_val = (u32)atomic_inc_return_relaxed(&apt->apt_count); ++ ++ if (apt_val >= CONFIG_LRNG_APT_CUTOFF_PERMANENT) ++ lrng_sp80090b_permanent_failure(health, es); ++ else if (apt_val >= CONFIG_LRNG_APT_CUTOFF) ++ lrng_sp80090b_failure(health, es); ++ } ++ ++ if (atomic_dec_and_test(&apt->apt_trigger)) { ++ lrng_apt_restart(apt); ++ lrng_apt_reset(apt, now_time); ++ lrng_sp80090b_startup(health, es); ++ } ++} ++ ++/*************************************************************************** ++ * Repetition Count Test ++ * ++ * The LRNG uses an enhanced version of the Repetition Count Test ++ * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical ++ * back-to-back values, the input to the RCT is the counting of the stuck ++ * values while filling the entropy pool. ++ * ++ * The RCT is applied with an alpha of 2^-30 compliant to FIPS 140-2 IG 9.8. ++ * ++ * During the counting operation, the LRNG always calculates the RCT ++ * cut-off value of C. If that value exceeds the allowed cut-off value, ++ * the LRNG will invalidate all entropy for the entropy pool which implies ++ * that no data can be extracted from the entropy pool unless new entropy ++ * is received. ++ ***************************************************************************/ ++ ++static void lrng_rct_reset(struct lrng_rct *rct) ++{ ++ /* Reset RCT */ ++ atomic_set(&rct->rct_count, 0); ++} ++ ++/* ++ * Hot code path - Insert data for Repetition Count Test ++ * ++ * @health: Reference to health information ++ * @stuck: Decision of stuck test ++ */ ++static void lrng_rct(struct lrng_health *health, enum lrng_internal_es es, ++ int stuck) ++{ ++ struct lrng_health_es_state *es_state = &health->es_state[es]; ++ struct lrng_rct *rct = &es_state->rct; ++ ++ if (!lrng_sp80090b_health_requested()) ++ return; ++ ++ if (stuck) { ++ u32 rct_count = atomic_add_return_relaxed(1, &rct->rct_count); ++ ++ /* ++ * The cutoff value is based on the following consideration: ++ * alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8. ++ * In addition, we imply an entropy value H of 1 bit as this ++ * is the minimum entropy required to provide full entropy. ++ * ++ * Note, rct_count (which equals to value B in the ++ * pseudo code of SP800-90B section 4.4.1) starts with zero. ++ * Hence we need to subtract one from the cutoff value as ++ * calculated following SP800-90B. ++ */ ++ if (rct_count >= CONFIG_LRNG_RCT_CUTOFF_PERMANENT) ++ lrng_sp80090b_permanent_failure(health, es); ++ else if (rct_count >= CONFIG_LRNG_RCT_CUTOFF) ++ lrng_sp80090b_failure(health, es); ++ } else { ++ lrng_rct_reset(rct); ++ } ++} ++ ++/*************************************************************************** ++ * Stuck Test ++ * ++ * Checking the: ++ * 1st derivative of the event occurrence (time delta) ++ * 2nd derivative of the event occurrence (delta of time deltas) ++ * 3rd derivative of the event occurrence (delta of delta of time deltas) ++ * ++ * All values must always be non-zero. The stuck test is only valid disabled if ++ * high-resolution time stamps are identified after initialization. ++ ***************************************************************************/ ++ ++static u32 lrng_delta(u32 prev, u32 next) ++{ ++ /* ++ * Note that this (unsigned) subtraction does yield the correct value ++ * in the wraparound-case, i.e. when next < prev. ++ */ ++ return (next - prev); ++} ++ ++/* ++ * Hot code path ++ * ++ * @health: Reference to health information ++ * @now: Event time ++ * @return: 0 event occurrence not stuck (good time stamp) ++ * != 0 event occurrence stuck (reject time stamp) ++ */ ++static int lrng_irq_stuck(enum lrng_internal_es es, u32 now_time) ++{ ++ struct lrng_stuck_test *stuck = this_cpu_ptr(lrng_stuck_test_array); ++ u32 delta = lrng_delta(stuck[es].last_time, now_time); ++ u32 delta2 = lrng_delta(stuck[es].last_delta, delta); ++ u32 delta3 = lrng_delta(stuck[es].last_delta2, delta2); ++ ++ stuck[es].last_time = now_time; ++ stuck[es].last_delta = delta; ++ stuck[es].last_delta2 = delta2; ++ ++ if (!delta || !delta2 || !delta3) ++ return 1; ++ ++ return 0; ++} ++ ++/*************************************************************************** ++ * Health test interfaces ++ ***************************************************************************/ ++ ++/* ++ * Disable all health tests ++ */ ++void lrng_health_disable(void) ++{ ++ struct lrng_health *health = &lrng_health; ++ ++ health->health_test_enabled = false; ++ ++ if (lrng_sp80090b_health_requested()) ++ pr_warn("SP800-90B compliance requested but the Linux RNG is NOT SP800-90B compliant\n"); ++} ++ ++/* ++ * Hot code path - Perform health test on time stamp received from an event ++ * ++ * @now_time Time stamp ++ */ ++enum lrng_health_res lrng_health_test(u32 now_time, enum lrng_internal_es es) ++{ ++ struct lrng_health *health = &lrng_health; ++ int stuck; ++ ++ if (!health->health_test_enabled) ++ return lrng_health_pass; ++ ++ lrng_apt_insert(health, now_time, es); ++ ++ stuck = lrng_irq_stuck(es, now_time); ++ lrng_rct(health, es, stuck); ++ if (stuck) { ++ /* SP800-90B disallows using a failing health test time stamp */ ++ return lrng_sp80090b_health_requested() ? ++ lrng_health_fail_drop : lrng_health_fail_use; ++ } ++ ++ return lrng_health_pass; ++} diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch new file mode 100644 index 000000000..6f97cc889 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch @@ -0,0 +1,207 @@ +From 92148eed7179e55a0f9d5cbedf42b814502e222a Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Mon, 20 Feb 2023 22:07:27 +0100 +Subject: [PATCH 15/25] LRNG - add random.c entropy source support + +The random.c implementation can be used as an entropy source by the +LRNG. This support can be enabled at compile time. + +The entropy rate can be set at compile time which is only applied: + +- once the random.c considers itself fully seeded, and + +- the kernel does not operate in FIPS mode (i.e. fips=1 is not set at + the kernel command line) + +If one of these properties is not set, the ES will obtain data, but will +credit it with zero bits of entropy. For the first bullet, it is clear +why it will have zero bits of entropy. But for the second property, this +is set because the random.c is not operating SP800-90B compliant and +thus must be treated to not deliver any entropy in FIPS mode. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 56 ++++++++--------- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_es_krng.c | 100 +++++++++++++++++++++++++++++++ + 3 files changed, 129 insertions(+), 28 deletions(-) + create mode 100644 drivers/char/lrng/lrng_es_krng.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -586,34 +586,34 @@ config LRNG_SCHED_ENTROPY_RATE + scheduler entropy source will still deliver data but without + being credited with entropy. + +-# comment "Kernel RNG Entropy Source" +-# +-# config LRNG_KERNEL_RNG +-# bool "Enable Kernel RNG as LRNG Seed Source" +-# depends on RANDOM_DEFAULT_IMPL +-# help +-# The LRNG may use the kernel RNG (random.c) as entropy +-# source. +-# +-# config LRNG_KERNEL_RNG_ENTROPY_RATE +-# int "Kernel RNG Entropy Source Entropy Rate" +-# depends on LRNG_KERNEL_RNG +-# range 0 256 +-# default 256 +-# help +-# The option defines the amount of entropy the LRNG applies to 256 +-# bits of data obtained from the kernel RNG entropy source. The +-# LRNG enforces the limit that this value must be in the range +-# between 0 and 256. +-# +-# When configuring this value to 0, the kernel RNG entropy source +-# will provide 256 bits of data without being credited to contain +-# entropy. +-# +-# Note: This value is set to 0 automatically when booting the +-# kernel in FIPS mode (with fips=1 kernel command line option). +-# This is due to the fact that random.c is not SP800-90B +-# compliant. ++comment "Kernel RNG Entropy Source" ++ ++config LRNG_KERNEL_RNG ++ bool "Enable Kernel RNG as LRNG Seed Source" ++ depends on RANDOM_DEFAULT_IMPL ++ help ++ The LRNG may use the kernel RNG (random.c) as entropy ++ source. ++ ++config LRNG_KERNEL_RNG_ENTROPY_RATE ++ int "Kernel RNG Entropy Source Entropy Rate" ++ depends on LRNG_KERNEL_RNG ++ range 0 256 ++ default 256 ++ help ++ The option defines the amount of entropy the LRNG applies to 256 ++ bits of data obtained from the kernel RNG entropy source. The ++ LRNG enforces the limit that this value must be in the range ++ between 0 and 256. ++ ++ When configuring this value to 0, the kernel RNG entropy source ++ will provide 256 bits of data without being credited to contain ++ entropy. ++ ++ Note: This value is set to 0 automatically when booting the ++ kernel in FIPS mode (with fips=1 kernel command line option). ++ This is due to the fact that random.c is not SP800-90B ++ compliant. + + endmenu # "Entropy Source Configuration" + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_ + + obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o + obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o ++obj-$(CONFIG_LRNG_KERNEL_RNG) += lrng_es_krng.o + obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o + + obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_krng.c +@@ -0,0 +1,100 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Fast Entropy Source: Linux kernel RNG (random.c) ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++ ++#include "lrng_es_aux.h" ++#include "lrng_es_krng.h" ++ ++static u32 krng_entropy = CONFIG_LRNG_KERNEL_RNG_ENTROPY_RATE; ++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG ++module_param(krng_entropy, uint, 0644); ++MODULE_PARM_DESC(krng_entropy, "Entropy in bits of 256 data bits from the kernel RNG noise source"); ++#endif ++ ++static atomic_t lrng_krng_initial_rate = ATOMIC_INIT(0); ++ ++static u32 lrng_krng_fips_entropylevel(u32 entropylevel) ++{ ++ return fips_enabled ? 0 : entropylevel; ++} ++ ++static int lrng_krng_adjust_entropy(void) ++{ ++ u32 entropylevel; ++ ++ krng_entropy = atomic_read_u32(&lrng_krng_initial_rate); ++ ++ entropylevel = lrng_krng_fips_entropylevel(krng_entropy); ++ pr_debug("Kernel RNG is fully seeded, setting entropy rate to %u bits of entropy\n", ++ entropylevel); ++ lrng_drng_force_reseed(); ++ if (entropylevel) ++ lrng_es_add_entropy(); ++ return 0; ++} ++ ++static u32 lrng_krng_entropylevel(u32 requested_bits) ++{ ++ static bool init = false; ++ ++ if (unlikely(!init) && rng_is_initialized()) { ++ init = true; ++ lrng_krng_adjust_entropy(); ++ } ++ ++ return lrng_fast_noise_entropylevel( ++ lrng_krng_fips_entropylevel(krng_entropy), requested_bits); ++} ++ ++static u32 lrng_krng_poolsize(void) ++{ ++ return lrng_krng_entropylevel(lrng_security_strength()); ++} ++ ++/* ++ * lrng_krng_get() - Get kernel RNG entropy ++ * ++ * @eb: entropy buffer to store entropy ++ * @requested_bits: requested entropy in bits ++ */ ++static void lrng_krng_get(struct entropy_buf *eb, u32 requested_bits, ++ bool __unused) ++{ ++ u32 ent_bits = lrng_krng_entropylevel(requested_bits); ++ ++ get_random_bytes(eb->e[lrng_ext_es_krng], requested_bits >> 3); ++ ++ pr_debug("obtained %u bits of entropy from kernel RNG noise source\n", ++ ent_bits); ++ ++ eb->e_bits[lrng_ext_es_krng] = ent_bits; ++} ++ ++static void lrng_krng_es_state(unsigned char *buf, size_t buflen) ++{ ++ snprintf(buf, buflen, ++ " Available entropy: %u\n" ++ " Entropy Rate per 256 data bits: %u\n", ++ lrng_krng_poolsize(), ++ lrng_krng_entropylevel(256)); ++} ++ ++struct lrng_es_cb lrng_es_krng = { ++ .name = "KernelRNG", ++ .get_ent = lrng_krng_get, ++ .curr_entropy = lrng_krng_entropylevel, ++ .max_entropy = lrng_krng_poolsize, ++ .state = lrng_krng_es_state, ++ .reset = NULL, ++ .switch_hash = NULL, ++}; diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch new file mode 100644 index 000000000..5058625a9 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch @@ -0,0 +1,401 @@ +From 67d7584f291dc9e3fb5a59645fce2fc8cadf3e38 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Mon, 20 Feb 2023 22:08:23 +0100 +Subject: [PATCH 16/25] LRNG - CPU entropy source + +Certain CPUs provide instructions giving access to an entropy source +(e.g. RDSEED on Intel/AMD, DARN on POWER, etc.). The LRNG can utilize +the entropy source to seed its DRNG from. + +Some CPU entropy sources (e.g. POWER DARN, RISC-V) are defined to +deliver data that does not contain full entropy. In this case, the CPU +is sampled for as much data as needed to obtain the required amount of +entropy. In this case, a compression operation using the set message +digest is applied. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 76 ++++----- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_es_cpu.c | 281 ++++++++++++++++++++++++++++++++ + 3 files changed, 320 insertions(+), 38 deletions(-) + create mode 100644 drivers/char/lrng/lrng_es_cpu.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -496,44 +496,44 @@ config LRNG_IRQ_ENTROPY_RATE + # will provide 256 bits of data without being credited to contain + # entropy. + # +-# comment "CPU Entropy Source" +-# +-# config LRNG_CPU +-# bool "Enable CPU Entropy Source as LRNG Seed Source" +-# default y +-# help +-# Current CPUs commonly contain entropy sources which can be +-# used to seed the LRNG. For example, the Intel RDSEED +-# instruction, or the POWER DARN instruction will be sourced +-# to seed the LRNG if this option is enabled. +-# +-# Note, if this option is enabled and the underlying CPU +-# does not offer such entropy source, the LRNG will automatically +-# detect this and ignore the hardware. +-# +-# config LRNG_CPU_FULL_ENT_MULTIPLIER +-# int +-# default 1 if !LRNG_TEST_CPU_ES_COMPRESSION +-# default 123 if LRNG_TEST_CPU_ES_COMPRESSION +-# +-# config LRNG_CPU_ENTROPY_RATE +-# int "CPU Entropy Source Entropy Rate" +-# depends on LRNG_CPU +-# range 0 256 +-# default 8 +-# help +-# The option defines the amount of entropy the LRNG applies to 256 +-# bits of data obtained from the CPU entropy source. The LRNG +-# enforces the limit that this value must be in the range between +-# 0 and 256. +-# +-# When configuring this value to 0, the CPU entropy source will +-# provide 256 bits of data without being credited to contain +-# entropy. +-# +-# Note, this option is overwritten when the option +-# CONFIG_RANDOM_TRUST_CPU is set. +-# ++comment "CPU Entropy Source" ++ ++config LRNG_CPU ++ bool "Enable CPU Entropy Source as LRNG Seed Source" ++ default y ++ help ++ Current CPUs commonly contain entropy sources which can be ++ used to seed the LRNG. For example, the Intel RDSEED ++ instruction, or the POWER DARN instruction will be sourced ++ to seed the LRNG if this option is enabled. ++ ++ Note, if this option is enabled and the underlying CPU ++ does not offer such entropy source, the LRNG will automatically ++ detect this and ignore the hardware. ++ ++config LRNG_CPU_FULL_ENT_MULTIPLIER ++ int ++ default 1 if !LRNG_TEST_CPU_ES_COMPRESSION ++ default 123 if LRNG_TEST_CPU_ES_COMPRESSION ++ ++config LRNG_CPU_ENTROPY_RATE ++ int "CPU Entropy Source Entropy Rate" ++ depends on LRNG_CPU ++ range 0 256 ++ default 8 ++ help ++ The option defines the amount of entropy the LRNG applies to 256 ++ bits of data obtained from the CPU entropy source. The LRNG ++ enforces the limit that this value must be in the range between ++ 0 and 256. ++ ++ When configuring this value to 0, the CPU entropy source will ++ provide 256 bits of data without being credited to contain ++ entropy. ++ ++ Note, this option is overwritten when the option ++ CONFIG_RANDOM_TRUST_CPU is set. ++ + comment "Scheduler Entropy Source" + + config LRNG_SCHED +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -22,5 +22,6 @@ obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng + obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o + obj-$(CONFIG_LRNG_KERNEL_RNG) += lrng_es_krng.o + obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o ++obj-$(CONFIG_LRNG_CPU) += lrng_es_cpu.o + + obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_cpu.c +@@ -0,0 +1,281 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Fast Entropy Source: CPU-based entropy source ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_definitions.h" ++#include "lrng_es_aux.h" ++#include "lrng_es_cpu.h" ++ ++/* ++ * Estimated entropy of data is a 32th of LRNG_DRNG_SECURITY_STRENGTH_BITS. ++ * As we have no ability to review the implementation of those noise sources, ++ * it is prudent to have a conservative estimate here. ++ */ ++#define LRNG_ARCHRANDOM_DEFAULT_STRENGTH CONFIG_LRNG_CPU_ENTROPY_RATE ++#define LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH LRNG_DRNG_SECURITY_STRENGTH_BITS ++#ifdef CONFIG_RANDOM_TRUST_CPU ++static u32 cpu_entropy = LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH; ++#else ++static u32 cpu_entropy = LRNG_ARCHRANDOM_DEFAULT_STRENGTH; ++#endif ++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG ++module_param(cpu_entropy, uint, 0644); ++MODULE_PARM_DESC(cpu_entropy, "Entropy in bits of 256 data bits from CPU noise source (e.g. RDSEED)"); ++#endif ++ ++static int __init lrng_parse_trust_cpu(char *arg) ++{ ++ int ret; ++ bool trust_cpu = false; ++ ++ ret = kstrtobool(arg, &trust_cpu); ++ if (ret) ++ return ret; ++ ++ if (trust_cpu) ++ cpu_entropy = LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH; ++ else ++ cpu_entropy = LRNG_ARCHRANDOM_DEFAULT_STRENGTH; ++ ++ lrng_force_fully_seeded(); ++ ++ return 0; ++} ++early_param("random.trust_cpu", lrng_parse_trust_cpu); ++ ++static u32 lrng_cpu_entropylevel(u32 requested_bits) ++{ ++ return lrng_fast_noise_entropylevel(cpu_entropy, requested_bits); ++} ++ ++static u32 lrng_cpu_poolsize(void) ++{ ++ return lrng_cpu_entropylevel(lrng_security_strength()); ++} ++ ++static u32 lrng_get_cpu_data(u8 *outbuf, u32 requested_bits) ++{ ++ size_t longs = 0; ++ u32 i, req = requested_bits >> 3; ++ ++ /* operate on full blocks */ ++ BUILD_BUG_ON(LRNG_DRNG_SECURITY_STRENGTH_BYTES % sizeof(unsigned long)); ++ BUILD_BUG_ON(LRNG_SEED_BUFFER_INIT_ADD_BITS % sizeof(unsigned long)); ++ /* ensure we have aligned buffers */ ++ BUILD_BUG_ON(LRNG_KCAPI_ALIGN % sizeof(unsigned long)); ++ ++ for (i = 0; i < req; i += longs) { ++ longs = arch_get_random_seed_longs( ++ (unsigned long *)(outbuf + i), req - i); ++ if (longs) ++ continue; ++ longs = arch_get_random_longs((unsigned long *)(outbuf + i), ++ req - i); ++ if (!longs) { ++ cpu_entropy = 0; ++ return 0; ++ } ++ } ++ ++ return requested_bits; ++} ++ ++static u32 lrng_get_cpu_data_compress(u8 *outbuf, u32 requested_bits, ++ u32 data_multiplier) ++{ ++ SHASH_DESC_ON_STACK(shash, NULL); ++ const struct lrng_hash_cb *hash_cb; ++ struct lrng_drng *drng = lrng_drng_node_instance(); ++ unsigned long flags; ++ u32 ent_bits = 0, i, partial_bits = 0, digestsize, digestsize_bits, ++ full_bits; ++ void *hash; ++ ++ read_lock_irqsave(&drng->hash_lock, flags); ++ hash_cb = drng->hash_cb; ++ hash = drng->hash; ++ ++ digestsize = hash_cb->hash_digestsize(hash); ++ digestsize_bits = digestsize << 3; ++ /* Cap to maximum entropy that can ever be generated with given hash */ ++ lrng_cap_requested(digestsize_bits, requested_bits); ++ full_bits = requested_bits * data_multiplier; ++ ++ /* Calculate oversampling for SP800-90C */ ++ if (lrng_sp80090c_compliant()) { ++ /* Complete amount of bits to be pulled */ ++ full_bits += LRNG_OVERSAMPLE_ES_BITS * data_multiplier; ++ /* Full blocks that will be pulled */ ++ data_multiplier = full_bits / requested_bits; ++ /* Partial block in bits to be pulled */ ++ partial_bits = full_bits - (data_multiplier * requested_bits); ++ } ++ ++ if (hash_cb->hash_init(shash, hash)) ++ goto out; ++ ++ /* Hash all data from the CPU entropy source */ ++ for (i = 0; i < data_multiplier; i++) { ++ ent_bits = lrng_get_cpu_data(outbuf, requested_bits); ++ if (!ent_bits) ++ goto out; ++ ++ if (hash_cb->hash_update(shash, outbuf, ent_bits >> 3)) ++ goto err; ++ } ++ ++ /* Hash partial block, if applicable */ ++ ent_bits = lrng_get_cpu_data(outbuf, partial_bits); ++ if (ent_bits && ++ hash_cb->hash_update(shash, outbuf, ent_bits >> 3)) ++ goto err; ++ ++ pr_debug("pulled %u bits from CPU RNG entropy source\n", full_bits); ++ ent_bits = requested_bits; ++ ++ /* Generate the compressed data to be returned to the caller */ ++ if (requested_bits < digestsize_bits) { ++ u8 digest[LRNG_MAX_DIGESTSIZE]; ++ ++ if (hash_cb->hash_final(shash, digest)) ++ goto err; ++ ++ /* Truncate output data to requested size */ ++ memcpy(outbuf, digest, requested_bits >> 3); ++ memzero_explicit(digest, digestsize); ++ } else { ++ if (hash_cb->hash_final(shash, outbuf)) ++ goto err; ++ } ++ ++out: ++ hash_cb->hash_desc_zero(shash); ++ read_unlock_irqrestore(&drng->hash_lock, flags); ++ return ent_bits; ++ ++err: ++ ent_bits = 0; ++ goto out; ++} ++ ++/* ++ * If CPU entropy source requires does not return full entropy, return the ++ * multiplier of how much data shall be sampled from it. ++ */ ++static u32 lrng_cpu_multiplier(void) ++{ ++ static u32 data_multiplier = 0; ++ unsigned long v; ++ ++ if (data_multiplier > 0) ++ return data_multiplier; ++ ++ if (IS_ENABLED(CONFIG_X86) && !arch_get_random_seed_longs(&v, 1)) { ++ /* ++ * Intel SPEC: pulling 512 blocks from RDRAND ensures ++ * one reseed making it logically equivalent to RDSEED. ++ */ ++ data_multiplier = 512; ++ } else if (IS_ENABLED(CONFIG_PPC)) { ++ /* ++ * PowerISA defines DARN to deliver at least 0.5 bits of ++ * entropy per data bit. ++ */ ++ data_multiplier = 2; ++ } else if (IS_ENABLED(CONFIG_RISCV)) { ++ /* ++ * riscv-crypto-spec-scalar-1.0.0-rc6.pdf section 4.2 defines ++ * this requirement. ++ */ ++ data_multiplier = 2; ++ } else { ++ /* CPU provides full entropy */ ++ data_multiplier = CONFIG_LRNG_CPU_FULL_ENT_MULTIPLIER; ++ } ++ return data_multiplier; ++} ++ ++static int ++lrng_cpu_switch_hash(struct lrng_drng *drng, int node, ++ const struct lrng_hash_cb *new_cb, void *new_hash, ++ const struct lrng_hash_cb *old_cb) ++{ ++ u32 digestsize, multiplier; ++ ++ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) ++ return -EOPNOTSUPP; ++ ++ digestsize = lrng_get_digestsize(); ++ multiplier = lrng_cpu_multiplier(); ++ ++ /* ++ * It would be security violation if the new digestsize is smaller than ++ * the set CPU entropy rate. ++ */ ++ WARN_ON(multiplier > 1 && digestsize < cpu_entropy); ++ cpu_entropy = min_t(u32, digestsize, cpu_entropy); ++ return 0; ++} ++ ++/* ++ * lrng_get_arch() - Get CPU entropy source entropy ++ * ++ * @eb: entropy buffer to store entropy ++ * @requested_bits: requested entropy in bits ++ */ ++static void lrng_cpu_get(struct entropy_buf *eb, u32 requested_bits, ++ bool __unused) ++{ ++ u32 ent_bits, data_multiplier = lrng_cpu_multiplier(); ++ ++ if (data_multiplier <= 1) { ++ ent_bits = lrng_get_cpu_data(eb->e[lrng_ext_es_cpu], ++ requested_bits); ++ } else { ++ ent_bits = lrng_get_cpu_data_compress(eb->e[lrng_ext_es_cpu], ++ requested_bits, ++ data_multiplier); ++ } ++ ++ ent_bits = lrng_cpu_entropylevel(ent_bits); ++ pr_debug("obtained %u bits of entropy from CPU RNG entropy source\n", ++ ent_bits); ++ eb->e_bits[lrng_ext_es_cpu] = ent_bits; ++} ++ ++static void lrng_cpu_es_state(unsigned char *buf, size_t buflen) ++{ ++ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); ++ u32 data_multiplier = lrng_cpu_multiplier(); ++ ++ /* Assume the lrng_drng_init lock is taken by caller */ ++ snprintf(buf, buflen, ++ " Hash for compressing data: %s\n" ++ " Available entropy: %u\n" ++ " Data multiplier: %u\n", ++ (data_multiplier <= 1) ? ++ "N/A" : lrng_drng_init->hash_cb->hash_name(), ++ lrng_cpu_poolsize(), ++ data_multiplier); ++} ++ ++struct lrng_es_cb lrng_es_cpu = { ++ .name = "CPU", ++ .get_ent = lrng_cpu_get, ++ .curr_entropy = lrng_cpu_entropylevel, ++ .max_entropy = lrng_cpu_poolsize, ++ .state = lrng_cpu_es_state, ++ .reset = NULL, ++ .switch_hash = lrng_cpu_switch_hash, ++}; diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch new file mode 100644 index 000000000..597c190f1 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch @@ -0,0 +1,571 @@ +From a9b4e46d8253ca9e63fcf1fed126c407a1e4f73c Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 27 Aug 2023 17:11:37 +0200 +Subject: [PATCH 17/25] LRNG - add Jitter RNG fast noise source + +The Jitter RNG fast noise source implemented as part of the kernel +crypto API is queried for 256 bits of entropy at the time the seed +buffer managed by the LRNG is about to be filled. + +The default entropy rate is set to 16 bits of entropy per 256 bits of +data. In FIPS mode, the ratio is set to 256 bits of entropy per 256 bits +of data considering that the Jitter RNG passed the NIST ENT validation +to claim full entropy. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 172 +++++++-------- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_es_jent.c | 356 +++++++++++++++++++++++++++++++ + 3 files changed, 443 insertions(+), 86 deletions(-) + create mode 100644 drivers/char/lrng/lrng_es_jent.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -410,92 +410,92 @@ config LRNG_IRQ_ENTROPY_RATE + interrupt entropy source will still deliver data but without + being credited with entropy. + +-# comment "Jitter RNG Entropy Source" +-# +-# config LRNG_JENT +-# bool "Enable Jitter RNG as LRNG Seed Source" +-# depends on CRYPTO +-# select CRYPTO_JITTERENTROPY +-# help +-# The LRNG may use the Jitter RNG as entropy source. Enabling +-# this option enables the use of the Jitter RNG. Its default +-# entropy level is 16 bits of entropy per 256 data bits delivered +-# by the Jitter RNG. This entropy level can be changed at boot +-# time or at runtime with the lrng_base.jitterrng configuration +-# variable. +-# +-#choice +-# prompt "Jitter RNG Async Block Number" +-# default LRNG_JENT_ENTROPY_BLOCKS_NO_128 +-# depends on LRNG_JENT +-# help +-# Select the number of Jitter RNG entropy blocks the asynchronous +-# collection operation will fill. A caller for Jitter RNG entropy +-# will be given data from the pre-filled blocks if available to +-# prevent the Jitter RNG from utilizing the CPU too much in a +-# possible hot code path. +-# +-# The number specifies the number of 256/384 bit blocks that will +-# be held in memory and asynchronously filled with Jitter RNG data. +-# +-# The asynchronous entropy collection can also be disabled at +-# kernel startup time when setting the command line option of +-# lrng_es_jent.jent_async_enabled=0. Also, setting this option at +-# runtime is allowed via the corresponding SysFS interface. This +-# option is only available with the options SysFS and +-# CONFIG_LRNG_RUNTIME_ES_CONFIG enabled. +-# +-# config LRNG_JENT_ENTROPY_BLOCKS_DISABLED +-# bool "Async collection disabled" +-# +-# # Any block number is allowed, provided it is a power of 2 and +-# # equal or larger than 4 (4 is due to the division in +-# # lrng_jent_async_get when deciding to wake up the monitor). +-# config LRNG_JENT_ENTROPY_BLOCKS_NO_32 +-# bool "32 blocks" +-# +-# config LRNG_JENT_ENTROPY_BLOCKS_NO_64 +-# bool "64 blocks" +-# +-# config LRNG_JENT_ENTROPY_BLOCKS_NO_128 +-# bool "128 blocks (default)" +-# +-# config LRNG_JENT_ENTROPY_BLOCKS_NO_256 +-# bool "256 blocks" +-# +-# config LRNG_JENT_ENTROPY_BLOCKS_NO_512 +-# bool "512 blocks" +-# +-# config LRNG_JENT_ENTROPY_BLOCKS_NO_1024 +-# bool "1024 blocks" +-# +-#endchoice +-# +-#config LRNG_JENT_ENTROPY_BLOCKS +-# int +-# default 0 if LRNG_JENT_ENTROPY_BLOCKS_DISABLED +-# default 32 if LRNG_JENT_ENTROPY_BLOCKS_NO_32 +-# default 64 if LRNG_JENT_ENTROPY_BLOCKS_NO_64 +-# default 128 if LRNG_JENT_ENTROPY_BLOCKS_NO_128 +-# default 256 if LRNG_JENT_ENTROPY_BLOCKS_NO_256 +-# default 512 if LRNG_JENT_ENTROPY_BLOCKS_NO_512 +-# default 1024 if LRNG_JENT_ENTROPY_BLOCKS_NO_1024 +-# +-# config LRNG_JENT_ENTROPY_RATE +-# int "Jitter RNG Entropy Source Entropy Rate" +-# depends on LRNG_JENT +-# range 0 256 +-# default 16 +-# help +-# The option defines the amount of entropy the LRNG applies to 256 +-# bits of data obtained from the Jitter RNG entropy source. The +-# LRNG enforces the limit that this value must be in the range +-# between 0 and 256. +-# +-# When configuring this value to 0, the Jitter RNG entropy source +-# will provide 256 bits of data without being credited to contain +-# entropy. +-# ++comment "Jitter RNG Entropy Source" ++ ++config LRNG_JENT ++ bool "Enable Jitter RNG as LRNG Seed Source" ++ depends on CRYPTO ++ select CRYPTO_JITTERENTROPY ++ help ++ The LRNG may use the Jitter RNG as entropy source. Enabling ++ this option enables the use of the Jitter RNG. Its default ++ entropy level is 16 bits of entropy per 256 data bits delivered ++ by the Jitter RNG. This entropy level can be changed at boot ++ time or at runtime with the lrng_base.jitterrng configuration ++ variable. ++ ++choice ++ prompt "Jitter RNG Async Block Number" ++ default LRNG_JENT_ENTROPY_BLOCKS_NO_128 ++ depends on LRNG_JENT ++ help ++ Select the number of Jitter RNG entropy blocks the asynchronous ++ collection operation will fill. A caller for Jitter RNG entropy ++ will be given data from the pre-filled blocks if available to ++ prevent the Jitter RNG from utilizing the CPU too much in a ++ possible hot code path. ++ ++ The number specifies the number of 256/384 bit blocks that will ++ be held in memory and asynchronously filled with Jitter RNG data. ++ ++ The asynchronous entropy collection can also be disabled at ++ kernel startup time when setting the command line option of ++ lrng_es_jent.jent_async_enabled=0. Also, setting this option at ++ runtime is allowed via the corresponding SysFS interface. This ++ option is only available with the options SysFS and ++ CONFIG_LRNG_RUNTIME_ES_CONFIG enabled. ++ ++ config LRNG_JENT_ENTROPY_BLOCKS_DISABLED ++ bool "Async collection disabled" ++ ++ # Any block number is allowed, provided it is a power of 2 and ++ # equal or larger than 4 (4 is due to the division in ++ # lrng_jent_async_get when deciding to wake up the monitor). ++ config LRNG_JENT_ENTROPY_BLOCKS_NO_32 ++ bool "32 blocks" ++ ++ config LRNG_JENT_ENTROPY_BLOCKS_NO_64 ++ bool "64 blocks" ++ ++ config LRNG_JENT_ENTROPY_BLOCKS_NO_128 ++ bool "128 blocks (default)" ++ ++ config LRNG_JENT_ENTROPY_BLOCKS_NO_256 ++ bool "256 blocks" ++ ++ config LRNG_JENT_ENTROPY_BLOCKS_NO_512 ++ bool "512 blocks" ++ ++ config LRNG_JENT_ENTROPY_BLOCKS_NO_1024 ++ bool "1024 blocks" ++ ++endchoice ++ ++config LRNG_JENT_ENTROPY_BLOCKS ++ int ++ default 0 if LRNG_JENT_ENTROPY_BLOCKS_DISABLED ++ default 32 if LRNG_JENT_ENTROPY_BLOCKS_NO_32 ++ default 64 if LRNG_JENT_ENTROPY_BLOCKS_NO_64 ++ default 128 if LRNG_JENT_ENTROPY_BLOCKS_NO_128 ++ default 256 if LRNG_JENT_ENTROPY_BLOCKS_NO_256 ++ default 512 if LRNG_JENT_ENTROPY_BLOCKS_NO_512 ++ default 1024 if LRNG_JENT_ENTROPY_BLOCKS_NO_1024 ++ ++config LRNG_JENT_ENTROPY_RATE ++ int "Jitter RNG Entropy Source Entropy Rate" ++ depends on LRNG_JENT ++ range 0 256 ++ default 16 ++ help ++ The option defines the amount of entropy the LRNG applies to 256 ++ bits of data obtained from the Jitter RNG entropy source. The ++ LRNG enforces the limit that this value must be in the range ++ between 0 and 256. ++ ++ When configuring this value to 0, the Jitter RNG entropy source ++ will provide 256 bits of data without being credited to contain ++ entropy. ++ + comment "CPU Entropy Source" + + config LRNG_CPU +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -23,5 +23,6 @@ obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq. + obj-$(CONFIG_LRNG_KERNEL_RNG) += lrng_es_krng.o + obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o + obj-$(CONFIG_LRNG_CPU) += lrng_es_cpu.o ++obj-$(CONFIG_LRNG_JENT) += lrng_es_jent.o + + obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_es_jent.c +@@ -0,0 +1,356 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Fast Entropy Source: Jitter RNG ++ * ++ * Copyright (C) 2022 - 2023, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_definitions.h" ++#include "lrng_es_aux.h" ++#include "lrng_es_jent.h" ++#include "lrng_es_mgr.h" ++ ++/* ++ * Estimated entropy of data is a 16th of LRNG_DRNG_SECURITY_STRENGTH_BITS. ++ * Albeit a full entropy assessment is provided for the noise source indicating ++ * that it provides high entropy rates and considering that it deactivates ++ * when it detects insufficient hardware, the chosen under estimation of ++ * entropy is considered to be acceptable to all reviewers. ++ */ ++static u32 jent_entropy = CONFIG_LRNG_JENT_ENTROPY_RATE; ++#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG ++module_param(jent_entropy, uint, 0644); ++MODULE_PARM_DESC(jent_entropy, ++ "Entropy in bits of 256 data bits from Jitter RNG noise source"); ++#endif ++ ++static bool lrng_jent_initialized = false; ++static struct crypto_rng *jent; ++ ++#if (CONFIG_LRNG_JENT_ENTROPY_BLOCKS != 0) ++ ++/* Entropy buffer filled by Jitter RNG thread - must be power of 2 */ ++#define LRNG_JENT_ENTROPY_BLOCKS_MASK (CONFIG_LRNG_JENT_ENTROPY_BLOCKS - 1) ++ ++struct jent_entropy_es { ++ uint8_t e[LRNG_DRNG_INIT_SEED_SIZE_BYTES]; ++ uint32_t e_bits; ++}; ++ ++/* Buffer that is filled with Jitter RNG data by a thread. */ ++static struct jent_entropy_es ++ lrng_jent_async[CONFIG_LRNG_JENT_ENTROPY_BLOCKS] __aligned(sizeof(u64)); ++ ++/* State of each Jitter RNG buffer entry to ensure atomic access. */ ++enum lrng_jent_async_state { ++ buffer_empty, ++ buffer_filling, ++ buffer_filled, ++ buffer_reading, ++}; ++static atomic_t lrng_jent_async_set[CONFIG_LRNG_JENT_ENTROPY_BLOCKS]; ++ ++/* Jitter RNG buffer work handler. */ ++static struct work_struct lrng_jent_async_work; ++ ++/* Is the asynchronous operation enabled? */ ++static bool lrng_es_jent_async_enabled = true; ++ ++#else /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ ++ ++/* The asynchronous operation is disabled by compile time option. */ ++static bool lrng_es_jent_async_enabled = false; ++ ++#endif /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ ++ ++static u32 lrng_jent_entropylevel(u32 requested_bits) ++{ ++ return lrng_fast_noise_entropylevel(lrng_jent_initialized ? ++ jent_entropy : 0, requested_bits); ++} ++ ++static u32 lrng_jent_poolsize(void) ++{ ++ return lrng_jent_entropylevel(lrng_security_strength()); ++} ++ ++static void __lrng_jent_get(u8 *e, u32 *e_bits, u32 requested_bits) ++{ ++ int ret; ++ u32 ent_bits = lrng_jent_entropylevel(requested_bits); ++ unsigned long flags; ++ static DEFINE_SPINLOCK(lrng_jent_lock); ++ ++ if (!lrng_jent_initialized) ++ goto err; ++ ++ spin_lock_irqsave(&lrng_jent_lock, flags); ++ ret = crypto_rng_get_bytes(jent, e, requested_bits >> 3); ++ spin_unlock_irqrestore(&lrng_jent_lock, flags); ++ ++ if (ret) { ++ pr_debug("Jitter RNG failed with %d\n", ret); ++ goto err; ++ } ++ ++ pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n", ++ ent_bits); ++ ++ *e_bits = ent_bits; ++ return; ++ ++err: ++ *e_bits = 0; ++} ++ ++/* ++ * lrng_get_jent() - Get Jitter RNG entropy ++ * ++ * @eb: entropy buffer to store entropy ++ * @requested_bits: requested entropy in bits ++ */ ++static void lrng_jent_get(struct entropy_buf *eb, u32 requested_bits, ++ bool __unused) ++{ ++ __lrng_jent_get(eb->e[lrng_ext_es_jitter], ++ &eb->e_bits[lrng_ext_es_jitter], requested_bits); ++} ++ ++#if (CONFIG_LRNG_JENT_ENTROPY_BLOCKS != 0) ++ ++/* Fill the Jitter RNG buffer with random data. */ ++static void lrng_jent_async_monitor(struct work_struct *__unused) ++{ ++ unsigned int i, requested_bits = lrng_get_seed_entropy_osr(true); ++ ++ pr_debug("Jitter RNG block filling started\n"); ++ ++ for (i = 0; i < CONFIG_LRNG_JENT_ENTROPY_BLOCKS; i++) { ++ /* Ensure atomic access to the Jitter RNG buffer slot. */ ++ if (atomic_cmpxchg(&lrng_jent_async_set[i], ++ buffer_empty, buffer_filling) != ++ buffer_empty) ++ continue; ++ ++ /* ++ * Always gather entropy data including ++ * potential oversampling factor. ++ */ ++ __lrng_jent_get(lrng_jent_async[i].e, ++ &lrng_jent_async[i].e_bits, requested_bits); ++ ++ atomic_set(&lrng_jent_async_set[i], buffer_filled); ++ ++ pr_debug("Jitter RNG ES monitor: filled slot %u with %u bits of entropy\n", ++ i, requested_bits); ++ } ++ ++ pr_debug("Jitter RNG block filling completed\n"); ++} ++ ++static void lrng_jent_async_monitor_schedule(void) ++{ ++ if (lrng_es_jent_async_enabled) ++ schedule_work(&lrng_jent_async_work); ++} ++ ++static void lrng_jent_async_fini(void) ++{ ++ /* Reset state */ ++ memzero_explicit(lrng_jent_async, sizeof(lrng_jent_async)); ++} ++ ++/* Get Jitter RNG data from the buffer */ ++static void lrng_jent_async_get(struct entropy_buf *eb, uint32_t requested_bits, ++ bool __unused) ++{ ++ static atomic_t idx = ATOMIC_INIT(-1); ++ unsigned int slot; ++ ++ (void)requested_bits; ++ ++ if (!lrng_jent_initialized) { ++ eb->e_bits[lrng_ext_es_jitter] = 0; ++ return; ++ } ++ ++ /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS must be a power of 2 */ ++ BUILD_BUG_ON((CONFIG_LRNG_JENT_ENTROPY_BLOCKS & ++ LRNG_JENT_ENTROPY_BLOCKS_MASK) != 0); ++ ++ slot = ((unsigned int)atomic_inc_return(&idx)) & ++ LRNG_JENT_ENTROPY_BLOCKS_MASK; ++ ++ /* Ensure atomic access to the Jitter RNG buffer slot. */ ++ if (atomic_cmpxchg(&lrng_jent_async_set[slot], ++ buffer_filled, buffer_reading) != buffer_filled) { ++ pr_debug("Jitter RNG ES monitor: buffer slot %u exhausted\n", ++ slot); ++ lrng_jent_get(eb, requested_bits, __unused); ++ lrng_jent_async_monitor_schedule(); ++ return; ++ } ++ ++ pr_debug("Jitter RNG ES monitor: used slot %u\n", slot); ++ memcpy(eb->e[lrng_ext_es_jitter], lrng_jent_async[slot].e, ++ LRNG_DRNG_INIT_SEED_SIZE_BYTES); ++ eb->e_bits[lrng_ext_es_jitter] = lrng_jent_async[slot].e_bits; ++ ++ pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n", ++ eb->e_bits[lrng_ext_es_jitter]); ++ ++ memzero_explicit(&lrng_jent_async[slot], ++ sizeof(struct jent_entropy_es)); ++ ++ atomic_set(&lrng_jent_async_set[slot], buffer_empty); ++ ++ /* Ensure division in the following check works */ ++ BUILD_BUG_ON(CONFIG_LRNG_JENT_ENTROPY_BLOCKS < 4); ++ if (!(slot % (CONFIG_LRNG_JENT_ENTROPY_BLOCKS / 4)) && slot) ++ lrng_jent_async_monitor_schedule(); ++} ++ ++static void lrng_jent_get_check(struct entropy_buf *eb, ++ uint32_t requested_bits, bool __unused) ++{ ++ if (lrng_es_jent_async_enabled && ++ (requested_bits == lrng_get_seed_entropy_osr(true))) { ++ lrng_jent_async_get(eb, requested_bits, __unused); ++ } else { ++ lrng_jent_get(eb, requested_bits, __unused); ++ } ++} ++ ++static void lrng_jent_async_init(void) ++{ ++ unsigned int i; ++ ++ if (!lrng_es_jent_async_enabled) ++ return; ++ ++ for (i = 0; i < CONFIG_LRNG_JENT_ENTROPY_BLOCKS; i++) ++ atomic_set(&lrng_jent_async_set[i], buffer_empty); ++} ++ ++static void lrng_jent_async_init_complete(void) ++{ ++ lrng_jent_async_init(); ++ INIT_WORK(&lrng_jent_async_work, lrng_jent_async_monitor); ++} ++ ++#if (defined(CONFIG_SYSFS) && defined(CONFIG_LRNG_RUNTIME_ES_CONFIG)) ++/* Initialize or deinitialize the Jitter RNG async collection */ ++static int lrng_jent_async_sysfs_set(const char *val, ++ const struct kernel_param *kp) ++{ ++ static const char val_dflt[] = "1"; ++ int ret; ++ bool setting; ++ ++ if (!val) ++ val = val_dflt; ++ ++ ret = kstrtobool(val, &setting); ++ if (ret) ++ return ret; ++ ++ if (setting) { ++ if (!lrng_es_jent_async_enabled) { ++ lrng_es_jent_async_enabled = 1; ++ lrng_jent_async_init(); ++ pr_devel("Jitter RNG async data collection enabled\n"); ++ lrng_jent_async_monitor_schedule(); ++ } ++ } else { ++ if (lrng_es_jent_async_enabled) { ++ lrng_es_jent_async_enabled = 0; ++ lrng_jent_async_fini(); ++ pr_devel("Jitter RNG async data collection disabled\n"); ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct kernel_param_ops lrng_jent_async_sysfs = { ++ .set = lrng_jent_async_sysfs_set, ++ .get = param_get_bool, ++}; ++module_param_cb(jent_async_enabled, &lrng_jent_async_sysfs, ++ &lrng_es_jent_async_enabled, 0644); ++MODULE_PARM_DESC(lrng_es_jent_async_enabled, ++ "Enable Jitter RNG entropy buffer asynchronous collection"); ++#endif /* CONFIG_SYSFS && CONFIG_LRNG_RUNTIME_ES_CONFIG */ ++ ++#else /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ ++ ++static void lrng_jent_get_check(struct entropy_buf *eb, ++ uint32_t requested_bits, bool __unused) ++{ ++ lrng_jent_get(eb, requested_bits, __unused); ++} ++ ++static inline void __init lrng_jent_async_init_complete(void) { } ++ ++#endif /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ ++ ++static void lrng_jent_es_state(unsigned char *buf, size_t buflen) ++{ ++ snprintf(buf, buflen, ++ " Available entropy: %u\n" ++ " Enabled: %s\n" ++ " Jitter RNG async collection %s\n", ++ lrng_jent_poolsize(), ++ lrng_jent_initialized ? "true" : "false", ++ lrng_es_jent_async_enabled ? "true" : "false"); ++} ++ ++static int __init lrng_jent_initialize(void) ++{ ++ jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); ++ if (IS_ERR(jent)) { ++ pr_err("Cannot allocate Jitter RNG\n"); ++ return PTR_ERR(jent); ++ } ++ ++ lrng_jent_async_init_complete(); ++ ++ lrng_jent_initialized = true; ++ pr_debug("Jitter RNG working on current system\n"); ++ ++ /* ++ * In FIPS mode, the Jitter RNG is defined to have full of entropy ++ * unless a different value has been specified at the command line ++ * (i.e. the user overrides the default), and the default value is ++ * larger than zero (if it is zero, it is assumed that an RBG2(P) or ++ * RBG2(NP) construction is attempted that intends to exclude the ++ * Jitter RNG). ++ */ ++ if (fips_enabled && CONFIG_LRNG_JENT_ENTROPY_RATE > 0 && ++ jent_entropy == CONFIG_LRNG_JENT_ENTROPY_RATE) ++ jent_entropy = LRNG_DRNG_SECURITY_STRENGTH_BITS; ++ ++ if (jent_entropy) ++ lrng_force_fully_seeded(); ++ ++ return 0; ++} ++device_initcall(lrng_jent_initialize); ++ ++struct lrng_es_cb lrng_es_jent = { ++ .name = "JitterRNG", ++ .get_ent = lrng_jent_get_check, ++ .curr_entropy = lrng_jent_entropylevel, ++ .max_entropy = lrng_jent_poolsize, ++ .state = lrng_jent_es_state, ++ .reset = NULL, ++ .switch_hash = NULL, ++}; diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch new file mode 100644 index 000000000..6961b98ab --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch @@ -0,0 +1,60 @@ +From 718c21ecd7a9ac35fbdf28d2dcd2310634c669ef Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 17:56:56 +0200 +Subject: [PATCH 18/25] LRNG - add option to enable runtime entropy rate + configuration + +The entropy rate for the different entropy sources is configured at +compile time. Enabling the option CONFIG_LRNG_RUNTIME_ES_CONFIG allows +the entropy sources' entropy rate to be adjusted at runtime or boot +time. The different options are: + +- IRQ ES: lrng_es_irq.irq_entropy + +- Scheduler ES: lrng_es_sched.sched_entropy + +- CPU ES: lrng_es_cpu.cpu_entropy + +- Kernel ES: lrng_es_krng.krng_entropy + +- Jitter RNG ES: lrng_es_jent.jent_entropy + +The values to be specified there must apply the rationale given for the +different CONFIG_LRNG_*_ENTROPY_RATE kernel configuration options. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -124,17 +124,17 @@ endmenu # "Specific DRNG seeding strateg + + menu "Entropy Source Configuration" + +-# config LRNG_RUNTIME_ES_CONFIG +-# bool "Enable runtime configuration of entropy sources" +-# help +-# When enabling this option, the LRNG provides the mechanism +-# allowing to alter the entropy rate of each entropy source +-# during boot time and runtime. +-# +-# Each entropy source allows its entropy rate changed with +-# a kernel command line option. When not providing any +-# option, the default specified during kernel compilation +-# is applied. ++config LRNG_RUNTIME_ES_CONFIG ++ bool "Enable runtime configuration of entropy sources" ++ help ++ When enabling this option, the LRNG provides the mechanism ++ allowing to alter the entropy rate of each entropy source ++ during boot time and runtime. ++ ++ Each entropy source allows its entropy rate changed with ++ a kernel command line option. When not providing any ++ option, the default specified during kernel compilation ++ is applied. + + comment "Common Timer-based Entropy Source Configuration" + diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch new file mode 100644 index 000000000..ac7aee69c --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch @@ -0,0 +1,1533 @@ +From 78cb1213ad35895b6d0d1a1ff49224f0c123e86c Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 18 Dec 2022 21:22:36 +0100 +Subject: [PATCH 19/25] LRNG - add interface for gathering of raw entropy + +The test interface allows a privileged process to capture the raw +unconditioned noise that is collected by the LRNG for statistical +analysis. Such testing allows the analysis how much entropy +the interrupt noise source provides on a given platform. +Extracted noise data is not used to seed the LRNG. This +is a test interface and not appropriate for production systems. +Yet, the interface is considered to be sufficiently secured for +production systems. + +The raw entropy collection is provided for the internal entropy sources +under full control of the LRNG: the IRQ ES and the scheduler-based ES. +The test interfaces are only enabled for the given ES if the ES is +enabled itself. + +Access to the data is given through the lrng_raw debugfs file. The +data buffer should be multiples of sizeof(u32) to fill the entire +buffer. Using the option lrng_testing.boot_test=1 the raw noise of +the first 1000 entropy events since boot can be sampled. + +This test interface allows generating the data required for +analysis whether the LRNG is in compliance with SP800-90B +sections 3.1.3 and 3.1.4. + +In addition, the test interface allows gathering of the concatenated raw +entropy data to verify that the concatenation works appropriately. +This includes sampling of the following raw IRQ data: + +* high-resolution time stamp obtained for an IRQ event + +* Jiffies + +* IRQ number + +* return instruction pointer + +* interrupt register state + +* array logic batching the high-resolution time stamp + +* a performance monitor of the IRQ ES + +The sampling of the following scheduler-based ES data is possible: + +* high-resolution time stamp obtained for a context switch event + +* the PID of the process scheduled to + +* the process' start time value + +* the process' context switch numbers value + +* a performance monitor of the scheduler-based ES + +Also, a testing interface to support ACVT of the hash implementation +is provided. The reason why only hash testing is supported (as +opposed to also provide testing for the DRNG) is the fact that the +LRNG software hash implementation contains glue code that may +warrant testing in addition to the testing of the software ciphers +via the kernel crypto API. Also, for testing the CTR-DRBG, the +underlying AES implementation would need to be tested. However, +such AES test interface cannot be provided by the LRNG as it has no +means to access the AES operation. + +If a test interface is not compiled, its code is a noop which has no +impact on the performance. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 534 +++++++++--------- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_testing.c | 901 +++++++++++++++++++++++++++++++ + 3 files changed, 1169 insertions(+), 267 deletions(-) + create mode 100644 drivers/char/lrng/lrng_testing.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -718,273 +718,273 @@ choice + select LRNG_DRNG_KCAPI + endchoice + +-# menuconfig LRNG_TESTING_MENU +-# bool "LRNG testing interfaces" +-# depends on DEBUG_FS +-# help +-# Enable one or more of the following test interfaces. +-# +-# If unsure, say N. +-# +-# if LRNG_TESTING_MENU +-# +-# config LRNG_TESTING +-# bool +-# +-# config LRNG_TESTING_RECORDING +-# bool +-# +-# comment "Interrupt Entropy Source Test Interfaces" +-# +-# config LRNG_RAW_HIRES_ENTROPY +-# bool "Interface to obtain raw unprocessed IRQ noise source data" +-# default y +-# depends on LRNG_IRQ +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned high resolution time stamp noise that +-# is collected by the LRNG for statistical analysis. Extracted +-# noise data is not used to seed the LRNG. +-# +-# The raw noise data can be obtained using the lrng_raw_hires +-# debugfs file. Using the option lrng_testing.boot_raw_hires_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_RAW_JIFFIES_ENTROPY +-# bool "Entropy test interface to Jiffies of IRQ noise source" +-# depends on LRNG_IRQ +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned Jiffies that is collected by +-# the LRNG for statistical analysis. This data is used for +-# seeding the LRNG if a high-resolution time stamp is not +-# available. If a high-resolution time stamp is detected, +-# the Jiffies value is not collected by the LRNG and no +-# data is provided via the test interface. Extracted noise +-# data is not used to seed the random number generator. +-# +-# The raw noise data can be obtained using the lrng_raw_jiffies +-# debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_RAW_IRQ_ENTROPY +-# bool "Entropy test interface to IRQ number noise source" +-# depends on LRNG_IRQ +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned interrupt number that is collected by +-# the LRNG for statistical analysis. Extracted noise data is +-# not used to seed the random number generator. +-# +-# The raw noise data can be obtained using the lrng_raw_irq +-# debugfs file. Using the option lrng_testing.boot_raw_irq_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_RAW_RETIP_ENTROPY +-# bool "Entropy test interface to RETIP value of IRQ noise source" +-# depends on LRNG_IRQ +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned return instruction pointer value +-# that is collected by the LRNG for statistical analysis. +-# Extracted noise data is not used to seed the random number +-# generator. +-# +-# The raw noise data can be obtained using the lrng_raw_retip +-# debugfs file. Using the option lrng_testing.boot_raw_retip_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_RAW_REGS_ENTROPY +-# bool "Entropy test interface to IRQ register value noise source" +-# depends on LRNG_IRQ +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned interrupt register value that is +-# collected by the LRNG for statistical analysis. Extracted noise +-# data is not used to seed the random number generator. +-# +-# The raw noise data can be obtained using the lrng_raw_regs +-# debugfs file. Using the option lrng_testing.boot_raw_regs_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_RAW_ARRAY +-# bool "Test interface to LRNG raw entropy IRQ storage array" +-# depends on LRNG_IRQ +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw noise data that is collected by the LRNG +-# in the per-CPU array for statistical analysis. The purpose +-# of this interface is to verify that the array handling code +-# truly only concatenates data and provides the same entropy +-# rate as the raw unconditioned noise source when assessing +-# the collected data byte-wise. +-# +-# The data can be obtained using the lrng_raw_array debugfs +-# file. Using the option lrng_testing.boot_raw_array=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_IRQ_PERF +-# bool "LRNG interrupt entropy source performance monitor" +-# depends on LRNG_IRQ +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# With this option, the performance monitor of the LRNG +-# interrupt handling code is enabled. The file provides +-# the execution time of the interrupt handler in +-# cycles. +-# +-# The interrupt performance data can be obtained using +-# the lrng_irq_perf debugfs file. Using the option +-# lrng_testing.boot_irq_perf=1 the performance data of +-# the first 1000 entropy events since boot can be sampled. +-# +-# comment "Scheduler Entropy Source Test Interfaces" +-# +-# config LRNG_RAW_SCHED_HIRES_ENTROPY +-# bool "Interface to obtain raw unprocessed scheduler noise source data" +-# depends on LRNG_SCHED +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned high resolution time stamp noise that +-# is collected by the LRNG for the Scheduler-based noise source +-# for statistical analysis. Extracted noise data is not used to +-# seed the LRNG. +-# +-# The raw noise data can be obtained using the lrng_raw_sched_hires +-# debugfs file. Using the option +-# lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the +-# first 1000 entropy events since boot can be sampled. +-# +-# config LRNG_RAW_SCHED_PID_ENTROPY +-# bool "Entropy test interface to PID value" +-# depends on LRNG_SCHED +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned PID value that is collected by the +-# LRNG for statistical analysis. Extracted noise +-# data is not used to seed the random number generator. +-# +-# The raw noise data can be obtained using the +-# lrng_raw_sched_pid debugfs file. Using the option +-# lrng_testing.boot_raw_sched_pid_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_RAW_SCHED_START_TIME_ENTROPY +-# bool "Entropy test interface to task start time value" +-# depends on LRNG_SCHED +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned task start time value that is collected +-# by the LRNG for statistical analysis. Extracted noise +-# data is not used to seed the random number generator. +-# +-# The raw noise data can be obtained using the +-# lrng_raw_sched_starttime debugfs file. Using the option +-# lrng_testing.boot_raw_sched_starttime_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# +-# config LRNG_RAW_SCHED_NVCSW_ENTROPY +-# bool "Entropy test interface to task context switch numbers" +-# depends on LRNG_SCHED +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# The test interface allows a privileged process to capture +-# the raw unconditioned task numbers of context switches that +-# are collected by the LRNG for statistical analysis. Extracted +-# noise data is not used to seed the random number generator. +-# +-# The raw noise data can be obtained using the +-# lrng_raw_sched_nvcsw debugfs file. Using the option +-# lrng_testing.boot_raw_sched_nvcsw_test=1 +-# the raw noise of the first 1000 entropy events since boot +-# can be sampled. +-# +-# config LRNG_SCHED_PERF +-# bool "LRNG scheduler entropy source performance monitor" +-# depends on LRNG_SCHED +-# select LRNG_TESTING +-# select LRNG_TESTING_RECORDING +-# help +-# With this option, the performance monitor of the LRNG +-# scheduler event handling code is enabled. The file provides +-# the execution time of the interrupt handler in cycles. +-# +-# The scheduler performance data can be obtained using +-# the lrng_sched_perf debugfs file. Using the option +-# lrng_testing.boot_sched_perf=1 the performance data of +-# the first 1000 entropy events since boot can be sampled. +-# +-# comment "Auxiliary Test Interfaces" +-# +-# config LRNG_ACVT_HASH +-# bool "Enable LRNG ACVT Hash interface" +-# select LRNG_TESTING +-# help +-# With this option, the LRNG built-in hash function used for +-# auxiliary pool management and prior to switching the +-# cryptographic backends is made available for ACVT. The +-# interface allows writing of the data to be hashed +-# into the interface. The read operation triggers the hash +-# operation to generate message digest. +-# +-# The ACVT interface is available with the lrng_acvt_hash +-# debugfs file. +-# +-# config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG +-# bool "Enable runtime configuration of max reseed threshold" +-# help +-# When enabling this option, the LRNG provides an interface +-# allowing the setting of the maximum number of DRNG generate +-# operations without a reseed that has full entropy. The +-# interface is lrng_drng.max_wo_reseed. +-# +-#config LRNG_RUNTIME_FORCE_SEEDING_DISABLE +-# bool "Enable runtime configuration of force seeding" +-# help +-# When enabling this option, the LRNG provides an interface +-# allowing the disabling of the force seeding when the DRNG +-# is not fully seeded but entropy is available. +-# +-# config LRNG_TEST_CPU_ES_COMPRESSION +-# bool "Force CPU ES compression operation" +-# help +-# When enabling this option, the CPU ES compression operation +-# is forced by setting an arbitrary value > 1 for the data +-# multiplier even when the CPU ES would deliver full entropy. +-# This allows testing of the compression operation. It +-# therefore forces to pull more data from the CPU ES +-# than what may be required. +-# +-# endif #LRNG_TESTING_MENU ++menuconfig LRNG_TESTING_MENU ++ bool "LRNG testing interfaces" ++ depends on DEBUG_FS ++ help ++ Enable one or more of the following test interfaces. ++ ++ If unsure, say N. ++ ++if LRNG_TESTING_MENU ++ ++config LRNG_TESTING ++ bool ++ ++config LRNG_TESTING_RECORDING ++ bool ++ ++comment "Interrupt Entropy Source Test Interfaces" ++ ++config LRNG_RAW_HIRES_ENTROPY ++ bool "Interface to obtain raw unprocessed IRQ noise source data" ++ default y ++ depends on LRNG_IRQ ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned high resolution time stamp noise that ++ is collected by the LRNG for statistical analysis. Extracted ++ noise data is not used to seed the LRNG. ++ ++ The raw noise data can be obtained using the lrng_raw_hires ++ debugfs file. Using the option lrng_testing.boot_raw_hires_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_RAW_JIFFIES_ENTROPY ++ bool "Entropy test interface to Jiffies of IRQ noise source" ++ depends on LRNG_IRQ ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned Jiffies that is collected by ++ the LRNG for statistical analysis. This data is used for ++ seeding the LRNG if a high-resolution time stamp is not ++ available. If a high-resolution time stamp is detected, ++ the Jiffies value is not collected by the LRNG and no ++ data is provided via the test interface. Extracted noise ++ data is not used to seed the random number generator. ++ ++ The raw noise data can be obtained using the lrng_raw_jiffies ++ debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_RAW_IRQ_ENTROPY ++ bool "Entropy test interface to IRQ number noise source" ++ depends on LRNG_IRQ ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned interrupt number that is collected by ++ the LRNG for statistical analysis. Extracted noise data is ++ not used to seed the random number generator. ++ ++ The raw noise data can be obtained using the lrng_raw_irq ++ debugfs file. Using the option lrng_testing.boot_raw_irq_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_RAW_RETIP_ENTROPY ++ bool "Entropy test interface to RETIP value of IRQ noise source" ++ depends on LRNG_IRQ ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned return instruction pointer value ++ that is collected by the LRNG for statistical analysis. ++ Extracted noise data is not used to seed the random number ++ generator. ++ ++ The raw noise data can be obtained using the lrng_raw_retip ++ debugfs file. Using the option lrng_testing.boot_raw_retip_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_RAW_REGS_ENTROPY ++ bool "Entropy test interface to IRQ register value noise source" ++ depends on LRNG_IRQ ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned interrupt register value that is ++ collected by the LRNG for statistical analysis. Extracted noise ++ data is not used to seed the random number generator. ++ ++ The raw noise data can be obtained using the lrng_raw_regs ++ debugfs file. Using the option lrng_testing.boot_raw_regs_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_RAW_ARRAY ++ bool "Test interface to LRNG raw entropy IRQ storage array" ++ depends on LRNG_IRQ ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw noise data that is collected by the LRNG ++ in the per-CPU array for statistical analysis. The purpose ++ of this interface is to verify that the array handling code ++ truly only concatenates data and provides the same entropy ++ rate as the raw unconditioned noise source when assessing ++ the collected data byte-wise. ++ ++ The data can be obtained using the lrng_raw_array debugfs ++ file. Using the option lrng_testing.boot_raw_array=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_IRQ_PERF ++ bool "LRNG interrupt entropy source performance monitor" ++ depends on LRNG_IRQ ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ With this option, the performance monitor of the LRNG ++ interrupt handling code is enabled. The file provides ++ the execution time of the interrupt handler in ++ cycles. ++ ++ The interrupt performance data can be obtained using ++ the lrng_irq_perf debugfs file. Using the option ++ lrng_testing.boot_irq_perf=1 the performance data of ++ the first 1000 entropy events since boot can be sampled. ++ ++comment "Scheduler Entropy Source Test Interfaces" ++ ++config LRNG_RAW_SCHED_HIRES_ENTROPY ++ bool "Interface to obtain raw unprocessed scheduler noise source data" ++ depends on LRNG_SCHED ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned high resolution time stamp noise that ++ is collected by the LRNG for the Scheduler-based noise source ++ for statistical analysis. Extracted noise data is not used to ++ seed the LRNG. ++ ++ The raw noise data can be obtained using the lrng_raw_sched_hires ++ debugfs file. Using the option ++ lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the ++ first 1000 entropy events since boot can be sampled. ++ ++config LRNG_RAW_SCHED_PID_ENTROPY ++ bool "Entropy test interface to PID value" ++ depends on LRNG_SCHED ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned PID value that is collected by the ++ LRNG for statistical analysis. Extracted noise ++ data is not used to seed the random number generator. ++ ++ The raw noise data can be obtained using the ++ lrng_raw_sched_pid debugfs file. Using the option ++ lrng_testing.boot_raw_sched_pid_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_RAW_SCHED_START_TIME_ENTROPY ++ bool "Entropy test interface to task start time value" ++ depends on LRNG_SCHED ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned task start time value that is collected ++ by the LRNG for statistical analysis. Extracted noise ++ data is not used to seed the random number generator. ++ ++ The raw noise data can be obtained using the ++ lrng_raw_sched_starttime debugfs file. Using the option ++ lrng_testing.boot_raw_sched_starttime_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++ ++config LRNG_RAW_SCHED_NVCSW_ENTROPY ++ bool "Entropy test interface to task context switch numbers" ++ depends on LRNG_SCHED ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ The test interface allows a privileged process to capture ++ the raw unconditioned task numbers of context switches that ++ are collected by the LRNG for statistical analysis. Extracted ++ noise data is not used to seed the random number generator. ++ ++ The raw noise data can be obtained using the ++ lrng_raw_sched_nvcsw debugfs file. Using the option ++ lrng_testing.boot_raw_sched_nvcsw_test=1 ++ the raw noise of the first 1000 entropy events since boot ++ can be sampled. ++ ++config LRNG_SCHED_PERF ++ bool "LRNG scheduler entropy source performance monitor" ++ depends on LRNG_SCHED ++ select LRNG_TESTING ++ select LRNG_TESTING_RECORDING ++ help ++ With this option, the performance monitor of the LRNG ++ scheduler event handling code is enabled. The file provides ++ the execution time of the interrupt handler in cycles. ++ ++ The scheduler performance data can be obtained using ++ the lrng_sched_perf debugfs file. Using the option ++ lrng_testing.boot_sched_perf=1 the performance data of ++ the first 1000 entropy events since boot can be sampled. ++ ++comment "Auxiliary Test Interfaces" ++ ++config LRNG_ACVT_HASH ++ bool "Enable LRNG ACVT Hash interface" ++ select LRNG_TESTING ++ help ++ With this option, the LRNG built-in hash function used for ++ auxiliary pool management and prior to switching the ++ cryptographic backends is made available for ACVT. The ++ interface allows writing of the data to be hashed ++ into the interface. The read operation triggers the hash ++ operation to generate message digest. ++ ++ The ACVT interface is available with the lrng_acvt_hash ++ debugfs file. ++ ++config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG ++ bool "Enable runtime configuration of max reseed threshold" ++ help ++ When enabling this option, the LRNG provides an interface ++ allowing the setting of the maximum number of DRNG generate ++ operations without a reseed that has full entropy. The ++ interface is lrng_drng.max_wo_reseed. ++ ++config LRNG_RUNTIME_FORCE_SEEDING_DISABLE ++ bool "Enable runtime configuration of force seeding" ++ help ++ When enabling this option, the LRNG provides an interface ++ allowing the disabling of the force seeding when the DRNG ++ is not fully seeded but entropy is available. ++ ++config LRNG_TEST_CPU_ES_COMPRESSION ++ bool "Force CPU ES compression operation" ++ help ++ When enabling this option, the CPU ES compression operation ++ is forced by setting an arbitrary value > 1 for the data ++ multiplier even when the CPU ES would deliver full entropy. ++ This allows testing of the compression operation. It ++ therefore forces to pull more data from the CPU ES ++ than what may be required. ++ ++endif #LRNG_TESTING_MENU + # + # config LRNG_SELFTEST + # bool "Enable power-on and on-demand self-tests" +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -26,3 +26,4 @@ obj-$(CONFIG_LRNG_CPU) += lrng_es_cpu. + obj-$(CONFIG_LRNG_JENT) += lrng_es_jent.o + + obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o ++obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_testing.c +@@ -0,0 +1,901 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG testing interfaces to obtain raw entropy ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_definitions.h" ++#include "lrng_drng_chacha20.h" ++#include "lrng_sha.h" ++#include "lrng_testing.h" ++ ++#if defined(CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY) || \ ++ defined(CONFIG_LRNG_RAW_SCHED_PID_ENTROPY) || \ ++ defined(CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY) || \ ++ defined(CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY) || \ ++ defined(CONFIG_LRNG_SCHED_PERF) ++#define LRNG_TESTING_USE_BUSYLOOP ++#endif ++ ++#ifdef CONFIG_LRNG_TESTING_RECORDING ++ ++#define LRNG_TESTING_RINGBUFFER_SIZE 1024 ++#define LRNG_TESTING_RINGBUFFER_MASK (LRNG_TESTING_RINGBUFFER_SIZE - 1) ++ ++struct lrng_testing { ++ u32 lrng_testing_rb[LRNG_TESTING_RINGBUFFER_SIZE]; ++ u32 rb_reader; ++ atomic_t rb_writer; ++ atomic_t lrng_testing_enabled; ++ spinlock_t lock; ++ wait_queue_head_t read_wait; ++}; ++ ++/*************************** Generic Data Handling ****************************/ ++ ++/* ++ * boot variable: ++ * 0 ==> No boot test, gathering of runtime data allowed ++ * 1 ==> Boot test enabled and ready for collecting data, gathering runtime ++ * data is disabled ++ * 2 ==> Boot test completed and disabled, gathering of runtime data is ++ * disabled ++ */ ++ ++static void lrng_testing_reset(struct lrng_testing *data) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ data->rb_reader = 0; ++ atomic_set(&data->rb_writer, 0); ++ spin_unlock_irqrestore(&data->lock, flags); ++} ++ ++static void lrng_testing_init(struct lrng_testing *data, u32 boot) ++{ ++ /* ++ * The boot time testing implies we have a running test. If the ++ * caller wants to clear it, he has to unset the boot_test flag ++ * at runtime via sysfs to enable regular runtime testing ++ */ ++ if (boot) ++ return; ++ ++ lrng_testing_reset(data); ++ atomic_set(&data->lrng_testing_enabled, 1); ++ pr_warn("Enabling data collection\n"); ++} ++ ++static void lrng_testing_fini(struct lrng_testing *data, u32 boot) ++{ ++ /* If we have boot data, we do not reset yet to allow data to be read */ ++ if (boot) ++ return; ++ ++ atomic_set(&data->lrng_testing_enabled, 0); ++ lrng_testing_reset(data); ++ pr_warn("Disabling data collection\n"); ++} ++ ++static bool lrng_testing_store(struct lrng_testing *data, u32 value, ++ u32 *boot) ++{ ++ unsigned long flags; ++ ++ if (!atomic_read(&data->lrng_testing_enabled) && (*boot != 1)) ++ return false; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ /* ++ * Disable entropy testing for boot time testing after ring buffer ++ * is filled. ++ */ ++ if (*boot) { ++ if (((u32)atomic_read(&data->rb_writer)) > ++ LRNG_TESTING_RINGBUFFER_SIZE) { ++ *boot = 2; ++ pr_warn_once("One time data collection test disabled\n"); ++ spin_unlock_irqrestore(&data->lock, flags); ++ return false; ++ } ++ ++ if (atomic_read(&data->rb_writer) == 1) ++ pr_warn("One time data collection test enabled\n"); ++ } ++ ++ data->lrng_testing_rb[((u32)atomic_read(&data->rb_writer)) & ++ LRNG_TESTING_RINGBUFFER_MASK] = value; ++ atomic_inc(&data->rb_writer); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++#ifndef LRNG_TESTING_USE_BUSYLOOP ++ if (wq_has_sleeper(&data->read_wait)) ++ wake_up_interruptible(&data->read_wait); ++#endif ++ ++ return true; ++} ++ ++static bool lrng_testing_have_data(struct lrng_testing *data) ++{ ++ return ((((u32)atomic_read(&data->rb_writer)) & ++ LRNG_TESTING_RINGBUFFER_MASK) != ++ (data->rb_reader & LRNG_TESTING_RINGBUFFER_MASK)); ++} ++ ++static int lrng_testing_reader(struct lrng_testing *data, u32 *boot, ++ u8 *outbuf, u32 outbuflen) ++{ ++ unsigned long flags; ++ int collected_data = 0; ++ ++ lrng_testing_init(data, *boot); ++ ++ while (outbuflen) { ++ u32 writer = (u32)atomic_read(&data->rb_writer); ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ /* We have no data or reached the writer. */ ++ if (!writer || (writer == data->rb_reader)) { ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ /* ++ * Now we gathered all boot data, enable regular data ++ * collection. ++ */ ++ if (*boot) { ++ *boot = 0; ++ goto out; ++ } ++ ++#ifdef LRNG_TESTING_USE_BUSYLOOP ++ while (!lrng_testing_have_data(data)) ++ ; ++#else ++ wait_event_interruptible(data->read_wait, ++ lrng_testing_have_data(data)); ++#endif ++ if (signal_pending(current)) { ++ collected_data = -ERESTARTSYS; ++ goto out; ++ } ++ ++ continue; ++ } ++ ++ /* We copy out word-wise */ ++ if (outbuflen < sizeof(u32)) { ++ spin_unlock_irqrestore(&data->lock, flags); ++ goto out; ++ } ++ ++ memcpy(outbuf, &data->lrng_testing_rb[data->rb_reader], ++ sizeof(u32)); ++ data->rb_reader++; ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ outbuf += sizeof(u32); ++ outbuflen -= sizeof(u32); ++ collected_data += sizeof(u32); ++ } ++ ++out: ++ lrng_testing_fini(data, *boot); ++ return collected_data; ++} ++ ++static int lrng_testing_extract_user(struct file *file, char __user *buf, ++ size_t nbytes, loff_t *ppos, ++ int (*reader)(u8 *outbuf, u32 outbuflen)) ++{ ++ u8 *tmp, *tmp_aligned; ++ int ret = 0, large_request = (nbytes > 256); ++ ++ if (!nbytes) ++ return 0; ++ ++ /* ++ * The intention of this interface is for collecting at least ++ * 1000 samples due to the SP800-90B requirements. So, we make no ++ * effort in avoiding allocating more memory that actually needed ++ * by the user. Hence, we allocate sufficient memory to always hold ++ * that amount of data. ++ */ ++ tmp = kmalloc(LRNG_TESTING_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL); ++ if (!tmp) ++ return -ENOMEM; ++ ++ tmp_aligned = PTR_ALIGN(tmp, sizeof(u32)); ++ ++ while (nbytes) { ++ int i; ++ ++ if (large_request && need_resched()) { ++ if (signal_pending(current)) { ++ if (ret == 0) ++ ret = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } ++ ++ i = min_t(int, nbytes, LRNG_TESTING_RINGBUFFER_SIZE); ++ i = reader(tmp_aligned, i); ++ if (i <= 0) { ++ if (i < 0) ++ ret = i; ++ break; ++ } ++ if (copy_to_user(buf, tmp_aligned, i)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ nbytes -= i; ++ buf += i; ++ ret += i; ++ } ++ ++ kfree_sensitive(tmp); ++ ++ if (ret > 0) ++ *ppos += ret; ++ ++ return ret; ++} ++ ++#endif /* CONFIG_LRNG_TESTING_RECORDING */ ++ ++/************* Raw High-Resolution IRQ Timer Entropy Data Handling ************/ ++ ++#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY ++ ++static u32 boot_raw_hires_test = 0; ++module_param(boot_raw_hires_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_hires_test, "Enable gathering boot time high resolution timer entropy of the first IRQ entropy events"); ++ ++static struct lrng_testing lrng_raw_hires = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_hires.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_hires.read_wait) ++}; ++ ++bool lrng_raw_hires_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_hires, value, &boot_raw_hires_test); ++} ++ ++static int lrng_raw_hires_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_hires, &boot_raw_hires_test, ++ outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_hires_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_hires_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_hires_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_hires_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */ ++ ++/********************* Raw Jiffies Entropy Data Handling **********************/ ++ ++#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY ++ ++static u32 boot_raw_jiffies_test = 0; ++module_param(boot_raw_jiffies_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_jiffies_test, "Enable gathering boot time high resolution timer entropy of the first entropy events"); ++ ++static struct lrng_testing lrng_raw_jiffies = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_jiffies.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_jiffies.read_wait) ++}; ++ ++bool lrng_raw_jiffies_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_jiffies, value, ++ &boot_raw_jiffies_test); ++} ++ ++static int lrng_raw_jiffies_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_jiffies, &boot_raw_jiffies_test, ++ outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_jiffies_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_jiffies_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_jiffies_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_jiffies_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */ ++ ++/************************** Raw IRQ Data Handling ****************************/ ++ ++#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY ++ ++static u32 boot_raw_irq_test = 0; ++module_param(boot_raw_irq_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_irq_test, "Enable gathering boot time entropy of the first IRQ entropy events"); ++ ++static struct lrng_testing lrng_raw_irq = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_irq.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_irq.read_wait) ++}; ++ ++bool lrng_raw_irq_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_irq, value, &boot_raw_irq_test); ++} ++ ++static int lrng_raw_irq_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_irq, &boot_raw_irq_test, outbuf, ++ outbuflen); ++} ++ ++static ssize_t lrng_raw_irq_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_irq_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_irq_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_irq_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */ ++ ++/************************ Raw _RET_IP_ Data Handling **************************/ ++ ++#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY ++ ++static u32 boot_raw_retip_test = 0; ++module_param(boot_raw_retip_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_retip_test, "Enable gathering boot time entropy of the first return instruction pointer entropy events"); ++ ++static struct lrng_testing lrng_raw_retip = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_retip.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_retip.read_wait) ++}; ++ ++bool lrng_raw_retip_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_retip, value, &boot_raw_retip_test); ++} ++ ++static int lrng_raw_retip_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_retip, &boot_raw_retip_test, ++ outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_retip_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_retip_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_retip_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_retip_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */ ++ ++/********************** Raw IRQ register Data Handling ************************/ ++ ++#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY ++ ++static u32 boot_raw_regs_test = 0; ++module_param(boot_raw_regs_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_regs_test, "Enable gathering boot time entropy of the first interrupt register entropy events"); ++ ++static struct lrng_testing lrng_raw_regs = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_regs.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_regs.read_wait) ++}; ++ ++bool lrng_raw_regs_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_regs, value, &boot_raw_regs_test); ++} ++ ++static int lrng_raw_regs_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_regs, &boot_raw_regs_test, ++ outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_regs_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_regs_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_regs_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_regs_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */ ++ ++/********************** Raw Entropy Array Data Handling ***********************/ ++ ++#ifdef CONFIG_LRNG_RAW_ARRAY ++ ++static u32 boot_raw_array = 0; ++module_param(boot_raw_array, uint, 0644); ++MODULE_PARM_DESC(boot_raw_array, "Enable gathering boot time raw noise array data of the first entropy events"); ++ ++static struct lrng_testing lrng_raw_array = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_array.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_array.read_wait) ++}; ++ ++bool lrng_raw_array_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_array, value, &boot_raw_array); ++} ++ ++static int lrng_raw_array_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_array, &boot_raw_array, outbuf, ++ outbuflen); ++} ++ ++static ssize_t lrng_raw_array_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_array_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_array_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_array_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_ARRAY */ ++ ++/******************** Interrupt Performance Data Handling *********************/ ++ ++#ifdef CONFIG_LRNG_IRQ_PERF ++ ++static u32 boot_irq_perf = 0; ++module_param(boot_irq_perf, uint, 0644); ++MODULE_PARM_DESC(boot_irq_perf, "Enable gathering interrupt entropy source performance data"); ++ ++static struct lrng_testing lrng_irq_perf = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_irq_perf.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_irq_perf.read_wait) ++}; ++ ++bool lrng_perf_time(u32 start) ++{ ++ return lrng_testing_store(&lrng_irq_perf, random_get_entropy() - start, ++ &boot_irq_perf); ++} ++ ++static int lrng_irq_perf_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_irq_perf, &boot_irq_perf, outbuf, ++ outbuflen); ++} ++ ++static ssize_t lrng_irq_perf_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_irq_perf_reader); ++} ++ ++static const struct file_operations lrng_irq_perf_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_irq_perf_read, ++}; ++ ++#endif /* CONFIG_LRNG_IRQ_PERF */ ++ ++/****** Raw High-Resolution Scheduler-based Timer Entropy Data Handling *******/ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY ++ ++static u32 boot_raw_sched_hires_test = 0; ++module_param(boot_raw_sched_hires_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_sched_hires_test, "Enable gathering boot time high resolution timer entropy of the first Scheduler-based entropy events"); ++ ++static struct lrng_testing lrng_raw_sched_hires = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_hires.lock), ++ .read_wait = ++ __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_hires.read_wait) ++}; ++ ++bool lrng_raw_sched_hires_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_sched_hires, value, ++ &boot_raw_sched_hires_test); ++} ++ ++static int lrng_raw_sched_hires_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_sched_hires, ++ &boot_raw_sched_hires_test, ++ outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_sched_hires_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_sched_hires_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_sched_hires_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_sched_hires_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY */ ++ ++/******************** Interrupt Performance Data Handling *********************/ ++ ++#ifdef CONFIG_LRNG_SCHED_PERF ++ ++static u32 boot_sched_perf = 0; ++module_param(boot_sched_perf, uint, 0644); ++MODULE_PARM_DESC(boot_sched_perf, "Enable gathering scheduler-based entropy source performance data"); ++ ++static struct lrng_testing lrng_sched_perf = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_sched_perf.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_sched_perf.read_wait) ++}; ++ ++bool lrng_sched_perf_time(u32 start) ++{ ++ return lrng_testing_store(&lrng_sched_perf, random_get_entropy() - start, ++ &boot_sched_perf); ++} ++ ++static int lrng_sched_perf_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_sched_perf, &boot_sched_perf, outbuf, ++ outbuflen); ++} ++ ++static ssize_t lrng_sched_perf_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_sched_perf_reader); ++} ++ ++static const struct file_operations lrng_sched_perf_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_sched_perf_read, ++}; ++ ++#endif /* CONFIG_LRNG_SCHED_PERF */ ++ ++/*************** Raw Scheduler task_struct->pid Data Handling *****************/ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY ++ ++static u32 boot_raw_sched_pid_test = 0; ++module_param(boot_raw_sched_pid_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_sched_pid_test, "Enable gathering boot time entropy of the first PIDs collected by the scheduler entropy source"); ++ ++static struct lrng_testing lrng_raw_sched_pid = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_pid.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_pid.read_wait) ++}; ++ ++bool lrng_raw_sched_pid_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_sched_pid, value, ++ &boot_raw_sched_pid_test); ++} ++ ++static int lrng_raw_sched_pid_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_sched_pid, ++ &boot_raw_sched_pid_test, outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_sched_pid_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_sched_pid_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_sched_pid_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_sched_pid_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_SCHED_PID_ENTROPY */ ++ ++ ++/*********** Raw Scheduler task_struct->start_time Data Handling **************/ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY ++ ++static u32 boot_raw_sched_starttime_test = 0; ++module_param(boot_raw_sched_starttime_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_sched_starttime_test, "Enable gathering boot time entropy of the first task start times collected by the scheduler entropy source"); ++ ++static struct lrng_testing lrng_raw_sched_starttime = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_starttime.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_starttime.read_wait) ++}; ++ ++bool lrng_raw_sched_starttime_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_sched_starttime, value, ++ &boot_raw_sched_starttime_test); ++} ++ ++static int lrng_raw_sched_starttime_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_sched_starttime, ++ &boot_raw_sched_starttime_test, outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_sched_starttime_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_sched_starttime_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_sched_starttime_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_sched_starttime_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY */ ++ ++/************** Raw Scheduler task_struct->nvcsw Data Handling ****************/ ++ ++#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY ++ ++static u32 boot_raw_sched_nvcsw_test = 0; ++module_param(boot_raw_sched_nvcsw_test, uint, 0644); ++MODULE_PARM_DESC(boot_raw_sched_nvcsw_test, "Enable gathering boot time entropy of the first task context switch numbers collected by the scheduler entropy source"); ++ ++static struct lrng_testing lrng_raw_sched_nvcsw = { ++ .rb_reader = 0, ++ .rb_writer = ATOMIC_INIT(0), ++ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_nvcsw.lock), ++ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_nvcsw.read_wait) ++}; ++ ++bool lrng_raw_sched_nvcsw_entropy_store(u32 value) ++{ ++ return lrng_testing_store(&lrng_raw_sched_nvcsw, value, ++ &boot_raw_sched_nvcsw_test); ++} ++ ++static int lrng_raw_sched_nvcsw_entropy_reader(u8 *outbuf, u32 outbuflen) ++{ ++ return lrng_testing_reader(&lrng_raw_sched_nvcsw, ++ &boot_raw_sched_nvcsw_test, outbuf, outbuflen); ++} ++ ++static ssize_t lrng_raw_sched_nvcsw_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_testing_extract_user(file, to, count, ppos, ++ lrng_raw_sched_nvcsw_entropy_reader); ++} ++ ++static const struct file_operations lrng_raw_sched_nvcsw_fops = { ++ .owner = THIS_MODULE, ++ .read = lrng_raw_sched_nvcsw_read, ++}; ++ ++#endif /* CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY */ ++ ++/*********************************** ACVT ************************************/ ++ ++#ifdef CONFIG_LRNG_ACVT_HASH ++ ++/* maximum amount of data to be hashed as defined by ACVP */ ++#define LRNG_ACVT_MAX_SHA_MSG (65536 >> 3) ++ ++/* ++ * As we use static variables to store the data, it is clear that the ++ * test interface is only able to handle single threaded testing. This is ++ * considered to be sufficient for testing. If multi-threaded use of the ++ * ACVT test interface would be performed, the caller would get garbage ++ * but the kernel operation is unaffected by this. ++ */ ++static u8 lrng_acvt_hash_data[LRNG_ACVT_MAX_SHA_MSG] ++ __aligned(LRNG_KCAPI_ALIGN); ++static atomic_t lrng_acvt_hash_data_size = ATOMIC_INIT(0); ++static u8 lrng_acvt_hash_digest[LRNG_ATOMIC_DIGEST_SIZE]; ++ ++static ssize_t lrng_acvt_hash_write(struct file *file, const char __user *buf, ++ size_t nbytes, loff_t *ppos) ++{ ++ if (nbytes > LRNG_ACVT_MAX_SHA_MSG) ++ return -EINVAL; ++ ++ atomic_set(&lrng_acvt_hash_data_size, (int)nbytes); ++ ++ return simple_write_to_buffer(lrng_acvt_hash_data, ++ LRNG_ACVT_MAX_SHA_MSG, ppos, buf, nbytes); ++} ++ ++static ssize_t lrng_acvt_hash_read(struct file *file, char __user *to, ++ size_t count, loff_t *ppos) ++{ ++ SHASH_DESC_ON_STACK(shash, NULL); ++ const struct lrng_hash_cb *hash_cb = &lrng_sha_hash_cb; ++ ssize_t ret; ++ ++ if (count > LRNG_ATOMIC_DIGEST_SIZE) ++ return -EINVAL; ++ ++ ret = hash_cb->hash_init(shash, NULL) ?: ++ hash_cb->hash_update(shash, lrng_acvt_hash_data, ++ atomic_read_u32(&lrng_acvt_hash_data_size)) ?: ++ hash_cb->hash_final(shash, lrng_acvt_hash_digest); ++ if (ret) ++ return ret; ++ ++ return simple_read_from_buffer(to, count, ppos, lrng_acvt_hash_digest, ++ sizeof(lrng_acvt_hash_digest)); ++} ++ ++static const struct file_operations lrng_acvt_hash_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .llseek = default_llseek, ++ .read = lrng_acvt_hash_read, ++ .write = lrng_acvt_hash_write, ++}; ++ ++#endif /* CONFIG_LRNG_ACVT_DRNG */ ++ ++/************************************************************************** ++ * Debugfs interface ++ **************************************************************************/ ++ ++static int __init lrng_raw_init(void) ++{ ++ struct dentry *lrng_raw_debugfs_root; ++ ++ lrng_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); ++ ++#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_hires", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_hires_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_jiffies", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_jiffies_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_irq", 0400, lrng_raw_debugfs_root, ++ NULL, &lrng_raw_irq_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_retip", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_retip_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_regs", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_regs_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_ARRAY ++ debugfs_create_file_unsafe("lrng_raw_array", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_array_fops); ++#endif ++#ifdef CONFIG_LRNG_IRQ_PERF ++ debugfs_create_file_unsafe("lrng_irq_perf", 0400, lrng_raw_debugfs_root, ++ NULL, &lrng_irq_perf_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_sched_hires", 0400, ++ lrng_raw_debugfs_root, ++ NULL, &lrng_raw_sched_hires_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_sched_pid", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_sched_pid_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_sched_starttime", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_sched_starttime_fops); ++#endif ++#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY ++ debugfs_create_file_unsafe("lrng_raw_sched_nvcsw", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_raw_sched_nvcsw_fops); ++#endif ++#ifdef CONFIG_LRNG_SCHED_PERF ++ debugfs_create_file_unsafe("lrng_sched_perf", 0400, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_sched_perf_fops); ++#endif ++#ifdef CONFIG_LRNG_ACVT_HASH ++ debugfs_create_file_unsafe("lrng_acvt_hash", 0600, ++ lrng_raw_debugfs_root, NULL, ++ &lrng_acvt_hash_fops); ++#endif ++ ++ return 0; ++} ++ ++module_init(lrng_raw_init); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch new file mode 100644 index 000000000..c2cec9681 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch @@ -0,0 +1,523 @@ +From 6c02564f6cdabbb5a463e0b10438d61a055e93d9 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 18:13:56 +0200 +Subject: [PATCH 20/25] LRNG - add power-on and runtime self-tests + +Parts of the LRNG are already covered by self-tests, including: + +* Self-test of SP800-90A DRBG provided by the Linux kernel crypto API. + +* Self-test of the PRNG provided by the Linux kernel crypto API. + +* Raw noise source data testing including SP800-90B compliant + tests when enabling CONFIG_LRNG_HEALTH_TESTS + +This patch adds the self-tests for the remaining critical functions of +the LRNG that are essential to maintain entropy and provide +cryptographic strong random numbers. The following self-tests are +implemented: + +* Self-test of the time array maintenance. This test verifies whether +the time stamp array management to store multiple values in one integer +implements a concatenation of the data. + +* Self-test of the software hash implementation ensures that this +function operates compliant to the FIPS 180-4 specification. The +self-test performs a hash operation of a zeroized per-CPU data array. + +* Self-test of the ChaCha20 DRNG is based on the self-tests that are +already present and implemented with the stand-alone user space +ChaCha20 DRNG implementation available at [1]. The self-tests cover +different use cases of the DRNG seeded with known seed data. + +The status of the LRNG self-tests is provided with the selftest_status +SysFS file. If the file contains a zero, the self-tests passed. The +value 0xffffffff means that the self-tests were not executed. Any other +value indicates a self-test failure. + +The self-test may be compiled to panic the system if the self-test +fails. + +All self-tests operate on private state data structures. This implies +that none of the self-tests have any impact on the regular LRNG +operations. This allows the self-tests to be repeated at runtime by +writing anything into the selftest_status SysFS file. + +[1] https://www.chronox.de/chacha20.html + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 52 ++-- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_selftest.c | 397 ++++++++++++++++++++++++++++++ + 3 files changed, 424 insertions(+), 26 deletions(-) + create mode 100644 drivers/char/lrng/lrng_selftest.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -985,32 +985,32 @@ config LRNG_TEST_CPU_ES_COMPRESSION + than what may be required. + + endif #LRNG_TESTING_MENU +-# +-# config LRNG_SELFTEST +-# bool "Enable power-on and on-demand self-tests" +-# help +-# The power-on self-tests are executed during boot time +-# covering the ChaCha20 DRNG, the hash operation used for +-# processing the entropy pools and the auxiliary pool, and +-# the time stamp management of the LRNG. +-# +-# The on-demand self-tests are triggered by writing any +-# value into the SysFS file selftest_status. At the same +-# time, when reading this file, the test status is +-# returned. A zero indicates that all tests were executed +-# successfully. +-# +-# If unsure, say Y. +-# +-# if LRNG_SELFTEST +-# +-# config LRNG_SELFTEST_PANIC +-# bool "Panic the kernel upon self-test failure" +-# help +-# If the option is enabled, the kernel is terminated if an +-# LRNG power-on self-test failure is detected. +-# +-# endif # LRNG_SELFTEST ++ ++config LRNG_SELFTEST ++ bool "Enable power-on and on-demand self-tests" ++ help ++ The power-on self-tests are executed during boot time ++ covering the ChaCha20 DRNG, the hash operation used for ++ processing the entropy pools and the auxiliary pool, and ++ the time stamp management of the LRNG. ++ ++ The on-demand self-tests are triggered by writing any ++ value into the SysFS file selftest_status. At the same ++ time, when reading this file, the test status is ++ returned. A zero indicates that all tests were executed ++ successfully. ++ ++ If unsure, say Y. ++ ++if LRNG_SELFTEST ++ ++config LRNG_SELFTEST_PANIC ++ bool "Panic the kernel upon self-test failure" ++ help ++ If the option is enabled, the kernel is terminated if an ++ LRNG power-on self-test failure is detected. ++ ++endif # LRNG_SELFTEST + + endif # LRNG + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -27,3 +27,4 @@ obj-$(CONFIG_LRNG_JENT) += lrng_es_jen + + obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o + obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o ++obj-$(CONFIG_LRNG_SELFTEST) += lrng_selftest.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_selftest.c +@@ -0,0 +1,397 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG power-on and on-demand self-test ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++/* ++ * In addition to the self-tests below, the following LRNG components ++ * are covered with self-tests during regular operation: ++ * ++ * * power-on self-test: SP800-90A DRBG provided by the Linux kernel crypto API ++ * * power-on self-test: PRNG provided by the Linux kernel crypto API ++ * * runtime test: Raw noise source data testing including SP800-90B compliant ++ * tests when enabling CONFIG_LRNG_HEALTH_TESTS ++ * ++ * Additional developer tests present with LRNG code: ++ * * SP800-90B APT and RCT test enforcement validation when enabling ++ * CONFIG_LRNG_APT_BROKEN or CONFIG_LRNG_RCT_BROKEN. ++ * * Collection of raw entropy from the interrupt noise source when enabling ++ * CONFIG_LRNG_TESTING and pulling the data from the kernel with the provided ++ * interface. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++ ++#include "lrng_drng_chacha20.h" ++#include "lrng_sha.h" ++ ++#define LRNG_SELFTEST_PASSED 0 ++#define LRNG_SEFLTEST_ERROR_TIME (1 << 0) ++#define LRNG_SEFLTEST_ERROR_CHACHA20 (1 << 1) ++#define LRNG_SEFLTEST_ERROR_HASH (1 << 2) ++#define LRNG_SEFLTEST_ERROR_GCD (1 << 3) ++#define LRNG_SELFTEST_NOT_EXECUTED 0xffffffff ++ ++#ifdef CONFIG_LRNG_TIMER_COMMON ++ ++#include "lrng_es_timer_common.h" ++ ++static u32 lrng_data_selftest_ptr = 0; ++static u32 lrng_data_selftest[LRNG_DATA_ARRAY_SIZE]; ++ ++static void lrng_data_process_selftest_insert(u32 time) ++{ ++ u32 ptr = lrng_data_selftest_ptr++ & LRNG_DATA_WORD_MASK; ++ unsigned int array = lrng_data_idx2array(ptr); ++ unsigned int slot = lrng_data_idx2slot(ptr); ++ ++ /* zeroization of slot to ensure the following OR adds the data */ ++ lrng_data_selftest[array] &= ++ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK, ++ slot)); ++ lrng_data_selftest[array] |= ++ lrng_data_slot_val(time & LRNG_DATA_SLOTSIZE_MASK, slot); ++} ++ ++static void lrng_data_process_selftest_u32(u32 data) ++{ ++ u32 pre_ptr, ptr, mask; ++ unsigned int pre_array; ++ ++ /* Increment pointer by number of slots taken for input value */ ++ lrng_data_selftest_ptr += LRNG_DATA_SLOTS_PER_UINT; ++ ++ /* ptr to current unit */ ++ ptr = lrng_data_selftest_ptr; ++ ++ lrng_data_split_u32(&ptr, &pre_ptr, &mask); ++ ++ /* MSB of data go into previous unit */ ++ pre_array = lrng_data_idx2array(pre_ptr); ++ /* zeroization of slot to ensure the following OR adds the data */ ++ lrng_data_selftest[pre_array] &= ~(0xffffffff & ~mask); ++ lrng_data_selftest[pre_array] |= data & ~mask; ++ ++ /* LSB of data go into current unit */ ++ lrng_data_selftest[lrng_data_idx2array(ptr)] = data & mask; ++} ++ ++static unsigned int lrng_data_process_selftest(void) ++{ ++ u32 time; ++ u32 idx_zero_compare = (0 << 0) | (1 << 8) | (2 << 16) | (3 << 24); ++ u32 idx_one_compare = (4 << 0) | (5 << 8) | (6 << 16) | (7 << 24); ++ u32 idx_last_compare = ++ (((LRNG_DATA_NUM_VALUES - 4) & LRNG_DATA_SLOTSIZE_MASK) << 0) | ++ (((LRNG_DATA_NUM_VALUES - 3) & LRNG_DATA_SLOTSIZE_MASK) << 8) | ++ (((LRNG_DATA_NUM_VALUES - 2) & LRNG_DATA_SLOTSIZE_MASK) << 16) | ++ (((LRNG_DATA_NUM_VALUES - 1) & LRNG_DATA_SLOTSIZE_MASK) << 24); ++ ++ (void)idx_one_compare; ++ ++ /* "poison" the array to verify the operation of the zeroization */ ++ lrng_data_selftest[0] = 0xffffffff; ++ lrng_data_selftest[1] = 0xffffffff; ++ ++ lrng_data_process_selftest_insert(0); ++ /* ++ * Note, when using lrng_data_process_u32() on unaligned ptr, ++ * the first slots will go into next word, and the last slots go ++ * into the previous word. ++ */ ++ lrng_data_process_selftest_u32((4 << 0) | (1 << 8) | (2 << 16) | ++ (3 << 24)); ++ lrng_data_process_selftest_insert(5); ++ lrng_data_process_selftest_insert(6); ++ lrng_data_process_selftest_insert(7); ++ ++ if ((lrng_data_selftest[0] != idx_zero_compare) || ++ (lrng_data_selftest[1] != idx_one_compare)) ++ goto err; ++ ++ /* Reset for next test */ ++ lrng_data_selftest[0] = 0; ++ lrng_data_selftest[1] = 0; ++ lrng_data_selftest_ptr = 0; ++ ++ for (time = 0; time < LRNG_DATA_NUM_VALUES; time++) ++ lrng_data_process_selftest_insert(time); ++ ++ if ((lrng_data_selftest[0] != idx_zero_compare) || ++ (lrng_data_selftest[1] != idx_one_compare) || ++ (lrng_data_selftest[LRNG_DATA_ARRAY_SIZE - 1] != idx_last_compare)) ++ goto err; ++ ++ return LRNG_SELFTEST_PASSED; ++ ++err: ++ pr_err("LRNG data array self-test FAILED\n"); ++ return LRNG_SEFLTEST_ERROR_TIME; ++} ++ ++static unsigned int lrng_gcd_selftest(void) ++{ ++ u32 history[10]; ++ unsigned int i; ++ ++#define LRNG_GCD_SELFTEST 3 ++ for (i = 0; i < ARRAY_SIZE(history); i++) ++ history[i] = i * LRNG_GCD_SELFTEST; ++ ++ if (lrng_gcd_analyze(history, ARRAY_SIZE(history)) == LRNG_GCD_SELFTEST) ++ return LRNG_SELFTEST_PASSED; ++ ++ pr_err("LRNG GCD self-test FAILED\n"); ++ return LRNG_SEFLTEST_ERROR_GCD; ++} ++ ++#else /* CONFIG_LRNG_TIMER_COMMON */ ++ ++static unsigned int lrng_data_process_selftest(void) ++{ ++ return LRNG_SELFTEST_PASSED; ++} ++ ++static unsigned int lrng_gcd_selftest(void) ++{ ++ return LRNG_SELFTEST_PASSED; ++} ++ ++#endif /* CONFIG_LRNG_TIMER_COMMON */ ++ ++/* The test vectors are taken from crypto/testmgr.h */ ++static unsigned int lrng_hash_selftest(void) ++{ ++ SHASH_DESC_ON_STACK(shash, NULL); ++ const struct lrng_hash_cb *hash_cb = &lrng_sha_hash_cb; ++ static const u8 lrng_hash_selftest_result[] = ++#ifdef CONFIG_CRYPTO_LIB_SHA256 ++ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, ++ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, ++ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, ++ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }; ++#else /* CONFIG_CRYPTO_LIB_SHA256 */ ++ { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, ++ 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d }; ++#endif /* CONFIG_CRYPTO_LIB_SHA256 */ ++ static const u8 hash_input[] = { 0x61, 0x62, 0x63 }; /* "abc" */ ++ u8 digest[sizeof(lrng_hash_selftest_result)] __aligned(sizeof(u32)); ++ ++ if (sizeof(digest) != hash_cb->hash_digestsize(NULL)) ++ return LRNG_SEFLTEST_ERROR_HASH; ++ ++ if (!hash_cb->hash_init(shash, NULL) && ++ !hash_cb->hash_update(shash, hash_input, ++ sizeof(hash_input)) && ++ !hash_cb->hash_final(shash, digest) && ++ !memcmp(digest, lrng_hash_selftest_result, sizeof(digest))) ++ return 0; ++ ++ pr_err("LRNG %s Hash self-test FAILED\n", hash_cb->hash_name()); ++ return LRNG_SEFLTEST_ERROR_HASH; ++} ++ ++#ifdef CONFIG_LRNG_DRNG_CHACHA20 ++ ++static void lrng_selftest_bswap32(u32 *ptr, u32 words) ++{ ++ u32 i; ++ ++ /* Byte-swap data which is an LE representation */ ++ for (i = 0; i < words; i++) { ++ __le32 *p = (__le32 *)ptr; ++ ++ *p = cpu_to_le32(*ptr); ++ ptr++; ++ } ++} ++ ++/* ++ * The test vectors were generated using the ChaCha20 DRNG from ++ * https://www.chronox.de/chacha20.html ++ */ ++static unsigned int lrng_chacha20_drng_selftest(void) ++{ ++ const struct lrng_drng_cb *drng_cb = &lrng_cc20_drng_cb; ++ u8 seed[CHACHA_KEY_SIZE * 2] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ++ }; ++ struct chacha20_block chacha20; ++ int ret; ++ u8 outbuf[CHACHA_KEY_SIZE * 2] __aligned(sizeof(u32)); ++ ++ /* ++ * Expected result when ChaCha20 DRNG state is zero: ++ * * constants are set to "expand 32-byte k" ++ * * remaining state is 0 ++ * and pulling one half ChaCha20 DRNG block. ++ */ ++ static const u8 expected_halfblock[CHACHA_KEY_SIZE] = { ++ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, ++ 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, ++ 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, ++ 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7 }; ++ ++ /* ++ * Expected result when ChaCha20 DRNG state is zero: ++ * * constants are set to "expand 32-byte k" ++ * * remaining state is 0 ++ * followed by a reseed with two keyblocks ++ * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ * 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ * 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ * 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ * 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f ++ * and pulling one ChaCha20 DRNG block. ++ */ ++ static const u8 expected_oneblock[CHACHA_KEY_SIZE * 2] = { ++ 0xe3, 0xb0, 0x8a, 0xcc, 0x34, 0xc3, 0x17, 0x0e, ++ 0xc3, 0xd8, 0xc3, 0x40, 0xe7, 0x73, 0xe9, 0x0d, ++ 0xd1, 0x62, 0xa3, 0x5d, 0x7d, 0xf2, 0xf1, 0x4a, ++ 0x24, 0x42, 0xb7, 0x1e, 0xb0, 0x05, 0x17, 0x07, ++ 0xb9, 0x35, 0x10, 0x69, 0x8b, 0x46, 0xfb, 0x51, ++ 0xe9, 0x91, 0x3f, 0x46, 0xf2, 0x4d, 0xea, 0xd0, ++ 0x81, 0xc1, 0x1b, 0xa9, 0x5d, 0x52, 0x91, 0x5f, ++ 0xcd, 0xdc, 0xc6, 0xd6, 0xc3, 0x7c, 0x50, 0x23 }; ++ ++ /* ++ * Expected result when ChaCha20 DRNG state is zero: ++ * * constants are set to "expand 32-byte k" ++ * * remaining state is 0 ++ * followed by a reseed with one key block plus one byte ++ * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ * 0x20 ++ * and pulling less than one ChaCha20 DRNG block. ++ */ ++ static const u8 expected_block_nonalinged[CHACHA_KEY_SIZE + 4] = { ++ 0x9c, 0xfc, 0x5e, 0x31, 0x21, 0x62, 0x11, 0x85, ++ 0xd3, 0x77, 0xd3, 0x69, 0x0f, 0xa8, 0x16, 0x55, ++ 0xb4, 0x4c, 0xf6, 0x52, 0xf3, 0xa8, 0x37, 0x99, ++ 0x38, 0x76, 0xa0, 0x66, 0xec, 0xbb, 0xce, 0xa9, ++ 0x9c, 0x95, 0xa1, 0xfd }; ++ ++ BUILD_BUG_ON(sizeof(seed) % sizeof(u32)); ++ ++ memset(&chacha20, 0, sizeof(chacha20)); ++ lrng_cc20_init_rfc7539(&chacha20); ++ lrng_selftest_bswap32((u32 *)seed, sizeof(seed) / sizeof(u32)); ++ ++ /* Generate with zero state */ ++ ret = drng_cb->drng_generate(&chacha20, outbuf, ++ sizeof(expected_halfblock)); ++ if (ret != sizeof(expected_halfblock)) ++ goto err; ++ if (memcmp(outbuf, expected_halfblock, sizeof(expected_halfblock))) ++ goto err; ++ ++ /* Clear state of DRNG */ ++ memset(&chacha20.key.u[0], 0, 48); ++ ++ /* Reseed with 2 key blocks */ ++ ret = drng_cb->drng_seed(&chacha20, seed, sizeof(expected_oneblock)); ++ if (ret < 0) ++ goto err; ++ ret = drng_cb->drng_generate(&chacha20, outbuf, ++ sizeof(expected_oneblock)); ++ if (ret != sizeof(expected_oneblock)) ++ goto err; ++ if (memcmp(outbuf, expected_oneblock, sizeof(expected_oneblock))) ++ goto err; ++ ++ /* Clear state of DRNG */ ++ memset(&chacha20.key.u[0], 0, 48); ++ ++ /* Reseed with 1 key block and one byte */ ++ ret = drng_cb->drng_seed(&chacha20, seed, ++ sizeof(expected_block_nonalinged)); ++ if (ret < 0) ++ goto err; ++ ret = drng_cb->drng_generate(&chacha20, outbuf, ++ sizeof(expected_block_nonalinged)); ++ if (ret != sizeof(expected_block_nonalinged)) ++ goto err; ++ if (memcmp(outbuf, expected_block_nonalinged, ++ sizeof(expected_block_nonalinged))) ++ goto err; ++ ++ return LRNG_SELFTEST_PASSED; ++ ++err: ++ pr_err("LRNG ChaCha20 DRNG self-test FAILED\n"); ++ return LRNG_SEFLTEST_ERROR_CHACHA20; ++} ++ ++#else /* CONFIG_LRNG_DRNG_CHACHA20 */ ++ ++static unsigned int lrng_chacha20_drng_selftest(void) ++{ ++ return LRNG_SELFTEST_PASSED; ++} ++ ++#endif /* CONFIG_LRNG_DRNG_CHACHA20 */ ++ ++static unsigned int lrng_selftest_status = LRNG_SELFTEST_NOT_EXECUTED; ++ ++static int lrng_selftest(void) ++{ ++ unsigned int ret = lrng_data_process_selftest(); ++ ++ ret |= lrng_chacha20_drng_selftest(); ++ ret |= lrng_hash_selftest(); ++ ret |= lrng_gcd_selftest(); ++ ++ if (ret) { ++ if (IS_ENABLED(CONFIG_LRNG_SELFTEST_PANIC)) ++ panic("LRNG self-tests failed: %u\n", ret); ++ } else { ++ pr_info("LRNG self-tests passed\n"); ++ } ++ ++ lrng_selftest_status = ret; ++ ++ if (lrng_selftest_status) ++ return -EFAULT; ++ return 0; ++} ++ ++#ifdef CONFIG_SYSFS ++/* Re-perform self-test when any value is written to the sysfs file. */ ++static int lrng_selftest_sysfs_set(const char *val, ++ const struct kernel_param *kp) ++{ ++ return lrng_selftest(); ++} ++ ++static const struct kernel_param_ops lrng_selftest_sysfs = { ++ .set = lrng_selftest_sysfs_set, ++ .get = param_get_uint, ++}; ++module_param_cb(selftest_status, &lrng_selftest_sysfs, &lrng_selftest_status, ++ 0644); ++#endif /* CONFIG_SYSFS */ ++ ++static int __init lrng_selftest_init(void) ++{ ++ return lrng_selftest(); ++} ++ ++module_init(lrng_selftest_init); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch new file mode 100644 index 000000000..79889edf3 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch @@ -0,0 +1,174 @@ +From 6a5b2149c0ba1f6a04ae69368e5fbed2b38bff96 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 31 Jul 2022 22:34:51 +0200 +Subject: [PATCH 21/25] LRNG - sysctls and /proc interface + +The LRNG sysctl interface provides the same controls as the existing +/dev/random implementation. These sysctls behave identically and are +implemented identically. The goal is to allow a possible merge of the +existing /dev/random implementation with this implementation which +implies that this patch tries have a very close similarity. Yet, all +sysctls are documented at [1]. + +The sysctl implementation is only enabled if the existing random.c file +is not compiled. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_sysctl.c | 139 ++++++++++++++++++++++++++++++++ + 2 files changed, 140 insertions(+) + create mode 100644 drivers/char/lrng/lrng_sysctl.c + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -9,6 +9,7 @@ obj-$(CONFIG_LRNG_SHA256) += lrng_sha25 + obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o + + obj-$(CONFIG_SYSCTL) += lrng_proc.o ++obj-$(CONFIG_LRNG_SYSCTL) += lrng_sysctl.o + obj-$(CONFIG_NUMA) += lrng_numa.o + + obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_sysctl.c +@@ -0,0 +1,139 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG sysctl interfaces ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "lrng_drng_mgr.h" ++#include "lrng_es_mgr.h" ++#include "lrng_sysctl.h" ++ ++/* ++ * This function is used to return both the bootid UUID, and random ++ * UUID. The difference is in whether table->data is NULL; if it is, ++ * then a new UUID is generated and returned to the user. ++ * ++ * If the user accesses this via the proc interface, the UUID will be ++ * returned as an ASCII string in the standard UUID format; if via the ++ * sysctl system call, as 16 bytes of binary data. ++ */ ++static int lrng_sysctl_do_uuid(const struct ctl_table *table, int write, ++ void *buffer, size_t *lenp, loff_t *ppos) ++{ ++ struct ctl_table fake_table; ++ unsigned char buf[64], tmp_uuid[16], *uuid; ++ ++ uuid = table->data; ++ if (!uuid) { ++ uuid = tmp_uuid; ++ generate_random_uuid(uuid); ++ } else { ++ static DEFINE_SPINLOCK(bootid_spinlock); ++ ++ spin_lock(&bootid_spinlock); ++ if (!uuid[8]) ++ generate_random_uuid(uuid); ++ spin_unlock(&bootid_spinlock); ++ } ++ ++ sprintf(buf, "%pU", uuid); ++ ++ fake_table.data = buf; ++ fake_table.maxlen = sizeof(buf); ++ ++ return proc_dostring(&fake_table, write, buffer, lenp, ppos); ++} ++ ++static int lrng_sysctl_do_entropy(const struct ctl_table *table, int write, ++ void *buffer, size_t *lenp, loff_t *ppos) ++{ ++ struct ctl_table fake_table; ++ int entropy_count = lrng_avail_entropy_aux(); ++ ++ fake_table.data = &entropy_count; ++ fake_table.maxlen = sizeof(entropy_count); ++ ++ return proc_dointvec(&fake_table, write, buffer, lenp, ppos); ++} ++ ++static int lrng_sysctl_do_poolsize(const struct ctl_table *table, int write, ++ void *buffer, size_t *lenp, loff_t *ppos) ++{ ++ struct ctl_table fake_table; ++ u32 entropy_count = lrng_es[lrng_ext_es_aux]->max_entropy(); ++ ++ fake_table.data = &entropy_count; ++ fake_table.maxlen = sizeof(entropy_count); ++ ++ return proc_dointvec(&fake_table, write, buffer, lenp, ppos); ++} ++ ++static int lrng_min_write_thresh; ++static int lrng_max_write_thresh = (LRNG_WRITE_WAKEUP_ENTROPY << 3); ++static char lrng_sysctl_bootid[16]; ++static int lrng_drng_reseed_max_min; ++ ++void lrng_sysctl_update_max_write_thresh(u32 new_digestsize) ++{ ++ lrng_max_write_thresh = (int)new_digestsize; ++ /* Ensure that changes to the global variable are visible */ ++ mb(); ++} ++ ++static struct ctl_table random_table[] = { ++ { ++ .procname = "poolsize", ++ .maxlen = sizeof(int), ++ .mode = 0444, ++ .proc_handler = lrng_sysctl_do_poolsize, ++ }, ++ { ++ .procname = "entropy_avail", ++ .maxlen = sizeof(int), ++ .mode = 0444, ++ .proc_handler = lrng_sysctl_do_entropy, ++ }, ++ { ++ .procname = "write_wakeup_threshold", ++ .data = &lrng_write_wakeup_bits, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = &lrng_min_write_thresh, ++ .extra2 = &lrng_max_write_thresh, ++ }, ++ { ++ .procname = "boot_id", ++ .data = &lrng_sysctl_bootid, ++ .maxlen = 16, ++ .mode = 0444, ++ .proc_handler = lrng_sysctl_do_uuid, ++ }, ++ { ++ .procname = "uuid", ++ .maxlen = 16, ++ .mode = 0444, ++ .proc_handler = lrng_sysctl_do_uuid, ++ }, ++ { ++ .procname = "urandom_min_reseed_secs", ++ .data = &lrng_drng_reseed_max_time, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ .extra1 = &lrng_drng_reseed_max_min, ++ }, ++}; ++ ++static int __init random_sysctls_init(void) ++{ ++ register_sysctl_init("kernel/random", random_table); ++ return 0; ++} ++device_initcall(random_sysctls_init); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch new file mode 100644 index 000000000..f059f581d --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch @@ -0,0 +1,938 @@ +From fa6f7a3d77638110f79d1972668afc4b15254ffa Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Mon, 20 Feb 2023 22:12:04 +0100 +Subject: [PATCH 22/25] LRMG - add drop-in replacement random(4) API + +The LRNG is intended to be a full replacement of the existing random.c. +This also includes the providing of a full API and ABI compliant drop-in +replacement of all APIs offered by random.c. + +These LRNG interfaces are compiled when the random.c is not compiled +any more. + +Signed-off-by: Stephan Mueller +--- + drivers/char/Makefile | 3 +- + drivers/char/lrng/Makefile | 5 + + drivers/char/lrng/lrng_interface_aux.c | 210 ++++++++++++ + drivers/char/lrng/lrng_interface_dev_common.c | 315 ++++++++++++++++++ + .../char/lrng/lrng_interface_random_kernel.c | 248 ++++++++++++++ + .../char/lrng/lrng_interface_random_user.c | 104 ++++++ + 6 files changed, 884 insertions(+), 1 deletion(-) + create mode 100644 drivers/char/lrng/lrng_interface_aux.c + create mode 100644 drivers/char/lrng/lrng_interface_dev_common.c + create mode 100644 drivers/char/lrng/lrng_interface_random_kernel.c + create mode 100644 drivers/char/lrng/lrng_interface_random_user.c + +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -3,7 +3,8 @@ + # Makefile for the kernel character device drivers. + # + +-obj-y += mem.o random.o ++obj-y += mem.o ++obj-$(CONFIG_RANDOM_DEFAULT_IMPL) += random.o + obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o + obj-y += misc.o + obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -29,3 +29,8 @@ obj-$(CONFIG_LRNG_JENT) += lrng_es_jen + obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o + obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o + obj-$(CONFIG_LRNG_SELFTEST) += lrng_selftest.o ++ ++obj-$(CONFIG_LRNG_COMMON_DEV_IF) += lrng_interface_dev_common.o ++obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_interface_random_user.o \ ++ lrng_interface_random_kernel.o \ ++ lrng_interface_aux.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_aux.c +@@ -0,0 +1,210 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG auxiliary interfaces ++ * ++ * Copyright (C) 2022 Stephan Mueller ++ * Copyright (C) 2017 Jason A. Donenfeld . All ++ * Rights Reserved. ++ * Copyright (C) 2016 Jason Cooper ++ */ ++ ++#include ++#include ++#include ++ ++#include "lrng_es_mgr.h" ++#include "lrng_interface_random_kernel.h" ++ ++/* ++ * Fill a buffer with random numbers and tokenize it to provide random numbers ++ * to callers in fixed chunks. This approach is provided to be consistent with ++ * the Linux kernel interface requirements. Yet, this approach violate the ++ * backtracking resistance of the random number generator. Thus, the provided ++ * random numbers are not considered to be as strong as those requested directly ++ * from the LRNG. ++ */ ++struct batched_entropy { ++ union { ++ u64 entropy_u64[LRNG_DRNG_BLOCKSIZE / sizeof(u64)]; ++ u32 entropy_u32[LRNG_DRNG_BLOCKSIZE / sizeof(u32)]; ++ u16 entropy_u16[LRNG_DRNG_BLOCKSIZE / sizeof(u16)]; ++ u8 entropy_u8[LRNG_DRNG_BLOCKSIZE / sizeof(u8)]; ++ }; ++ unsigned int position; ++ spinlock_t batch_lock; ++}; ++ ++/* ++ * Get a random word for internal kernel use only. The quality of the random ++ * number is as good as /dev/urandom, but there is no backtrack protection, ++ * with the goal of being quite fast and not depleting entropy. ++ */ ++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = { ++ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock), ++}; ++ ++u64 get_random_u64(void) ++{ ++ u64 ret; ++ unsigned long flags; ++ struct batched_entropy *batch; ++ ++ lrng_debug_report_seedlevel("get_random_u64"); ++ ++ batch = raw_cpu_ptr(&batched_entropy_u64); ++ spin_lock_irqsave(&batch->batch_lock, flags); ++ if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) { ++ lrng_get_random_bytes(batch->entropy_u64, LRNG_DRNG_BLOCKSIZE); ++ batch->position = 0; ++ } ++ ret = batch->entropy_u64[batch->position++]; ++ spin_unlock_irqrestore(&batch->batch_lock, flags); ++ return ret; ++} ++EXPORT_SYMBOL(get_random_u64); ++ ++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32) = { ++ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u32.lock), ++}; ++ ++u32 get_random_u32(void) ++{ ++ u32 ret; ++ unsigned long flags; ++ struct batched_entropy *batch; ++ ++ lrng_debug_report_seedlevel("get_random_u32"); ++ ++ batch = raw_cpu_ptr(&batched_entropy_u32); ++ spin_lock_irqsave(&batch->batch_lock, flags); ++ if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) { ++ lrng_get_random_bytes(batch->entropy_u32, LRNG_DRNG_BLOCKSIZE); ++ batch->position = 0; ++ } ++ ret = batch->entropy_u32[batch->position++]; ++ spin_unlock_irqrestore(&batch->batch_lock, flags); ++ return ret; ++} ++EXPORT_SYMBOL(get_random_u32); ++ ++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u16) = { ++ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u16.lock), ++}; ++ ++u16 get_random_u16(void) ++{ ++ u16 ret; ++ unsigned long flags; ++ struct batched_entropy *batch; ++ ++ lrng_debug_report_seedlevel("get_random_u16"); ++ ++ batch = raw_cpu_ptr(&batched_entropy_u16); ++ spin_lock_irqsave(&batch->batch_lock, flags); ++ if (batch->position % ARRAY_SIZE(batch->entropy_u16) == 0) { ++ lrng_get_random_bytes(batch->entropy_u16, LRNG_DRNG_BLOCKSIZE); ++ batch->position = 0; ++ } ++ ret = batch->entropy_u16[batch->position++]; ++ spin_unlock_irqrestore(&batch->batch_lock, flags); ++ return ret; ++} ++EXPORT_SYMBOL(get_random_u16); ++ ++static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u8) = { ++ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u8.lock), ++}; ++ ++u8 get_random_u8(void) ++{ ++ u8 ret; ++ unsigned long flags; ++ struct batched_entropy *batch; ++ ++ lrng_debug_report_seedlevel("get_random_u8"); ++ ++ batch = raw_cpu_ptr(&batched_entropy_u8); ++ spin_lock_irqsave(&batch->batch_lock, flags); ++ if (batch->position % ARRAY_SIZE(batch->entropy_u8) == 0) { ++ lrng_get_random_bytes(batch->entropy_u8, LRNG_DRNG_BLOCKSIZE); ++ batch->position = 0; ++ } ++ ret = batch->entropy_u8[batch->position++]; ++ spin_unlock_irqrestore(&batch->batch_lock, flags); ++ return ret; ++} ++EXPORT_SYMBOL(get_random_u8); ++ ++/* Taken directly from random.c */ ++u32 __get_random_u32_below(u32 ceil) ++{ ++ u64 mult = (u64)ceil * get_random_u32(); ++ ++ if (unlikely((u32)mult < ceil)) { ++ u32 bound = -ceil % ceil; ++ while (unlikely((u32)mult < bound)) ++ mult = (u64)ceil * get_random_u32(); ++ } ++ return mult >> 32; ++} ++EXPORT_SYMBOL(__get_random_u32_below); ++ ++#ifdef CONFIG_SMP ++/* ++ * This function is called when the CPU is coming up, with entry ++ * CPUHP_RANDOM_PREPARE, which comes before CPUHP_WORKQUEUE_PREP. ++ */ ++int random_prepare_cpu(unsigned int cpu) ++{ ++ /* ++ * When the cpu comes back online, immediately invalidate all batches, ++ * so that we serve fresh randomness. ++ */ ++ per_cpu_ptr(&batched_entropy_u8, cpu)->position = 0; ++ per_cpu_ptr(&batched_entropy_u16, cpu)->position = 0; ++ per_cpu_ptr(&batched_entropy_u32, cpu)->position = 0; ++ per_cpu_ptr(&batched_entropy_u64, cpu)->position = 0; ++ return 0; ++} ++ ++int random_online_cpu(unsigned int cpu) ++{ ++ return 0; ++} ++#endif ++ ++/* ++ * It's important to invalidate all potential batched entropy that might ++ * be stored before the crng is initialized, which we can do lazily by ++ * simply resetting the counter to zero so that it's re-extracted on the ++ * next usage. ++ */ ++void invalidate_batched_entropy(void) ++{ ++ int cpu; ++ unsigned long flags; ++ ++ for_each_possible_cpu(cpu) { ++ struct batched_entropy *batched_entropy; ++ ++ batched_entropy = per_cpu_ptr(&batched_entropy_u8, cpu); ++ spin_lock_irqsave(&batched_entropy->batch_lock, flags); ++ batched_entropy->position = 0; ++ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); ++ ++ batched_entropy = per_cpu_ptr(&batched_entropy_u16, cpu); ++ spin_lock_irqsave(&batched_entropy->batch_lock, flags); ++ batched_entropy->position = 0; ++ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); ++ ++ batched_entropy = per_cpu_ptr(&batched_entropy_u32, cpu); ++ spin_lock_irqsave(&batched_entropy->batch_lock, flags); ++ batched_entropy->position = 0; ++ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); ++ ++ batched_entropy = per_cpu_ptr(&batched_entropy_u64, cpu); ++ spin_lock(&batched_entropy->batch_lock); ++ batched_entropy->position = 0; ++ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); ++ } ++} +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_dev_common.c +@@ -0,0 +1,315 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG User and kernel space interfaces ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++ ++#include "lrng_drng_mgr.h" ++#include "lrng_es_aux.h" ++#include "lrng_es_mgr.h" ++#include "lrng_interface_dev_common.h" ++ ++DECLARE_WAIT_QUEUE_HEAD(lrng_write_wait); ++static struct fasync_struct *fasync; ++ ++static bool lrng_seed_hw = true; /* Allow HW to provide seed */ ++static bool lrng_seed_user = true; /* Allow user space to provide seed */ ++ ++/********************************** Helper ***********************************/ ++ ++static u32 lrng_get_aux_ent(void) ++{ ++ return lrng_es[lrng_ext_es_aux]->curr_entropy(0); ++} ++ ++/* Is the DRNG seed level too low? */ ++bool lrng_need_entropy(void) ++{ ++ return (lrng_get_aux_ent() < lrng_write_wakeup_bits); ++} ++ ++void lrng_writer_wakeup(void) ++{ ++ if (lrng_need_entropy() && wq_has_sleeper(&lrng_write_wait)) { ++ wake_up_interruptible(&lrng_write_wait); ++ kill_fasync(&fasync, SIGIO, POLL_OUT); ++ } ++} ++ ++void lrng_init_wakeup_dev(void) ++{ ++ kill_fasync(&fasync, SIGIO, POLL_IN); ++} ++ ++/* External entropy provider is allowed to provide seed data */ ++bool lrng_state_exseed_allow(enum lrng_external_noise_source source) ++{ ++ if (source == lrng_noise_source_hw) ++ return lrng_seed_hw; ++ return lrng_seed_user; ++} ++ ++/* Enable / disable external entropy provider to furnish seed */ ++void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type) ++{ ++ /* ++ * If the LRNG is not yet operational, allow all entropy sources ++ * to deliver data unconditionally to get fully seeded asap. ++ */ ++ if (!lrng_state_operational()) ++ return; ++ ++ if (source == lrng_noise_source_hw) ++ lrng_seed_hw = type; ++ else ++ lrng_seed_user = type; ++} ++ ++void lrng_state_exseed_allow_all(void) ++{ ++ lrng_state_exseed_set(lrng_noise_source_hw, true); ++ lrng_state_exseed_set(lrng_noise_source_user, true); ++} ++ ++/************************ LRNG user output interfaces *************************/ ++ ++ssize_t lrng_read_seed(char __user *buf, size_t nbytes, unsigned int flags) ++{ ++ ssize_t ret = 0; ++ u64 t[(sizeof(struct entropy_buf) + 3 * sizeof(u64) - 1) / sizeof(u64)]; ++ ++ memset(t, 0, sizeof(t)); ++ ret = lrng_get_seed(t, min_t(size_t, nbytes, sizeof(t)), flags); ++ if (ret == -EMSGSIZE && copy_to_user(buf, t, sizeof(u64))) ++ ret = -EFAULT; ++ else if (ret > 0 && copy_to_user(buf, t, ret)) ++ ret = -EFAULT; ++ ++ memzero_explicit(t, sizeof(t)); ++ ++ return ret; ++} ++ ++ssize_t lrng_read_common(char __user *buf, size_t nbytes, bool pr) ++{ ++ ssize_t ret = 0; ++ u8 tmpbuf[LRNG_DRNG_BLOCKSIZE] __aligned(LRNG_KCAPI_ALIGN); ++ u8 *tmp_large = NULL, *tmp = tmpbuf; ++ u32 tmplen = sizeof(tmpbuf); ++ ++ if (nbytes == 0) ++ return 0; ++ ++ /* ++ * Satisfy large read requests -- as the common case are smaller ++ * request sizes, such as 16 or 32 bytes, avoid a kmalloc overhead for ++ * those by using the stack variable of tmpbuf. ++ */ ++ if (!IS_ENABLED(CONFIG_BASE_SMALL) && (nbytes > sizeof(tmpbuf))) { ++ tmplen = min_t(u32, nbytes, LRNG_DRNG_MAX_REQSIZE); ++ tmp_large = kmalloc(tmplen + LRNG_KCAPI_ALIGN, GFP_KERNEL); ++ if (!tmp_large) ++ tmplen = sizeof(tmpbuf); ++ else ++ tmp = PTR_ALIGN(tmp_large, LRNG_KCAPI_ALIGN); ++ } ++ ++ while (nbytes) { ++ u32 todo = min_t(u32, nbytes, tmplen); ++ int rc = 0; ++ ++ /* Reschedule if we received a large request. */ ++ if ((tmp_large) && need_resched()) { ++ if (signal_pending(current)) { ++ if (ret == 0) ++ ret = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } ++ ++ rc = lrng_drng_get_sleep(tmp, todo, pr); ++ if (rc <= 0) { ++ if (rc < 0) ++ ret = rc; ++ break; ++ } ++ if (copy_to_user(buf, tmp, rc)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ nbytes -= rc; ++ buf += rc; ++ ret += rc; ++ } ++ ++ /* Wipe data just returned from memory */ ++ if (tmp_large) ++ kfree_sensitive(tmp_large); ++ else ++ memzero_explicit(tmpbuf, sizeof(tmpbuf)); ++ ++ return ret; ++} ++ ++ssize_t lrng_read_common_block(int nonblock, int pr, ++ char __user *buf, size_t nbytes) ++{ ++ int ret; ++ ++ if (nbytes == 0) ++ return 0; ++ ++ ret = lrng_drng_sleep_while_nonoperational(nonblock); ++ if (ret) ++ return ret; ++ ++ return lrng_read_common(buf, nbytes, !!pr); ++} ++ ++ssize_t lrng_drng_read_block(struct file *file, char __user *buf, size_t nbytes, ++ loff_t *ppos) ++{ ++ return lrng_read_common_block(file->f_flags & O_NONBLOCK, ++ file->f_flags & O_SYNC, buf, nbytes); ++} ++ ++__poll_t lrng_random_poll(struct file *file, poll_table *wait) ++{ ++ __poll_t mask; ++ ++ poll_wait(file, &lrng_init_wait, wait); ++ poll_wait(file, &lrng_write_wait, wait); ++ mask = 0; ++ if (lrng_state_operational()) ++ mask |= EPOLLIN | EPOLLRDNORM; ++ if (lrng_need_entropy() || ++ lrng_state_exseed_allow(lrng_noise_source_user)) { ++ lrng_state_exseed_set(lrng_noise_source_user, false); ++ mask |= EPOLLOUT | EPOLLWRNORM; ++ } ++ return mask; ++} ++ ++ssize_t lrng_drng_write_common(const char __user *buffer, size_t count, ++ u32 entropy_bits) ++{ ++ ssize_t ret = 0; ++ u8 buf[64] __aligned(LRNG_KCAPI_ALIGN); ++ const char __user *p = buffer; ++ u32 orig_entropy_bits = entropy_bits; ++ ++ if (!lrng_get_available()) { ++ ret = lrng_drng_initalize(); ++ if (!ret) ++ return ret; ++ } ++ ++ count = min_t(size_t, count, INT_MAX); ++ while (count > 0) { ++ size_t bytes = min_t(size_t, count, sizeof(buf)); ++ u32 ent = min_t(u32, bytes<<3, entropy_bits); ++ ++ if (copy_from_user(&buf, p, bytes)) ++ return -EFAULT; ++ /* Inject data into entropy pool */ ++ lrng_pool_insert_aux(buf, bytes, ent); ++ ++ count -= bytes; ++ p += bytes; ++ ret += bytes; ++ entropy_bits -= ent; ++ ++ cond_resched(); ++ } ++ ++ /* Force reseed of DRNG during next data request. */ ++ if (!orig_entropy_bits) ++ lrng_drng_force_reseed(); ++ ++ return ret; ++} ++ ++ssize_t lrng_drng_write(struct file *file, const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ return lrng_drng_write_common(buffer, count, 0); ++} ++ ++long lrng_ioctl(struct file *f, unsigned int cmd, unsigned long arg) ++{ ++ u32 digestsize_bits; ++ int size, ent_count_bits, ret; ++ int __user *p = (int __user *)arg; ++ ++ switch (cmd) { ++ case RNDGETENTCNT: ++ ent_count_bits = lrng_avail_entropy_aux(); ++ if (put_user(ent_count_bits, p)) ++ return -EFAULT; ++ return 0; ++ case RNDADDTOENTCNT: ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ if (get_user(ent_count_bits, p)) ++ return -EFAULT; ++ ent_count_bits = (int)lrng_get_aux_ent() + ent_count_bits; ++ if (ent_count_bits < 0) ++ ent_count_bits = 0; ++ digestsize_bits = lrng_get_digestsize(); ++ if (ent_count_bits > digestsize_bits) ++ ent_count_bits = digestsize_bits; ++ lrng_pool_set_entropy(ent_count_bits); ++ return 0; ++ case RNDADDENTROPY: ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ if (get_user(ent_count_bits, p++)) ++ return -EFAULT; ++ if (ent_count_bits < 0) ++ return -EINVAL; ++ if (get_user(size, p++)) ++ return -EFAULT; ++ if (size < 0) ++ return -EINVAL; ++ /* there cannot be more entropy than data */ ++ ent_count_bits = min(ent_count_bits, size<<3); ++ ret = lrng_drng_write_common((const char __user *)p, size, ++ ent_count_bits); ++ return (ret < 0) ? ret : 0; ++ case RNDZAPENTCNT: ++ case RNDCLEARPOOL: ++ /* Clear the entropy pool counter. */ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ lrng_pool_set_entropy(0); ++ return 0; ++ case RNDRESEEDCRNG: ++ /* ++ * We leave the capability check here since it is present ++ * in the upstream's RNG implementation. Yet, user space ++ * can trigger a reseed as easy as writing into /dev/random ++ * or /dev/urandom where no privilege is needed. ++ */ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ /* Force a reseed of all DRNGs */ ++ lrng_drng_force_reseed(); ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++EXPORT_SYMBOL(lrng_ioctl); ++ ++int lrng_fasync(int fd, struct file *filp, int on) ++{ ++ return fasync_helper(fd, filp, on, &fasync); ++} +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_random_kernel.c +@@ -0,0 +1,248 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Kernel space interfaces API/ABI compliant to linux/random.h ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lrng_es_aux.h" ++#include "lrng_es_irq.h" ++#include "lrng_es_mgr.h" ++#include "lrng_interface_dev_common.h" ++#include "lrng_interface_random_kernel.h" ++ ++static ATOMIC_NOTIFIER_HEAD(random_ready_notifier); ++ ++/********************************** Helper ***********************************/ ++ ++static bool lrng_trust_bootloader __initdata = ++ IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER); ++ ++static int __init lrng_parse_trust_bootloader(char *arg) ++{ ++ return kstrtobool(arg, &lrng_trust_bootloader); ++} ++early_param("random.trust_bootloader", lrng_parse_trust_bootloader); ++ ++void __init random_init_early(const char *command_line) ++{ ++ lrng_rand_initialize_early(); ++ lrng_pool_insert_aux(command_line, strlen(command_line), 0); ++} ++ ++void __init random_init(void) ++{ ++ lrng_rand_initialize(); ++} ++ ++/* ++ * Add a callback function that will be invoked when the LRNG is initialised, ++ * or immediately if it already has been. Only use this is you are absolutely ++ * sure it is required. Most users should instead be able to test ++ * `rng_is_initialized()` on demand, or make use of `get_random_bytes_wait()`. ++ */ ++int __cold execute_with_initialized_rng(struct notifier_block *nb) ++{ ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&random_ready_notifier.lock, flags); ++ if (rng_is_initialized()) ++ nb->notifier_call(nb, 0, NULL); ++ else ++ ret = raw_notifier_chain_register( ++ (struct raw_notifier_head *)&random_ready_notifier.head, ++ nb); ++ spin_unlock_irqrestore(&random_ready_notifier.lock, flags); ++ return ret; ++} ++ ++void lrng_kick_random_ready(void) ++{ ++ atomic_notifier_call_chain(&random_ready_notifier, 0, NULL); ++} ++ ++/************************ LRNG kernel input interfaces ************************/ ++ ++/* ++ * add_hwgenerator_randomness() - Interface for in-kernel drivers of true ++ * hardware RNGs. ++ * ++ * Those devices may produce endless random bits and will be throttled ++ * when our pool is full. ++ * ++ * @buffer: buffer holding the entropic data from HW noise sources to be used to ++ * insert into entropy pool. ++ * @count: length of buffer ++ * @entropy_bits: amount of entropy in buffer (value is in bits) ++ */ ++void add_hwgenerator_randomness(const void *buffer, size_t count, ++ size_t entropy_bits, bool sleep_after) ++{ ++ /* ++ * Suspend writing if we are fully loaded with entropy or if caller ++ * did not provide any entropy. We'll be woken up again once below ++ * lrng_write_wakeup_thresh, or when the calling thread is about to ++ * terminate. ++ */ ++ wait_event_interruptible(lrng_write_wait, ++ (lrng_need_entropy() && entropy_bits) || ++ lrng_state_exseed_allow(lrng_noise_source_hw) || ++ !sleep_after || ++ kthread_should_stop()); ++ lrng_state_exseed_set(lrng_noise_source_hw, false); ++ lrng_pool_insert_aux(buffer, count, entropy_bits); ++} ++EXPORT_SYMBOL_GPL(add_hwgenerator_randomness); ++ ++/* ++ * add_bootloader_randomness() - Handle random seed passed by bootloader. ++ * ++ * If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise ++ * it would be regarded as device data. ++ * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER. ++ * ++ * @buf: buffer holding the entropic data from HW noise sources to be used to ++ * insert into entropy pool. ++ * @size: length of buffer ++ */ ++void __init add_bootloader_randomness(const void *buf, size_t size) ++{ ++ lrng_pool_insert_aux(buf, size, lrng_trust_bootloader ? size * 8 : 0); ++} ++ ++/* ++ * Callback for HID layer -- use the HID event values to stir the entropy pool ++ */ ++void add_input_randomness(unsigned int type, unsigned int code, ++ unsigned int value) ++{ ++ static unsigned char last_value; ++ ++ /* ignore autorepeat and the like */ ++ if (value == last_value) ++ return; ++ ++ last_value = value; ++ ++ lrng_irq_array_add_u32((type << 4) ^ code ^ (code >> 4) ^ value); ++} ++EXPORT_SYMBOL_GPL(add_input_randomness); ++ ++/* ++ * add_device_randomness() - Add device- or boot-specific data to the entropy ++ * pool to help initialize it. ++ * ++ * None of this adds any entropy; it is meant to avoid the problem of ++ * the entropy pool having similar initial state across largely ++ * identical devices. ++ * ++ * @buf: buffer holding the entropic data from HW noise sources to be used to ++ * insert into entropy pool. ++ * @size: length of buffer ++ */ ++void add_device_randomness(const void *buf, size_t size) ++{ ++ lrng_pool_insert_aux((u8 *)buf, size, 0); ++} ++EXPORT_SYMBOL(add_device_randomness); ++ ++#ifdef CONFIG_BLOCK ++void rand_initialize_disk(struct gendisk *disk) { } ++void add_disk_randomness(struct gendisk *disk) { } ++EXPORT_SYMBOL(add_disk_randomness); ++#endif ++ ++#ifndef CONFIG_LRNG_IRQ ++void add_interrupt_randomness(int irq) { } ++EXPORT_SYMBOL(add_interrupt_randomness); ++#endif ++ ++#if IS_ENABLED(CONFIG_VMGENID) ++static BLOCKING_NOTIFIER_HEAD(lrng_vmfork_chain); ++ ++/* ++ * Handle a new unique VM ID, which is unique, not secret, so we ++ * don't credit it, but we do immediately force a reseed after so ++ * that it's used by the crng posthaste. ++ */ ++void add_vmfork_randomness(const void *unique_vm_id, size_t size) ++{ ++ add_device_randomness(unique_vm_id, size); ++ if (lrng_state_operational()) ++ lrng_drng_force_reseed(); ++ blocking_notifier_call_chain(&lrng_vmfork_chain, 0, NULL); ++} ++#if IS_MODULE(CONFIG_VMGENID) ++EXPORT_SYMBOL_GPL(add_vmfork_randomness); ++#endif ++ ++int register_random_vmfork_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&lrng_vmfork_chain, nb); ++} ++EXPORT_SYMBOL_GPL(register_random_vmfork_notifier); ++ ++int unregister_random_vmfork_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&lrng_vmfork_chain, nb); ++} ++EXPORT_SYMBOL_GPL(unregister_random_vmfork_notifier); ++#endif ++ ++/*********************** LRNG kernel output interfaces ************************/ ++ ++/* ++ * get_random_bytes() - Provider of cryptographic strong random numbers for ++ * kernel-internal usage. ++ * ++ * This function is appropriate for all in-kernel use cases. However, ++ * it will always use the ChaCha20 DRNG. ++ * ++ * @buf: buffer to store the random bytes ++ * @nbytes: size of the buffer ++ */ ++void get_random_bytes(void *buf, size_t nbytes) ++{ ++ lrng_get_random_bytes(buf, nbytes); ++} ++EXPORT_SYMBOL(get_random_bytes); ++ ++/* ++ * wait_for_random_bytes() - Wait for the LRNG to be seeded and thus ++ * guaranteed to supply cryptographically secure random numbers. ++ * ++ * This applies to: the /dev/urandom device, the get_random_bytes function, ++ * and the get_random_{u32,u64,int,long} family of functions. Using any of ++ * these functions without first calling this function forfeits the guarantee ++ * of security. ++ * ++ * Return: ++ * * 0 if the LRNG has been seeded. ++ * * -ERESTARTSYS if the function was interrupted by a signal. ++ */ ++int wait_for_random_bytes(void) ++{ ++ return lrng_drng_sleep_while_non_min_seeded(); ++} ++EXPORT_SYMBOL(wait_for_random_bytes); ++ ++/* ++ * Returns whether or not the LRNG has been seeded. ++ * ++ * Returns: true if the urandom pool has been seeded. ++ * false if the urandom pool has not been seeded. ++ */ ++bool rng_is_initialized(void) ++{ ++ return lrng_state_operational(); ++} ++EXPORT_SYMBOL(rng_is_initialized); +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_random_user.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG Common user space interfaces compliant to random(4), random(7) and ++ * getrandom(2) man pages. ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++ ++#include "lrng_es_mgr.h" ++#include "lrng_interface_dev_common.h" ++ ++static ssize_t lrng_drng_read(struct file *file, char __user *buf, ++ size_t nbytes, loff_t *ppos) ++{ ++ if (!lrng_state_min_seeded()) ++ pr_notice_ratelimited("%s - use of insufficiently seeded DRNG (%zu bytes read)\n", ++ current->comm, nbytes); ++ else if (!lrng_state_operational()) ++ pr_debug_ratelimited("%s - use of not fully seeded DRNG (%zu bytes read)\n", ++ current->comm, nbytes); ++ ++ return lrng_read_common(buf, nbytes, false); ++} ++ ++const struct file_operations random_fops = { ++ .read = lrng_drng_read_block, ++ .write = lrng_drng_write, ++ .poll = lrng_random_poll, ++ .unlocked_ioctl = lrng_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, ++ .fasync = lrng_fasync, ++ .llseek = noop_llseek, ++}; ++ ++const struct file_operations urandom_fops = { ++ .read = lrng_drng_read, ++ .write = lrng_drng_write, ++ .unlocked_ioctl = lrng_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, ++ .fasync = lrng_fasync, ++ .llseek = noop_llseek, ++}; ++ ++/* ++ * GRND_SEED ++ * ++ * This flag requests to provide the data directly from the entropy sources. ++ * ++ * The behavior of the call is exactly as outlined for the function ++ * lrng_get_seed in lrng.h. ++ */ ++#define GRND_SEED 0x0010 ++ ++/* ++ * GRND_FULLY_SEEDED ++ * ++ * This flag indicates whether the caller wants to reseed a DRNG that is already ++ * fully seeded. See esdm_get_seed in lrng.h for details. ++ */ ++#define GRND_FULLY_SEEDED 0x0020 ++ ++SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, ++ unsigned int, flags) ++{ ++ if (flags & ~(GRND_NONBLOCK|GRND_RANDOM|GRND_INSECURE| ++ GRND_SEED|GRND_FULLY_SEEDED)) ++ return -EINVAL; ++ ++ /* ++ * Requesting insecure and blocking randomness at the same time makes ++ * no sense. ++ */ ++ if ((flags & ++ (GRND_INSECURE|GRND_RANDOM)) == (GRND_INSECURE|GRND_RANDOM)) ++ return -EINVAL; ++ if ((flags & ++ (GRND_INSECURE|GRND_SEED)) == (GRND_INSECURE|GRND_SEED)) ++ return -EINVAL; ++ if ((flags & ++ (GRND_RANDOM|GRND_SEED)) == (GRND_RANDOM|GRND_SEED)) ++ return -EINVAL; ++ ++ if (count > INT_MAX) ++ count = INT_MAX; ++ ++ if (flags & GRND_INSECURE) { ++ return lrng_drng_read(NULL, buf, count, NULL); ++ } else if (flags & GRND_SEED) { ++ unsigned int seed_flags = (flags & GRND_NONBLOCK) ? ++ LRNG_GET_SEED_NONBLOCK : 0; ++ ++ seed_flags |= (flags & GRND_FULLY_SEEDED) ? ++ LRNG_GET_SEED_FULLY_SEEDED : 0; ++ return lrng_read_seed(buf, count, seed_flags); ++ } ++ ++ return lrng_read_common_block(flags & GRND_NONBLOCK, ++ flags & GRND_RANDOM, buf, count); ++} diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch new file mode 100644 index 000000000..159f7f5fd --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch @@ -0,0 +1,199 @@ +From 021ba8b87e270abdb892ae853fc863cb7e258265 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 9 Oct 2022 10:22:39 +0200 +Subject: [PATCH 23/25] LRNG - add kernel crypto API interface + +The LRNG can be registered with the kernel crypto API's random number +generator framework. This offers a random number generator with the name +"lrng" and a priority that is intended to be higher than the existing +RNG implementations. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 26 ++--- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_interface_kcapi.c | 129 +++++++++++++++++++++++ + 3 files changed, 143 insertions(+), 13 deletions(-) + create mode 100644 drivers/char/lrng/lrng_interface_kcapi.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -89,18 +89,18 @@ config LRNG_AIS2031_NTG1_SEEDING_STRATEG + + endmenu # "Specific DRNG seeding strategies" + +-# menu "LRNG Interfaces" +-# +-# config LRNG_KCAPI_IF +-# tristate "Interface with Kernel Crypto API" +-# depends on CRYPTO_RNG +-# help +-# The LRNG can be registered with the kernel crypto API's +-# random number generator framework. This offers a random +-# number generator with the name "lrng" and a priority that +-# is intended to be higher than the existing RNG +-# implementations. +-# ++menu "LRNG Interfaces" ++ ++config LRNG_KCAPI_IF ++ tristate "Interface with Kernel Crypto API" ++ depends on CRYPTO_RNG ++ help ++ The LRNG can be registered with the kernel crypto API's ++ random number generator framework. This offers a random ++ number generator with the name "lrng" and a priority that ++ is intended to be higher than the existing RNG ++ implementations. ++ + # config LRNG_HWRAND_IF + # tristate "Interface with Hardware Random Number Generator Framework" + # depends on HW_RANDOM +@@ -120,7 +120,7 @@ endmenu # "Specific DRNG seeding strateg + # identically to /dev/random including IOCTL, read and write + # operations. + # +-# endmenu # "LRNG Interfaces" ++endmenu # "LRNG Interfaces" + + menu "Entropy Source Configuration" + +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -34,3 +34,4 @@ obj-$(CONFIG_LRNG_COMMON_DEV_IF) += lrng + obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_interface_random_user.o \ + lrng_interface_random_kernel.o \ + lrng_interface_aux.o ++obj-$(CONFIG_LRNG_KCAPI_IF) += lrng_interface_kcapi.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_kcapi.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG interface with the RNG framework of the kernel crypto API ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#include ++#include ++#include ++ ++#include "lrng_drng_mgr.h" ++#include "lrng_es_aux.h" ++ ++static int lrng_kcapi_if_init(struct crypto_tfm *tfm) ++{ ++ return 0; ++} ++ ++static void lrng_kcapi_if_cleanup(struct crypto_tfm *tfm) { } ++ ++static int lrng_kcapi_if_reseed(const u8 *src, unsigned int slen) ++{ ++ int ret; ++ ++ if (!slen) ++ return 0; ++ ++ /* Insert caller-provided data without crediting entropy */ ++ ret = lrng_pool_insert_aux((u8 *)src, slen, 0); ++ if (ret) ++ return ret; ++ ++ /* Make sure the new data is immediately available to DRNG */ ++ lrng_drng_force_reseed(); ++ ++ return 0; ++} ++ ++static int lrng_kcapi_if_random(struct crypto_rng *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *rdata, unsigned int dlen) ++{ ++ int ret = lrng_kcapi_if_reseed(src, slen); ++ ++ if (!ret) ++ lrng_get_random_bytes_full(rdata, dlen); ++ ++ return ret; ++} ++ ++static int lrng_kcapi_if_reset(struct crypto_rng *tfm, ++ const u8 *seed, unsigned int slen) ++{ ++ return lrng_kcapi_if_reseed(seed, slen); ++} ++ ++static struct rng_alg lrng_alg = { ++ .generate = lrng_kcapi_if_random, ++ .seed = lrng_kcapi_if_reset, ++ .seedsize = 0, ++ .base = { ++ .cra_name = "stdrng", ++ .cra_driver_name = "lrng", ++ .cra_priority = 500, ++ .cra_ctxsize = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = lrng_kcapi_if_init, ++ .cra_exit = lrng_kcapi_if_cleanup, ++ ++ } ++}; ++ ++#ifdef CONFIG_LRNG_DRNG_ATOMIC ++static int lrng_kcapi_if_random_atomic(struct crypto_rng *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *rdata, unsigned int dlen) ++{ ++ int ret = lrng_kcapi_if_reseed(src, slen); ++ ++ if (!ret) ++ lrng_get_random_bytes(rdata, dlen); ++ ++ return ret; ++} ++ ++static struct rng_alg lrng_alg_atomic = { ++ .generate = lrng_kcapi_if_random_atomic, ++ .seed = lrng_kcapi_if_reset, ++ .seedsize = 0, ++ .base = { ++ .cra_name = "lrng_atomic", ++ .cra_driver_name = "lrng_atomic", ++ .cra_priority = 100, ++ .cra_ctxsize = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = lrng_kcapi_if_init, ++ .cra_exit = lrng_kcapi_if_cleanup, ++ ++ } ++}; ++#endif /* CONFIG_LRNG_DRNG_ATOMIC */ ++ ++static int __init lrng_kcapi_if_mod_init(void) ++{ ++ return ++#ifdef CONFIG_LRNG_DRNG_ATOMIC ++ crypto_register_rng(&lrng_alg_atomic) ?: ++#endif ++ crypto_register_rng(&lrng_alg); ++} ++ ++static void __exit lrng_kcapi_if_mod_exit(void) ++{ ++ crypto_unregister_rng(&lrng_alg); ++#ifdef CONFIG_LRNG_DRNG_ATOMIC ++ crypto_unregister_rng(&lrng_alg_atomic); ++#endif ++} ++ ++module_init(lrng_kcapi_if_mod_init); ++module_exit(lrng_kcapi_if_mod_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Stephan Mueller "); ++MODULE_DESCRIPTION("Entropy Source and DRNG Manager kernel crypto API RNG framework interface"); ++MODULE_ALIAS_CRYPTO("lrng"); ++MODULE_ALIAS_CRYPTO("lrng_atomic"); ++MODULE_ALIAS_CRYPTO("stdrng"); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch new file mode 100644 index 000000000..02dfb11e2 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch @@ -0,0 +1,88 @@ +From 7697fe0de6bdc7a8e0a4c722dbf6dec24ffe53d5 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 18:39:30 +0200 +Subject: [PATCH 24/25] LRNG - add /dev/lrng device file support + +The LRNG can create a character device file that operates identically +to /dev/random including IOCTL, read and write operations. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 18 ++++++------- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_interface_dev.c | 35 ++++++++++++++++++++++++++ + 3 files changed, 45 insertions(+), 9 deletions(-) + create mode 100644 drivers/char/lrng/lrng_interface_dev.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -111,15 +111,15 @@ config LRNG_KCAPI_IF + # with the name "lrng" that is accessible via the framework. + # For example it allows pulling data from the LRNG via the + # /dev/hwrng file. +-# +-# config LRNG_DEV_IF +-# bool "Character device file interface" +-# select LRNG_COMMON_DEV_IF +-# help +-# The LRNG can create a character device file that operates +-# identically to /dev/random including IOCTL, read and write +-# operations. +-# ++ ++config LRNG_DEV_IF ++ bool "Character device file interface" ++ select LRNG_COMMON_DEV_IF ++ help ++ The LRNG can create a character device file that operates ++ identically to /dev/random including IOCTL, read and write ++ operations. ++ + endmenu # "LRNG Interfaces" + + menu "Entropy Source Configuration" +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -35,3 +35,4 @@ obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_in + lrng_interface_random_kernel.o \ + lrng_interface_aux.o + obj-$(CONFIG_LRNG_KCAPI_IF) += lrng_interface_kcapi.o ++obj-$(CONFIG_LRNG_DEV_IF) += lrng_interface_dev.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_dev.c +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG user space device file interface ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#include ++#include ++ ++#include "lrng_interface_dev_common.h" ++ ++static const struct file_operations lrng_fops = { ++ .read = lrng_drng_read_block, ++ .write = lrng_drng_write, ++ .poll = lrng_random_poll, ++ .unlocked_ioctl = lrng_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, ++ .fasync = lrng_fasync, ++ .llseek = noop_llseek, ++}; ++ ++static struct miscdevice lrng_miscdev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "lrng", ++ .nodename = "lrng", ++ .fops = &lrng_fops, ++ .mode = 0666 ++}; ++ ++static int __init lrng_dev_if_mod_init(void) ++{ ++ return misc_register(&lrng_miscdev); ++} ++device_initcall(lrng_dev_if_mod_init); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch new file mode 100644 index 000000000..bc8eed543 --- /dev/null +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch @@ -0,0 +1,125 @@ +From 243b20ab41748e898abcf298b0cb836f04391afd Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Sun, 15 May 2022 18:43:30 +0200 +Subject: [PATCH 25/25] LRNG - add hwrand framework interface + +The LRNG can be registered with the hardware random number generator +framework. This offers a random number generator with the name "lrng" +that is accessible via the framework. For example it allows pulling +data from the LRNG via the /dev/hwrng file. + +Signed-off-by: Stephan Mueller +--- + drivers/char/lrng/Kconfig | 20 +++---- + drivers/char/lrng/Makefile | 1 + + drivers/char/lrng/lrng_interface_hwrand.c | 68 +++++++++++++++++++++++ + 3 files changed, 79 insertions(+), 10 deletions(-) + create mode 100644 drivers/char/lrng/lrng_interface_hwrand.c + +--- a/drivers/char/lrng/Kconfig ++++ b/drivers/char/lrng/Kconfig +@@ -101,16 +101,16 @@ config LRNG_KCAPI_IF + is intended to be higher than the existing RNG + implementations. + +-# config LRNG_HWRAND_IF +-# tristate "Interface with Hardware Random Number Generator Framework" +-# depends on HW_RANDOM +-# select LRNG_DRNG_ATOMIC +-# help +-# The LRNG can be registered with the hardware random number +-# generator framework. This offers a random number generator +-# with the name "lrng" that is accessible via the framework. +-# For example it allows pulling data from the LRNG via the +-# /dev/hwrng file. ++config LRNG_HWRAND_IF ++ tristate "Interface with Hardware Random Number Generator Framework" ++ depends on HW_RANDOM ++ select LRNG_DRNG_ATOMIC ++ help ++ The LRNG can be registered with the hardware random number ++ generator framework. This offers a random number generator ++ with the name "lrng" that is accessible via the framework. ++ For example it allows pulling data from the LRNG via the ++ /dev/hwrng file. + + config LRNG_DEV_IF + bool "Character device file interface" +--- a/drivers/char/lrng/Makefile ++++ b/drivers/char/lrng/Makefile +@@ -36,3 +36,4 @@ obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_in + lrng_interface_aux.o + obj-$(CONFIG_LRNG_KCAPI_IF) += lrng_interface_kcapi.o + obj-$(CONFIG_LRNG_DEV_IF) += lrng_interface_dev.o ++obj-$(CONFIG_LRNG_HWRAND_IF) += lrng_interface_hwrand.o +--- /dev/null ++++ b/drivers/char/lrng/lrng_interface_hwrand.c +@@ -0,0 +1,68 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++/* ++ * LRNG interface with the HW-Random framework ++ * ++ * Copyright (C) 2022, Stephan Mueller ++ */ ++ ++#include ++#include ++#include ++ ++static int lrng_hwrand_if_random(struct hwrng *rng, void *buf, size_t max, ++ bool wait) ++{ ++ /* ++ * lrng_get_random_bytes_full not called as we cannot block. ++ * ++ * Note: We should either adjust .quality below depending on ++ * rng_is_initialized() or block here, but neither is not supported by ++ * the hw_rand framework. ++ */ ++ lrng_get_random_bytes(buf, max); ++ return (int)max; ++} ++ ++static struct hwrng lrng_hwrand = { ++ .name = "lrng", ++ .init = NULL, ++ .cleanup = NULL, ++ .read = lrng_hwrand_if_random, ++ ++ /* ++ * We set .quality only in case the LRNG does not provide the common ++ * interfaces or does not use the legacy RNG as entropy source. This ++ * shall avoid that the LRNG automatically spawns the hw_rand ++ * framework's hwrng kernel thread to feed data into ++ * add_hwgenerator_randomness. When the LRNG implements the common ++ * interfaces, this function feeds the data directly into the LRNG. ++ * If the LRNG uses the legacy RNG as entropy source, ++ * add_hwgenerator_randomness is implemented by the legacy RNG, but ++ * still eventually feeds the data into the LRNG. We should avoid such ++ * circular loops. ++ * ++ * We can specify full entropy here, because the LRNG is designed ++ * to provide full entropy. ++ */ ++#if !defined(CONFIG_LRNG_RANDOM_IF) && \ ++ !defined(CONFIG_LRNG_KERNEL_RNG) ++ .quality = 1024, ++#endif ++}; ++ ++static int __init lrng_hwrand_if_mod_init(void) ++{ ++ return hwrng_register(&lrng_hwrand); ++} ++ ++static void __exit lrng_hwrand_if_mod_exit(void) ++{ ++ hwrng_unregister(&lrng_hwrand); ++} ++ ++module_init(lrng_hwrand_if_mod_init); ++module_exit(lrng_hwrand_if_mod_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Stephan Mueller "); ++MODULE_DESCRIPTION("Entropy Source and DRNG Manager HW-Random Interface"); diff --git a/openwrt/patch/kernel-6.11/net/601-netfilter-export-udp_get_timeouts-function.patch b/openwrt/patch/kernel-6.11/net/601-netfilter-export-udp_get_timeouts-function.patch new file mode 100644 index 000000000..d741cb7c3 --- /dev/null +++ b/openwrt/patch/kernel-6.11/net/601-netfilter-export-udp_get_timeouts-function.patch @@ -0,0 +1,38 @@ +From e38488fd0a8a11b4bae4ccad9a7a8cfcf9eb5ab7 Mon Sep 17 00:00:00 2001 +From: Murat Sezgin +Date: Mon, 6 Apr 2020 11:08:09 -0700 +Subject: [PATCH] netfilter: export udp_get_timeouts function + +This function is required for acceleration support. + +Signed-off-by: Murat Sezgin +Change-Id: Ibca4f402735764e7e6fb3ce2678e670753c6ef9c +--- + include/net/netfilter/nf_conntrack_timeout.h | 1 + + net/netfilter/nf_conntrack_proto_udp.c | 3 ++- + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/include/net/netfilter/nf_conntrack_timeout.h ++++ b/include/net/netfilter/nf_conntrack_timeout.h +@@ -107,5 +107,6 @@ struct nf_ct_timeout_hooks { + + extern const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook; + #endif ++extern unsigned int *udp_get_timeouts(struct net *net); + + #endif /* _NF_CONNTRACK_TIMEOUT_H */ +--- a/net/netfilter/nf_conntrack_proto_udp.c ++++ b/net/netfilter/nf_conntrack_proto_udp.c +@@ -29,10 +29,11 @@ static const unsigned int udp_timeouts[U + [UDP_CT_REPLIED] = 120*HZ, + }; + +-static unsigned int *udp_get_timeouts(struct net *net) ++unsigned int *udp_get_timeouts(struct net *net) + { + return nf_udp_pernet(net)->timeouts; + } ++EXPORT_SYMBOL(udp_get_timeouts); + + static void udp_error_log(const struct sk_buff *skb, + const struct nf_hook_state *state, diff --git a/openwrt/patch/kernel-6.11/net/952-net-conntrack-events-support-multiple-registrant.patch b/openwrt/patch/kernel-6.11/net/952-net-conntrack-events-support-multiple-registrant.patch new file mode 100644 index 000000000..15e16ae73 --- /dev/null +++ b/openwrt/patch/kernel-6.11/net/952-net-conntrack-events-support-multiple-registrant.patch @@ -0,0 +1,352 @@ +From 986b513b5cc049e9a5f10c35b76f037dde8b8c3e Mon Sep 17 00:00:00 2001 +From: Zhi Chen +Date: Tue, 13 Jan 2015 14:28:18 -0800 +Subject: [PATCH 1/2] net: conntrack events, support multiple registrant + +Merging this patch from kernel 3.4: +This was supported by old (.28) kernel versions but removed +because of it's overhead. +But we need this feature for NA connection manager. Both ipv4 +and ipv6 modules needs to register themselves to ct events. + +Change-Id: Iebfb254590fb594f5baf232f849d1b7ae45ef757 +Signed-off-by: Zhi Chen +--- + include/net/netfilter/nf_conntrack_ecache.h | 33 +++++-- + include/net/netns/conntrack.h | 3 + + net/netfilter/Kconfig | 8 ++ + net/netfilter/nf_conntrack_core.c | 4 + + net/netfilter/nf_conntrack_ecache.c | 103 +++++++++++++++++++- + net/netfilter/nf_conntrack_netlink.c | 17 ++++ + 6 files changed, 160 insertions(+), 8 deletions(-) + +--- a/include/net/netfilter/nf_conntrack_ecache.h ++++ b/include/net/netfilter/nf_conntrack_ecache.h +@@ -65,9 +65,14 @@ struct nf_ct_event_notifier { + int (*exp_event)(unsigned int events, const struct nf_exp_event *item); + }; + +-void nf_conntrack_register_notifier(struct net *net, ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++extern int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb); ++extern int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb); ++#else ++int nf_conntrack_register_notifier(struct net *net, + const struct nf_ct_event_notifier *nb); + void nf_conntrack_unregister_notifier(struct net *net); ++#endif + + void nf_ct_deliver_cached_events(struct nf_conn *ct); + int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, +@@ -98,11 +103,13 @@ static inline void + nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) + { + #ifdef CONFIG_NF_CONNTRACK_EVENTS +- struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *e; ++#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ struct net *net = nf_ct_net(ct); + + if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) + return; ++#endif + + e = nf_ct_ecache_find(ct); + if (e == NULL) +@@ -117,20 +124,34 @@ nf_conntrack_event_report(enum ip_conntr + u32 portid, int report) + { + #ifdef CONFIG_NF_CONNTRACK_EVENTS +- if (nf_ct_ecache_exist(ct)) +- return nf_conntrack_eventmask_report(1 << event, ct, portid, report); ++#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ const struct net *net = nf_ct_net(ct); ++ ++ if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) ++ return 0; + #endif ++ ++ return nf_conntrack_eventmask_report(1 << event, ct, portid, report); ++#else + return 0; ++#endif + } + + static inline int + nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) + { + #ifdef CONFIG_NF_CONNTRACK_EVENTS +- if (nf_ct_ecache_exist(ct)) +- return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); ++#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ const struct net *net = nf_ct_net(ct); ++ ++ if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) ++ return 0; + #endif ++ ++ return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); ++#else + return 0; ++#endif + } + + #ifdef CONFIG_NF_CONNTRACK_EVENTS +--- a/include/net/netns/conntrack.h ++++ b/include/net/netns/conntrack.h +@@ -104,6 +104,9 @@ struct netns_ct { + u8 sysctl_checksum; + + struct ip_conntrack_stat __percpu *stat; ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ struct atomic_notifier_head nf_conntrack_chain; ++#endif + struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb; + struct nf_ip_net nf_ct_proto; + #if defined(CONFIG_NF_CONNTRACK_LABELS) +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -164,6 +164,14 @@ config NF_CONNTRACK_EVENTS + + If unsure, say `N'. + ++config NF_CONNTRACK_CHAIN_EVENTS ++ bool "Register multiple callbacks to ct events" ++ depends on NF_CONNTRACK_EVENTS ++ help ++ Support multiple registrations. ++ ++ If unsure, say `N'. ++ + config NF_CONNTRACK_TIMEOUT + bool 'Connection tracking timeout' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -2789,6 +2789,10 @@ int nf_conntrack_init_net(struct net *ne + nf_conntrack_ecache_pernet_init(net); + nf_conntrack_proto_pernet_init(net); + ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ ATOMIC_INIT_NOTIFIER_HEAD(&net->ct.nf_conntrack_chain); ++#endif ++ + return 0; + + err_expect: +--- a/net/netfilter/nf_conntrack_ecache.c ++++ b/net/netfilter/nf_conntrack_ecache.c +@@ -17,6 +17,9 @@ + #include + #include + #include ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++#include ++#endif + #include + #include + #include +@@ -162,6 +165,35 @@ static int __nf_conntrack_eventmask_repo + return ret; + } + ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, ++ u32 portid, int report) ++{ ++ struct nf_conntrack_ecache *e; ++ struct net *net = nf_ct_net(ct); ++ ++ e = nf_ct_ecache_find(ct); ++ if (e == NULL) ++ return 0; ++ ++ if (nf_ct_is_confirmed(ct)) { ++ struct nf_ct_event item = { ++ .ct = ct, ++ .portid = e->portid ? e->portid : portid, ++ .report = report ++ }; ++ /* This is a resent of a destroy event? If so, skip missed */ ++ unsigned long missed = e->portid ? 0 : e->missed; ++ ++ if (!((eventmask | missed) & e->ctmask)) ++ return 0; ++ ++ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, eventmask | missed, &item); ++ } ++ ++ return 0; ++} ++#else + int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct, + u32 portid, int report) + { +@@ -197,10 +229,52 @@ int nf_conntrack_eventmask_report(unsign + + return ret; + } ++#endif + EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report); + + /* deliver cached events and clear cache entry - must be called with locally + * disabled softirqs */ ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++void nf_ct_deliver_cached_events(struct nf_conn *ct) ++{ ++ unsigned long events, missed; ++ struct nf_conntrack_ecache *e; ++ struct nf_ct_event item; ++ struct net *net = nf_ct_net(ct); ++ ++ e = nf_ct_ecache_find(ct); ++ if (e == NULL) ++ return; ++ ++ events = xchg(&e->cache, 0); ++ ++ if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events) ++ return; ++ ++ /* We make a copy of the missed event cache without taking ++ * the lock, thus we may send missed events twice. However, ++ * this does not harm and it happens very rarely. */ ++ missed = e->missed; ++ ++ if (!((events | missed) & e->ctmask)) ++ return; ++ ++ item.ct = ct; ++ item.portid = 0; ++ item.report = 0; ++ ++ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, ++ events | missed, ++ &item); ++ ++ if (likely(!missed)) ++ return; ++ ++ spin_lock_bh(&ct->lock); ++ e->missed &= ~missed; ++ spin_unlock_bh(&ct->lock); ++} ++#else + void nf_ct_deliver_cached_events(struct nf_conn *ct) + { + struct nf_conntrack_ecache *e; +@@ -226,6 +300,7 @@ void nf_ct_deliver_cached_events(struct + */ + __nf_conntrack_eventmask_report(e, events, e->missed, &item); + } ++#endif + EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); + + void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, +@@ -258,20 +333,43 @@ out_unlock: + rcu_read_unlock(); + } + +-void nf_conntrack_register_notifier(struct net *net, ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++int nf_conntrack_register_notifier(struct net *net, ++ struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); ++} ++#else ++int nf_conntrack_register_notifier(struct net *net, + const struct nf_ct_event_notifier *new) + { ++ int ret; + struct nf_ct_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb, + lockdep_is_held(&nf_ct_ecache_mutex)); + WARN_ON_ONCE(notify); ++ if (notify != NULL) { ++ ret = -EBUSY; ++ goto out_unlock; ++ } ++ + rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new); +- mutex_unlock(&nf_ct_ecache_mutex); ++ ret = 0; ++out_unlock: ++ mutex_unlock(&nf_ct_ecache_mutex); ++ return ret; + } ++#endif + EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier); + ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); ++} ++#else + void nf_conntrack_unregister_notifier(struct net *net) + { + mutex_lock(&nf_ct_ecache_mutex); +@@ -279,6 +377,7 @@ void nf_conntrack_unregister_notifier(st + mutex_unlock(&nf_ct_ecache_mutex); + /* synchronize_rcu() is called after netns pre_exit */ + } ++#endif + EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); + + void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state) +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -724,12 +724,19 @@ static size_t ctnetlink_nlmsg_size(const + } + + static int ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ctnetlink_conntrack_event(struct notifier_block *this, unsigned long events, void *ptr) ++#else + ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item) ++#endif + { + const struct nf_conntrack_zone *zone; + struct net *net; + struct nlmsghdr *nlh; + struct nlattr *nest_parms; ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ struct nf_ct_event *item = (struct nf_ct_event *)ptr; ++#endif + struct nf_conn *ct = item->ct; + struct sk_buff *skb; + unsigned int type; +@@ -3760,11 +3767,17 @@ static int ctnetlink_stat_exp_cpu(struct + } + + #ifdef CONFIG_NF_CONNTRACK_EVENTS ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++static struct notifier_block ctnl_notifier = { ++ .notifier_call = ctnetlink_conntrack_event ++}; ++#else + static struct nf_ct_event_notifier ctnl_notifier = { + .ct_event = ctnetlink_conntrack_event, + .exp_event = ctnetlink_expect_event, + }; + #endif ++#endif + + static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { + [IPCTNL_MSG_CT_NEW] = { +@@ -3863,8 +3876,12 @@ static int __net_init ctnetlink_net_init + static void ctnetlink_net_pre_exit(struct net *net) + { + #ifdef CONFIG_NF_CONNTRACK_EVENTS ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ nf_conntrack_unregister_notifier(net,&ctnl_notifier); ++#else + nf_conntrack_unregister_notifier(net); + #endif ++#endif + } + + static struct pernet_operations ctnetlink_net_ops = { diff --git a/openwrt/patch/kernel-6.11/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.11/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch new file mode 100644 index 000000000..fea7ef88e --- /dev/null +++ b/openwrt/patch/kernel-6.11/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -0,0 +1,206 @@ +From 737595f75328d06ba4f1fb12dd39c233b9919259 Mon Sep 17 00:00:00 2001 +From: Xiaoping Fan +Date: Fri, 26 Feb 2016 15:01:53 -0800 +Subject: [PATCH 2/2] net: patch linux kernel to support shortcut-fe + +Change-Id: Icaa7c172a06df1c3bc89ff89814d1136772fe217 +Signed-off-by: Xiaoping Fan +--- + include/linux/if_bridge.h | 3 +++ + include/linux/skbuff.h | 4 +++ + include/net/netfilter/nf_conntrack_ecache.h | 2 ++ + net/Kconfig | 3 +++ + net/bridge/br_if.c | 20 +++++++++++++++ + net/core/dev.c | 27 +++++++++++++++++++++ + net/netfilter/nf_conntrack_ecache.c | 24 +++++++++++++++++- + 7 files changed, 86 insertions(+), 1 deletion(-) + +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -71,6 +71,9 @@ void brioctl_set(int (*hook)(struct net + int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, + struct ifreq *ifr, void __user *uarg); + ++extern void br_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats); ++ + #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) + int br_multicast_list_adjacent(struct net_device *dev, + struct list_head *br_ip_list); +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -1009,6 +1009,10 @@ struct sk_buff { + __u8 csum_not_inet:1; + #endif + ++#ifdef CONFIG_SHORTCUT_FE ++ __u8 fast_forwarded:1; ++#endif ++ + #if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS) + __u16 tc_index; /* traffic control index */ + #endif +--- a/include/net/netfilter/nf_conntrack_ecache.h ++++ b/include/net/netfilter/nf_conntrack_ecache.h +@@ -68,6 +68,8 @@ struct nf_ct_event_notifier { + #ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS + extern int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb); + extern int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb); ++extern int nf_conntrack_register_chain_notifier(struct net *net, struct notifier_block *nb); ++extern int nf_conntrack_unregister_chain_notifier(struct net *net, struct notifier_block *nb); + #else + int nf_conntrack_register_notifier(struct net *net, + const struct nf_ct_event_notifier *nb); +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -506,6 +506,9 @@ config FAILOVER + migration of VMs with direct attached VFs by failing over to the + paravirtual datapath when the VF is unplugged. + ++config SHORTCUT_FE ++ bool "Enables kernel network stack path for Shortcut Forwarding Engine" ++ + config ETHTOOL_NETLINK + bool "Netlink interface for ethtool" + select DIMLIB +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -764,6 +764,26 @@ void br_port_flags_change(struct net_bri + br_recalculate_neigh_suppress_enabled(br); + } + ++void br_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats) ++{ ++ struct pcpu_sw_netstats *stats; ++ ++ /* Is this a bridge? */ ++ if (!(dev->priv_flags & IFF_EBRIDGE)) ++ return; ++ ++ stats = this_cpu_ptr(dev->tstats); ++ ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->rx_packets, nlstats->rx_packets); ++ u64_stats_add(&stats->rx_bytes, nlstats->rx_bytes); ++ u64_stats_add(&stats->tx_packets, nlstats->tx_packets); ++ u64_stats_add(&stats->tx_bytes, nlstats->tx_bytes); ++ u64_stats_update_end(&stats->syncp); ++} ++EXPORT_SYMBOL_GPL(br_dev_update_stats); ++ + bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) + { + struct net_bridge_port *p; +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3572,8 +3572,17 @@ static int xmit_one(struct sk_buff *skb, + unsigned int len; + int rc; + ++#ifdef CONFIG_SHORTCUT_FE ++ /* If this skb has been fast forwarded then we don't want it to ++ * go to any taps (by definition we're trying to bypass them). ++ */ ++ if (!skb->fast_forwarded) { ++#endif + if (dev_nit_active(dev)) + dev_queue_xmit_nit(skb, dev); ++#ifdef CONFIG_SHORTCUT_FE ++ } ++#endif + + len = skb->len; + trace_net_dev_start_xmit(skb, dev); +@@ -5408,6 +5417,11 @@ void netdev_rx_handler_unregister(struct + } + EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); + ++#ifdef CONFIG_SHORTCUT_FE ++int (*athrs_fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly; ++EXPORT_SYMBOL_GPL(athrs_fast_nat_recv); ++#endif ++ + /* + * Limit the use of PFMEMALLOC reserves to those protocols that implement + * the special handling of PFMEMALLOC skbs. +@@ -5456,6 +5470,10 @@ static int __netif_receive_skb_core(stru + int ret = NET_RX_DROP; + __be16 type; + ++#ifdef CONFIG_SHORTCUT_FE ++ int (*fast_recv)(struct sk_buff *skb); ++#endif ++ + net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); + + trace_netif_receive_skb(skb); +@@ -5494,6 +5512,16 @@ another_round: + goto out; + } + ++#ifdef CONFIG_SHORTCUT_FE ++ fast_recv = rcu_dereference(athrs_fast_nat_recv); ++ if (fast_recv) { ++ if (fast_recv(skb)) { ++ ret = NET_RX_SUCCESS; ++ goto out; ++ } ++ } ++#endif ++ + if (skb_skip_tc_classify(skb)) + goto skip_classify; + +--- a/net/netfilter/nf_conntrack_ecache.c ++++ b/net/netfilter/nf_conntrack_ecache.c +@@ -143,12 +143,24 @@ static int __nf_conntrack_eventmask_repo + rcu_read_lock(); + + notify = rcu_dereference(net->ct.nf_conntrack_event_cb); +- if (!notify) { ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ if (!notify && !rcu_dereference_raw(net->ct.nf_conntrack_chain.head)) ++#else ++ if (!notify) ++#endif ++ { + rcu_read_unlock(); + return 0; + } + ++#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS ++ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, ++ events | missed, &item); ++ if (notify) ++ ret = notify->ct_event(events | missed, item); ++#else + ret = notify->ct_event(events | missed, item); ++#endif + rcu_read_unlock(); + + if (likely(ret >= 0 && missed == 0)) +@@ -339,6 +351,11 @@ int nf_conntrack_register_notifier(struc + { + return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); + } ++int nf_conntrack_register_chain_notifier(struct net *net, struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); ++} ++EXPORT_SYMBOL_GPL(nf_conntrack_register_chain_notifier); + #else + int nf_conntrack_register_notifier(struct net *net, + const struct nf_ct_event_notifier *new) +@@ -369,6 +386,11 @@ int nf_conntrack_unregister_notifier(str + { + return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); + } ++int nf_conntrack_unregister_chain_notifier(struct net *net, struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); ++} ++EXPORT_SYMBOL_GPL(nf_conntrack_unregister_chain_notifier); + #else + void nf_conntrack_unregister_notifier(struct net *net) + { diff --git a/openwrt/patch/kernel-6.11/net/982-add-bcm-fullcone-support.patch b/openwrt/patch/kernel-6.11/net/982-add-bcm-fullcone-support.patch new file mode 100644 index 000000000..446f6bba5 --- /dev/null +++ b/openwrt/patch/kernel-6.11/net/982-add-bcm-fullcone-support.patch @@ -0,0 +1,235 @@ +--- a/net/netfilter/nf_nat_masquerade.c ++++ b/net/netfilter/nf_nat_masquerade.c +@@ -8,6 +8,9 @@ + #include + + #include ++#include ++#include ++#include + + struct masq_dev_work { + struct work_struct work; +@@ -24,6 +27,129 @@ static DEFINE_MUTEX(masq_mutex); + static unsigned int masq_refcnt __read_mostly; + static atomic_t masq_worker_count __read_mostly; + ++static void bcm_nat_expect(struct nf_conn *ct, ++ struct nf_conntrack_expect *exp) ++{ ++ struct nf_nat_range2 range; ++ ++ /* This must be a fresh one. */ ++ BUG_ON(ct->status & IPS_NAT_DONE_MASK); ++ ++ /* Change src to where new ct comes from */ ++ range.flags = NF_NAT_RANGE_MAP_IPS; ++ range.min_addr = range.max_addr = ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3; ++ nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); ++ ++ /* For DST manip, map port here to where it's expected. */ ++ range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); ++ range.min_proto = range.max_proto = exp->saved_proto; ++ range.min_addr = range.max_addr = exp->saved_addr; ++ nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); ++} ++ ++/****************************************************************************/ ++static int bcm_nat_help(struct sk_buff *skb, unsigned int protoff, ++ struct nf_conn *ct, enum ip_conntrack_info ctinfo) ++{ ++ int dir = CTINFO2DIR(ctinfo); ++ struct nf_conn_help *help = nfct_help(ct); ++ struct nf_conntrack_expect *exp; ++ ++ if (dir != IP_CT_DIR_ORIGINAL || ++ help->expecting[NF_CT_EXPECT_CLASS_DEFAULT]) ++ return NF_ACCEPT; ++ ++ pr_debug("bcm_nat: packet[%d bytes] ", skb->len); ++ nf_ct_dump_tuple(&ct->tuplehash[dir].tuple); ++ pr_debug("reply: "); ++ nf_ct_dump_tuple(&ct->tuplehash[!dir].tuple); ++ ++ /* Create expect */ ++ if ((exp = nf_ct_expect_alloc(ct)) == NULL) ++ return NF_ACCEPT; ++ ++ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, AF_INET, NULL, ++ &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_UDP, ++ NULL, &ct->tuplehash[!dir].tuple.dst.u.udp.port); ++ exp->flags = NF_CT_EXPECT_PERMANENT; ++ exp->saved_addr = ct->tuplehash[dir].tuple.src.u3; ++ exp->saved_proto.udp.port = ct->tuplehash[dir].tuple.src.u.udp.port; ++ exp->dir = !dir; ++ exp->expectfn = bcm_nat_expect; ++ ++ /* Setup expect */ ++ nf_ct_expect_related(exp, 0); ++ nf_ct_expect_put(exp); ++ pr_debug("bcm_nat: expect setup\n"); ++ ++ return NF_ACCEPT; ++} ++ ++/****************************************************************************/ ++static struct nf_conntrack_expect_policy bcm_nat_exp_policy __read_mostly = { ++ .max_expected = 1000, ++ .timeout = 240, ++}; ++ ++/****************************************************************************/ ++static struct nf_conntrack_helper nf_conntrack_helper_bcm_nat __read_mostly = { ++ .name = "BCM-NAT", ++ .me = THIS_MODULE, ++ .tuple.src.l3num = AF_INET, ++ .tuple.dst.protonum = IPPROTO_UDP, ++ .expect_policy = &bcm_nat_exp_policy, ++ .expect_class_max = 1, ++ .help = bcm_nat_help, ++}; ++ ++/****************************************************************************/ ++static inline int find_exp(__be32 ip, __be16 port, struct nf_conn *ct) ++{ ++ struct nf_conntrack_tuple tuple; ++ struct nf_conntrack_expect *i = NULL; ++ ++ ++ memset(&tuple, 0, sizeof(tuple)); ++ tuple.src.l3num = AF_INET; ++ tuple.dst.protonum = IPPROTO_UDP; ++ tuple.dst.u3.ip = ip; ++ tuple.dst.u.udp.port = port; ++ ++ rcu_read_lock(); ++ i = __nf_ct_expect_find(nf_ct_net(ct), nf_ct_zone(ct), &tuple); ++ rcu_read_unlock(); ++ ++ return i != NULL; ++} ++ ++/****************************************************************************/ ++static inline struct nf_conntrack_expect *find_fullcone_exp(struct nf_conn *ct) ++{ ++ struct nf_conntrack_tuple * tp = ++ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_expect * exp = NULL; ++ struct nf_conntrack_expect * i; ++ unsigned int h; ++ ++ rcu_read_lock(); ++ for (h = 0; h < nf_ct_expect_hsize; h++) { ++ hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) { ++ if (nf_inet_addr_cmp(&i->saved_addr, &tp->src.u3) && ++ i->saved_proto.all == tp->src.u.all && ++ i->tuple.dst.protonum == tp->dst.protonum && ++ i->tuple.src.u3.ip == 0 && ++ i->tuple.src.u.udp.port == 0) { ++ exp = i; ++ break; ++ } ++ } ++ } ++ rcu_read_unlock(); ++ ++ return exp; ++} ++ + unsigned int + nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, + const struct nf_nat_range2 *range, +@@ -61,6 +187,72 @@ nf_nat_masquerade_ipv4(struct sk_buff *s + if (nat) + nat->masq_index = out->ifindex; + ++/* RFC 4787 - 4.2.2. Port Parity ++ i.e., an even port will be mapped to an even port, and an odd port will be mapped to an odd port. ++*/ ++#define CHECK_PORT_PARITY(a, b) ((a%2)==(b%2)) ++ if (range->min_addr.ip != 0 /* nat_mode == full cone */ ++ && (nfct_help(ct) == NULL || nfct_help(ct)->helper == NULL) ++ && nf_ct_protonum(ct) == IPPROTO_UDP) { ++ unsigned int ret; ++ u_int16_t minport; ++ u_int16_t maxport; ++ struct nf_conntrack_expect *exp; ++ ++ pr_debug("bcm_nat: need full cone NAT\n"); ++ ++ /* Choose port */ ++ spin_lock_bh(&nf_conntrack_expect_lock); ++ /* Look for existing expectation */ ++ exp = find_fullcone_exp(ct); ++ if (exp) { ++ minport = maxport = exp->tuple.dst.u.udp.port; ++ pr_debug("bcm_nat: existing mapped port = %hu\n", ++ ntohs(minport)); ++ } else { /* no previous expect */ ++ u_int16_t newport, tmpport, orgport; ++ ++ minport = range->min_proto.all == 0? ++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src. ++ u.udp.port : range->min_proto.all; ++ maxport = range->max_proto.all == 0? ++ htons(65535) : range->max_proto.all; ++ orgport = ntohs(minport); ++ for (newport = ntohs(minport),tmpport = ntohs(maxport); ++ newport <= tmpport; newport++) { ++ if (CHECK_PORT_PARITY(orgport, newport) && !find_exp(newsrc, htons(newport), ct)) { ++ pr_debug("bcm_nat: new mapped port = " ++ "%hu\n", newport); ++ minport = maxport = htons(newport); ++ break; ++ } ++ } ++ } ++ spin_unlock_bh(&nf_conntrack_expect_lock); ++ ++ ++ memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); ++ memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); ++ ++ newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS | ++ NF_NAT_RANGE_PROTO_SPECIFIED; ++ newrange.max_addr.ip = newrange.min_addr.ip = newsrc; ++ newrange.min_proto.udp.port = newrange.max_proto.udp.port = minport; ++ ++ /* Set ct helper */ ++ ret = nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); ++ if (ret == NF_ACCEPT) { ++ struct nf_conn_help *help = nfct_help(ct); ++ if (help == NULL) ++ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); ++ if (help != NULL) { ++ help->helper = &nf_conntrack_helper_bcm_nat; ++ pr_debug("bcm_nat: helper set\n"); ++ } ++ } ++ return ret; ++ } ++ + /* Transfer from original range. */ + memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); + memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); +@@ -352,6 +544,7 @@ EXPORT_SYMBOL_GPL(nf_nat_masquerade_inet + + void nf_nat_masquerade_inet_unregister_notifiers(void) + { ++ nf_conntrack_helper_unregister(&nf_conntrack_helper_bcm_nat); + mutex_lock(&masq_mutex); + /* check if the notifiers still have clients */ + if (--masq_refcnt > 0) +--- a/net/netfilter/xt_MASQUERADE.c ++++ b/net/netfilter/xt_MASQUERADE.c +@@ -42,6 +42,9 @@ masquerade_tg(struct sk_buff *skb, const + range.min_proto = mr->range[0].min; + range.max_proto = mr->range[0].max; + ++ range.min_addr.ip = mr->range[0].min_ip; ++ range.max_addr.ip = mr->range[0].max_ip; ++ + return nf_nat_masquerade_ipv4(skb, xt_hooknum(par), &range, + xt_out(par)); + } diff --git a/openwrt/patch/kernel-6.11/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.11/net/983-add-bcm-fullcone-nft_masq-support.patch new file mode 100644 index 000000000..8ab8fba37 --- /dev/null +++ b/openwrt/patch/kernel-6.11/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -0,0 +1,114 @@ +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1481,12 +1481,16 @@ enum nft_tproxy_attributes { + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) ++ * @NFTA_MASQ_REG_ADDR_MIN: source register of address range start (NLA_U32: nft_registers) non zero to enable bcm fullcone ++ * @NFTA_MASQ_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers) + */ + enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, ++ NFTA_MASQ_REG_ADDR_MIN, ++ NFTA_MASQ_REG_ADDR_MAX, + __NFTA_MASQ_MAX + }; + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nft_masq.c ++++ b/net/netfilter/nft_masq.c +@@ -17,6 +17,8 @@ struct nft_masq { + u32 flags; + u8 sreg_proto_min; + u8 sreg_proto_max; ++ u8 sreg_addr_min; // non zero to enable brcm fullconenat ++ u8 sreg_addr_max; + }; + + static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { +@@ -24,6 +26,8 @@ static const struct nla_policy nft_masq_ + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_ADDR_MIN] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_ADDR_MAX] = { .type = NLA_U32 }, + }; + + static int nft_masq_validate(const struct nft_ctx *ctx, +@@ -45,6 +49,7 @@ static int nft_masq_init(const struct nf + const struct nlattr * const tb[]) + { + u32 plen = sizeof_field(struct nf_nat_range, min_proto.all); ++ u32 alen = sizeof_field(struct nf_nat_range, min_addr.all); + struct nft_masq *priv = nft_expr_priv(expr); + int err; + +@@ -68,6 +73,25 @@ static int nft_masq_init(const struct nf + } + } + ++ if (tb[NFTA_MASQ_REG_ADDR_MIN]) { ++ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MIN], ++ &priv->sreg_addr_min, alen); ++ if (err < 0) ++ return err; ++ ++ if (tb[NFTA_MASQ_REG_ADDR_MAX]) { ++ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MAX], ++ &priv->sreg_addr_max, ++ alen); ++ if (err < 0) ++ return err; ++ } else { ++ priv->sreg_addr_max = priv->sreg_addr_min; ++ } ++ ++ priv->flags |= NF_NAT_RANGE_MAP_IPS; ++ } ++ + return nf_ct_netns_get(ctx->net, ctx->family); + } + +@@ -88,6 +112,14 @@ static int nft_masq_dump(struct sk_buff + goto nla_put_failure; + } + ++ if (priv->sreg_addr_min) { ++ if (nft_dump_register(skb, NFTA_MASQ_REG_ADDR_MIN, ++ priv->sreg_addr_min) || ++ nft_dump_register(skb, NFTA_MASQ_REG_ADDR_MAX, ++ priv->sreg_addr_max)) ++ goto nla_put_failure; ++ } ++ + return 0; + + nla_put_failure: +@@ -112,6 +144,12 @@ static void nft_masq_eval(const struct n + + switch (nft_pf(pkt)) { + case NFPROTO_IPV4: ++ if (priv->sreg_addr_min) { ++ range.min_addr.ip = (__force __be32) ++ regs->data[priv->sreg_addr_min]; ++ range.max_addr.ip = (__force __be32) ++ regs->data[priv->sreg_addr_max]; ++ } + regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, + nft_hook(pkt), + &range, +@@ -119,6 +157,12 @@ static void nft_masq_eval(const struct n + break; + #ifdef CONFIG_NF_TABLES_IPV6 + case NFPROTO_IPV6: ++ if (priv->sreg_addr_min) { ++ memcpy(range.min_addr.ip6, ®s->data[priv->sreg_addr_min], ++ sizeof(range.min_addr.ip6)); ++ memcpy(range.max_addr.ip6, ®s->data[priv->sreg_addr_max], ++ sizeof(range.max_addr.ip6)); ++ } + regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, + nft_out(pkt)); + break; diff --git a/openwrt/patch/kernel-6.11/net/README.md b/openwrt/patch/kernel-6.11/net/README.md new file mode 100644 index 000000000..105c48c9f --- /dev/null +++ b/openwrt/patch/kernel-6.11/net/README.md @@ -0,0 +1,15 @@ +# Patches + +## Fullcone + +- [x] Patch 1: [952-net-conntrack-events-support-multiple-registrant.patch](./952-net-conntrack-events-support-multiple-registrant.patch) + +## BCM-Fullcone + +- [x] Patch 1: [982-add-bcm-fullcone-support.patch](./982-add-bcm-fullcone-support.patch) +- [x] Patch 2: [983-add-bcm-fullcone-nft_masq-support.patch](./983-add-bcm-fullcone-nft_masq-support.patch) + +## Shortcut Forwarding Engine + +- [x] Patch 1: [601-netfilter-export-udp_get_timeouts-function.patch](./601-netfilter-export-udp_get_timeouts-function.patch) +- [x] Patch 2: [953-net-patch-linux-kernel-to-support-shortcut-fe.patch](./953-net-patch-linux-kernel-to-support-shortcut-fe.patch) diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch similarity index 99% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch index c6ba231d7..ddd23a2d9 100644 --- a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -708,7 +708,7 @@ Signed-off-by: Alexandre Frade + bytes = min_t(u32, bytes, gso_max_size - 1 - MAX_TCP_HEADER); - segs = max_t(u32, bytes / mss_now, bbr_min_tso_segs(sk)); -+ segs = max_t(u32, bytes / mss_now, ++ segs = max_t(u32, div_u64(bytes, mss_now), + sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); return segs; } diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch diff --git a/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch similarity index 100% rename from openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch rename to openwrt/patch/kernel-6.6/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index a07175d4d..4589a7e87 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2024-08-25 -PKG_SOURCE_VERSION:=904ef52a8d04f6808284011579fdd45418f643d9 -PKG_MIRROR_HASH:=4e285ac767336aab56006fc9f8ca1c35d639926b03de1d6d1667ffc939d81c87 +PKG_SOURCE_DATE:=2024-09-05 +PKG_SOURCE_VERSION:=65cc3daf2a332cc658e9f7438cdadde4392e672e +PKG_MIRROR_HASH:=fa4f75d2b7414b638f01374a6bd149681dac1cc8bbd3f2aa0b2e46415521fc97 PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 diff --git a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch new file mode 100644 index 000000000..b897c2690 --- /dev/null +++ b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch @@ -0,0 +1,298 @@ +--- a/mac80211.c ++++ b/mac80211.c +@@ -582,7 +582,7 @@ int mt76_create_page_pool(struct mt76_de + { + struct page_pool_params pp_params = { + .order = 0, +- .flags = PP_FLAG_PAGE_FRAG, ++ .flags = 0, + .nid = NUMA_NO_NODE, + .dev = dev->dma_dev, + }; +--- a/mt7603/main.c ++++ b/mt7603/main.c +@@ -23,7 +23,7 @@ mt7603_start(struct ieee80211_hw *hw) + } + + static void +-mt7603_stop(struct ieee80211_hw *hw) ++mt7603_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt7603_dev *dev = hw->priv; + +--- a/mt7603/soc.c ++++ b/mt7603/soc.c +@@ -52,15 +52,12 @@ error: + return ret; + } + +-static int +-mt76_wmac_remove(struct platform_device *pdev) ++static void mt76_wmac_remove(struct platform_device *pdev) + { + struct mt76_dev *mdev = platform_get_drvdata(pdev); + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + + mt7603_unregister_device(dev); +- +- return 0; + } + + static const struct of_device_id of_wmac_match[] = { +@@ -74,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2); + + struct platform_driver mt76_wmac_driver = { + .probe = mt76_wmac_probe, +- .remove = mt76_wmac_remove, ++ .remove_new = mt76_wmac_remove, + .driver = { + .name = "mt76_wmac", + .of_match_table = of_wmac_match, +--- a/mt7615/main.c ++++ b/mt7615/main.c +@@ -91,7 +91,7 @@ out: + return ret; + } + +-static void mt7615_stop(struct ieee80211_hw *hw) ++static void mt7615_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); +--- a/mt7615/mt7615_trace.h ++++ b/mt7615/mt7615_trace.h +@@ -14,7 +14,7 @@ + + #define MAXNAME 32 + #define DEV_ENTRY __array(char, wiphy_name, 32) +-#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ ++#define DEV_ASSIGN strscpy(__entry->wiphy_name, \ + wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) + #define DEV_PR_FMT "%s" + #define DEV_PR_ARG __entry->wiphy_name +--- a/mt7615/soc.c ++++ b/mt7615/soc.c +@@ -45,13 +45,11 @@ static int mt7622_wmac_probe(struct plat + return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map); + } + +-static int mt7622_wmac_remove(struct platform_device *pdev) ++static void mt7622_wmac_remove(struct platform_device *pdev) + { + struct mt7615_dev *dev = platform_get_drvdata(pdev); + + mt7615_unregister_device(dev); +- +- return 0; + } + + static const struct of_device_id mt7622_wmac_of_match[] = { +@@ -65,7 +63,7 @@ struct platform_driver mt7622_wmac_drive + .of_match_table = mt7622_wmac_of_match, + }, + .probe = mt7622_wmac_probe, +- .remove = mt7622_wmac_remove, ++ .remove_new = mt7622_wmac_remove, + }; + + MODULE_FIRMWARE(MT7622_FIRMWARE_N9); +--- a/mt7615/usb.c ++++ b/mt7615/usb.c +@@ -79,7 +79,7 @@ static void mt7663u_copy(struct mt76_dev + mutex_unlock(&usb->usb_ctrl_mtx); + } + +-static void mt7663u_stop(struct ieee80211_hw *hw) ++static void mt7663u_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt7615_dev *dev = hw->priv; +--- a/mt76x0/pci.c ++++ b/mt76x0/pci.c +@@ -44,7 +44,7 @@ static void mt76x0e_stop_hw(struct mt76x + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN); + } + +-static void mt76x0e_stop(struct ieee80211_hw *hw) ++static void mt76x0e_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt76x02_dev *dev = hw->priv; + +--- a/mt76x0/usb.c ++++ b/mt76x0/usb.c +@@ -77,7 +77,7 @@ static void mt76x0u_cleanup(struct mt76x + mt76u_queues_deinit(&dev->mt76); + } + +-static void mt76x0u_stop(struct ieee80211_hw *hw) ++static void mt76x0u_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt76x02_dev *dev = hw->priv; + +--- a/mt76x02_trace.h ++++ b/mt76x02_trace.h +@@ -14,7 +14,7 @@ + + #define MAXNAME 32 + #define DEV_ENTRY __array(char, wiphy_name, 32) +-#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ ++#define DEV_ASSIGN strscpy(__entry->wiphy_name, \ + wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) + #define DEV_PR_FMT "%s" + #define DEV_PR_ARG __entry->wiphy_name +--- a/mt76x2/pci_main.c ++++ b/mt76x2/pci_main.c +@@ -24,7 +24,7 @@ mt76x2_start(struct ieee80211_hw *hw) + } + + static void +-mt76x2_stop(struct ieee80211_hw *hw) ++mt76x2_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt76x02_dev *dev = hw->priv; + +--- a/mt76x2/usb_main.c ++++ b/mt76x2/usb_main.c +@@ -22,7 +22,7 @@ static int mt76x2u_start(struct ieee8021 + return 0; + } + +-static void mt76x2u_stop(struct ieee80211_hw *hw) ++static void mt76x2u_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt76x02_dev *dev = hw->priv; + +--- a/mt7915/main.c ++++ b/mt7915/main.c +@@ -108,7 +108,7 @@ static int mt7915_start(struct ieee80211 + return ret; + } + +-static void mt7915_stop(struct ieee80211_hw *hw) ++static void mt7915_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); +--- a/mt7915/mcu.c ++++ b/mt7915/mcu.c +@@ -335,7 +335,7 @@ mt7915_mcu_cca_finish(void *priv, u8 *ma + if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) + return; + +- ieee80211_color_change_finish(vif); ++ ieee80211_color_change_finish(vif, 0); + } + + static void +--- a/mt7921/main.c ++++ b/mt7921/main.c +@@ -268,7 +268,7 @@ static int mt7921_start(struct ieee80211 + return err; + } + +-static void mt7921_stop(struct ieee80211_hw *hw) ++static void mt7921_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err = 0; +@@ -281,7 +281,7 @@ static void mt7921_stop(struct ieee80211 + return; + } + +- mt792x_stop(hw); ++ mt792x_stop(hw, false); + } + + static int +--- a/mt792x.h ++++ b/mt792x.h +@@ -337,7 +337,7 @@ static inline bool mt792x_dma_need_reini + #define mt792x_mutex_release(dev) \ + mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) + +-void mt792x_stop(struct ieee80211_hw *hw); ++void mt792x_stop(struct ieee80211_hw *hw, bool suspend); + void mt792x_pm_wake_work(struct work_struct *work); + void mt792x_pm_power_save_work(struct work_struct *work); + void mt792x_reset(struct mt76_dev *mdev); +@@ -457,7 +457,7 @@ void mt792xu_wr(struct mt76_dev *dev, u3 + u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val); + void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len); + void mt792xu_disconnect(struct usb_interface *usb_intf); +-void mt792xu_stop(struct ieee80211_hw *hw); ++void mt792xu_stop(struct ieee80211_hw *hw, bool suspend); + + static inline void + mt792x_skb_add_usb_sdio_hdr(struct mt792x_dev *dev, struct sk_buff *skb, +--- a/mt792x_core.c ++++ b/mt792x_core.c +@@ -113,7 +113,7 @@ void mt792x_tx(struct ieee80211_hw *hw, + } + EXPORT_SYMBOL_GPL(mt792x_tx); + +-void mt792x_stop(struct ieee80211_hw *hw) ++void mt792x_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); +--- a/mt792x_usb.c ++++ b/mt792x_usb.c +@@ -285,12 +285,12 @@ int mt792xu_init_reset(struct mt792x_dev + } + EXPORT_SYMBOL_GPL(mt792xu_init_reset); + +-void mt792xu_stop(struct ieee80211_hw *hw) ++void mt792xu_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + mt76u_stop_tx(&dev->mt76); +- mt792x_stop(hw); ++ mt792x_stop(hw, false); + } + EXPORT_SYMBOL_GPL(mt792xu_stop); + +--- a/mt7996/main.c ++++ b/mt7996/main.c +@@ -93,7 +93,7 @@ static int mt7996_start(struct ieee80211 + return ret; + } + +-static void mt7996_stop(struct ieee80211_hw *hw) ++static void mt7996_stop(struct ieee80211_hw *hw, bool suspend) + { + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy = mt7996_hw_phy(hw); +--- a/mt7996/mcu.c ++++ b/mt7996/mcu.c +@@ -421,7 +421,7 @@ mt7996_mcu_cca_finish(void *priv, u8 *ma + if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) + return; + +- ieee80211_color_change_finish(vif); ++ ieee80211_color_change_finish(vif, 0); + } + + static void +--- a/trace.h ++++ b/trace.h +@@ -14,7 +14,7 @@ + + #define MAXNAME 32 + #define DEV_ENTRY __array(char, wiphy_name, 32) +-#define DEVICE_ASSIGN strlcpy(__entry->wiphy_name, \ ++#define DEVICE_ASSIGN strscpy(__entry->wiphy_name, \ + wiphy_name(dev->hw->wiphy), MAXNAME) + #define DEV_PR_FMT "%s" + #define DEV_PR_ARG __entry->wiphy_name +--- a/usb_trace.h ++++ b/usb_trace.h +@@ -14,7 +14,7 @@ + + #define MAXNAME 32 + #define DEV_ENTRY __array(char, wiphy_name, 32) +-#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ ++#define DEV_ASSIGN strscpy(__entry->wiphy_name, \ + wiphy_name(dev->hw->wiphy), MAXNAME) + #define DEV_PR_FMT "%s " + #define DEV_PR_ARG __entry->wiphy_name diff --git a/openwrt/patch/openwrt-6.x/modules/crypto.mk b/openwrt/patch/openwrt-6.x/modules/crypto.mk index 43330bf06..4f42eb357 100644 --- a/openwrt/patch/openwrt-6.x/modules/crypto.mk +++ b/openwrt/patch/openwrt-6.x/modules/crypto.mk @@ -243,7 +243,7 @@ $(eval $(call KernelPackage,crypto-ecdh)) define KernelPackage/crypto-echainiv TITLE:=Encrypted Chain IV Generator - DEPENDS:=+kmod-crypto-aead +LINUX_6_6:kmod-crypto-geniv + DEPENDS:=+kmod-crypto-aead +kmod-crypto-geniv KCONFIG:=CONFIG_CRYPTO_ECHAINIV FILES:=$(LINUX_DIR)/crypto/echainiv.ko AUTOLOAD:=$(call AutoLoad,09,echainiv) @@ -888,7 +888,7 @@ $(eval $(call KernelPackage,crypto-rmd160)) define KernelPackage/crypto-rng TITLE:=CryptoAPI random number generation - DEPENDS:=+kmod-crypto-hash +kmod-crypto-hmac +kmod-crypto-sha512 +LINUX_6_6:kmod-crypto-sha3 + DEPENDS:=+kmod-crypto-hash +kmod-crypto-hmac +kmod-crypto-sha512 +kmod-crypto-sha3 KCONFIG:= \ CONFIG_CRYPTO_DRBG \ CONFIG_CRYPTO_DRBG_HMAC=y \ @@ -910,7 +910,7 @@ $(eval $(call KernelPackage,crypto-rng)) define KernelPackage/crypto-geniv TITLE:=CryptoAPI Shared IV generator HIDDEN:=1 - DEPENDS:=+kmod-crypto-rng +kmod-crypto-aead @LINUX_6_6 + DEPENDS:=+kmod-crypto-rng +kmod-crypto-aead KCONFIG:=CONFIG_CRYPTO_GENIV FILES:=$(LINUX_DIR)/crypto/geniv.ko AUTOLOAD:=$(call AutoLoad,09,geniv) @@ -922,7 +922,7 @@ $(eval $(call KernelPackage,crypto-geniv)) define KernelPackage/crypto-seqiv TITLE:=CryptoAPI Sequence Number IV Generator - DEPENDS:=+kmod-crypto-aead +kmod-crypto-rng +LINUX_6_6:kmod-crypto-geniv + DEPENDS:=+kmod-crypto-aead +kmod-crypto-rng +kmod-crypto-geniv KCONFIG:=CONFIG_CRYPTO_SEQIV FILES:=$(LINUX_DIR)/crypto/seqiv.ko AUTOLOAD:=$(call AutoLoad,09,seqiv) @@ -1137,7 +1137,7 @@ $(eval $(call KernelPackage,crypto-test)) define KernelPackage/crypto-user TITLE:=CryptoAPI userspace interface - DEPENDS:=+kmod-crypto-hash +kmod-crypto-manager +LINUX_6_6:kmod-crypto-rng + DEPENDS:=+kmod-crypto-hash +kmod-crypto-manager +kmod-crypto-rng KCONFIG:= \ CONFIG_CRYPTO_USER \ CONFIG_CRYPTO_USER_API \ diff --git a/openwrt/patch/openwrt-6.x/modules/fs.mk b/openwrt/patch/openwrt-6.x/modules/fs.mk index 02fd06eaa..c4930e7f2 100644 --- a/openwrt/patch/openwrt-6.x/modules/fs.mk +++ b/openwrt/patch/openwrt-6.x/modules/fs.mk @@ -10,7 +10,7 @@ FS_MENU:=Filesystems define KernelPackage/fs-9p SUBMENU:=$(FS_MENU) TITLE:=Plan 9 Resource Sharing Support - DEPENDS:=+kmod-9pnet +LINUX_6_6:kmod-fs-netfs + DEPENDS:=+kmod-9pnet +kmod-fs-netfs KCONFIG:=\ CONFIG_9P_FS \ CONFIG_9P_FS_POSIX_ACL=n \ @@ -87,7 +87,7 @@ define KernelPackage/fs-smbfs-common SUBMENU:=$(FS_MENU) TITLE:=SMBFS common dependencies support HIDDEN:=1 - DEPENDS:=+LINUX_6_6:kmod-fs-netfs +LINUX_6_6:kmod-nls-ucs2-utils + DEPENDS:=+kmod-fs-netfs +kmod-nls-ucs2-utils KCONFIG:=\ CONFIG_SMBFS_COMMON@lt6.1 \ CONFIG_SMBFS@ge6.1 @@ -344,7 +344,7 @@ define KernelPackage/fs-jfs KCONFIG:=CONFIG_JFS_FS FILES:=$(LINUX_DIR)/fs/jfs/jfs.ko AUTOLOAD:=$(call AutoLoad,30,jfs,1) - DEPENDS:=+LINUX_6_6:kmod-nls-ucs2-utils + DEPENDS:=+kmod-nls-ucs2-utils $(call AddDepends/nls) endef @@ -569,6 +569,7 @@ $(eval $(call KernelPackage,fs-nfsd)) define KernelPackage/fs-ntfs SUBMENU:=$(FS_MENU) TITLE:=NTFS filesystem read-only (old driver) support + DEPENDS:=@LINUX_6_6 KCONFIG:=CONFIG_NTFS_FS FILES:=$(LINUX_DIR)/fs/ntfs/ntfs.ko AUTOLOAD:=$(call AutoLoad,30,ntfs) @@ -717,7 +718,7 @@ define KernelPackage/pstore CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y FILES:= $(LINUX_DIR)/fs/pstore/pstore.ko AUTOLOAD:=$(call AutoLoad,30,pstore,1) - DEPENDS:=+LINUX_6_6:kmod-lib-zlib-deflate +LINUX_6_6:kmod-lib-zlib-inflate + DEPENDS:=+kmod-lib-zlib-deflate +kmod-lib-zlib-inflate endef define KernelPackage/pstore/description diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index 6fdbf5d94..a7eea8623 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -10,6 +10,7 @@ HWMON_MENU:=Hardware Monitoring Support define KernelPackage/hwmon-core SUBMENU:=$(HWMON_MENU) TITLE:=Hardware monitoring support + DEPENDS:=+LINUX_6_11:kmod-i2c-core KCONFIG:= \ CONFIG_HWMON \ CONFIG_HWMON_DEBUG_CHIP=n @@ -34,7 +35,7 @@ define KernelPackage/hwmon-ad7418 KCONFIG:=CONFIG_SENSORS_AD7418 FILES:=$(LINUX_DIR)/drivers/hwmon/ad7418.ko AUTOLOAD:=$(call AutoLoad,60,ad7418 ad7418) - $(call AddDepends/hwmon,+kmod-i2c-core +LINUX_6_6:kmod-regmap-core) + $(call AddDepends/hwmon,+kmod-i2c-core +kmod-regmap-core) endef define KernelPackage/hwmon-ad7418/description @@ -130,7 +131,7 @@ define KernelPackage/hwmon-emc2305 KCONFIG:=CONFIG_SENSORS_EMC2305 FILES:=$(LINUX_DIR)/drivers/hwmon/emc2305.ko AUTOLOAD:=$(call AutoProbe,emc2305) - $(call AddDepends/hwmon,+kmod-i2c-core +PACKAGE_kmod-thermal:kmod-thermal +kmod-regmap-i2c @LINUX_6_1||LINUX_6_6) + $(call AddDepends/hwmon,+kmod-i2c-core +PACKAGE_kmod-thermal:kmod-thermal +kmod-regmap-i2c) endef define KernelPackage/hwmon-emc2305/description diff --git a/openwrt/patch/openwrt-6.x/modules/i2c.mk b/openwrt/patch/openwrt-6.x/modules/i2c.mk index 3aaf560ea..d1bdfffcb 100644 --- a/openwrt/patch/openwrt-6.x/modules/i2c.mk +++ b/openwrt/patch/openwrt-6.x/modules/i2c.mk @@ -150,7 +150,7 @@ I2C_I801_MODULES:= \ define KernelPackage/i2c-i801 $(call i2c_defaults,$(I2C_I801_MODULES),59) TITLE:=Intel I801 and compatible I2C interfaces - DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus + DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus +LINUX_6_11:kmod-i2c-mux endef define KernelPackage/i2c-i801/description @@ -289,7 +289,7 @@ I2C_PIIX4_MODULES:= \ define KernelPackage/i2c-piix4 $(call i2c_defaults,$(I2C_PIIX4_MODULES),59) TITLE:=Intel PIIX4 and compatible I2C interfaces - DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core + DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +LINUX_6_11:kmod-i2c-smbus endef define KernelPackage/i2c-piix4/description diff --git a/openwrt/patch/openwrt-6.x/modules/iio.mk b/openwrt/patch/openwrt-6.x/modules/iio.mk index 7cf0952db..e46544b79 100644 --- a/openwrt/patch/openwrt-6.x/modules/iio.mk +++ b/openwrt/patch/openwrt-6.x/modules/iio.mk @@ -383,7 +383,7 @@ $(eval $(call KernelPackage,iio-st_accel-spi)) define KernelPackage/iio-lsm6dsx - DEPENDS:=+kmod-iio-kfifo-buf +kmod-regmap-core +LINUX_6_6:kmod-industrialio-triggered-buffer + DEPENDS:=+kmod-iio-kfifo-buf +kmod-regmap-core +kmod-industrialio-triggered-buffer TITLE:=ST LSM6DSx driver for IMU MEMS sensors KCONFIG:=CONFIG_IIO_ST_LSM6DSX FILES:=$(LINUX_DIR)/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.ko diff --git a/openwrt/patch/openwrt-6.x/modules/input.mk b/openwrt/patch/openwrt-6.x/modules/input.mk index 89fba2900..4eafc7d6b 100644 --- a/openwrt/patch/openwrt-6.x/modules/input.mk +++ b/openwrt/patch/openwrt-6.x/modules/input.mk @@ -179,7 +179,7 @@ $(eval $(call KernelPackage,input-touchscreen-ads7846)) define KernelPackage/input-touchscreen-edt-ft5x06 SUBMENU:=$(INPUT_MODULES_MENU) TITLE:=EDT FT5x06 and Focaltech FT6236 based touchscreens - DEPENDS:=+kmod-i2c-core +kmod-input-core +LINUX_6_6:kmod-regmap-i2c + DEPENDS:=+kmod-i2c-core +kmod-input-core +kmod-regmap-i2c KCONFIG:= \ CONFIG_INPUT_TOUCHSCREEN=y \ CONFIG_TOUCHSCREEN_EDT_FT5X06 diff --git a/openwrt/patch/openwrt-6.x/modules/lib.mk b/openwrt/patch/openwrt-6.x/modules/lib.mk index 11f02fd21..8f0821590 100644 --- a/openwrt/patch/openwrt-6.x/modules/lib.mk +++ b/openwrt/patch/openwrt-6.x/modules/lib.mk @@ -385,7 +385,7 @@ $(eval $(call KernelPackage,lib-parman)) define KernelPackage/libwx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Wangxun(R) Ethernet driver common library - DEPENDS:=@PCI_SUPPORT @LINUX_6_6 + DEPENDS:=@PCI_SUPPORT +kmod-phylink KCONFIG:=CONFIG_LIBWX FILES:=$(LINUX_DIR)/drivers/net/ethernet/wangxun/libwx/libwx.ko AUTOLOAD:=$(call AutoProbe,libwx) diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index 579b772d2..ab95b3774 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -108,6 +108,37 @@ endef $(eval $(call KernelPackage,libphy)) +define KernelPackage/libie + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Intel Ethernet library + DEPENDS:=@LINUX_6_11 + KCONFIG:=CONFIG_LIBIE + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie.ko + AUTOLOAD:=$(call AutoLoad,15,libie,1) +endef + +define KernelPackage/libie/description + Intel Ethernet library +endef + +$(eval $(call KernelPackage,libie)) + + +define KernelPackage/libeth + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Intel Ethernet common library + DEPENDS:=@LINUX_6_11 + KCONFIG:=CONFIG_LIBETH + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libeth/libeth.ko + AUTOLOAD:=$(call AutoLoad,15,libeth,1) +endef + +define KernelPackage/libeth/description +endef + +$(eval $(call KernelPackage,libeth)) + + define KernelPackage/phylink SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Model for MAC to optional PHY connection @@ -363,7 +394,7 @@ define KernelPackage/phy-smsc SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=SMSC PHY driver KCONFIG:=CONFIG_SMSC_PHY - DEPENDS:=+kmod-libphy +LINUX_6_6:kmod-lib-crc16 + DEPENDS:=+kmod-libphy +kmod-lib-crc16 FILES:=$(LINUX_DIR)/drivers/net/phy/smsc.ko AUTOLOAD:=$(call AutoProbe,smsc) endef @@ -395,7 +426,7 @@ $(eval $(call KernelPackage,phy-airoha-en8811h)) define KernelPackage/phy-aquantia SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Aquantia Ethernet PHYs - DEPENDS:=+kmod-libphy +kmod-hwmon-core +kmod-lib-crc-ccitt + DEPENDS:=+kmod-libphy +kmod-hwmon-core +kmod-lib-crc-ccitt +LINUX_6_11:kmod-lib-crc-itu-t KCONFIG:=CONFIG_AQUANTIA_PHY FILES:=$(LINUX_DIR)/drivers/net/phy/aquantia/aquantia.ko AUTOLOAD:=$(call AutoLoad,18,aquantia,1) @@ -939,7 +970,7 @@ $(eval $(call KernelPackage,ixgbevf)) define KernelPackage/i40e SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) Ethernet Controller XL710 Family support - DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy + DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +LINUX_6_11:kmod-libie KCONFIG:=CONFIG_I40E \ CONFIG_I40E_VXLAN=n \ CONFIG_I40E_HWMON=y \ @@ -958,7 +989,7 @@ $(eval $(call KernelPackage,i40e)) define KernelPackage/iavf SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) Ethernet Adaptive Virtual Function support - DEPENDS:=@PCI_SUPPORT + DEPENDS:=@PCI_SUPPORT +LINUX_6_11:kmod-libie +LINUX_6_11:kmod-libeth KCONFIG:= \ CONFIG_I40EVF \ CONFIG_IAVF @@ -1393,7 +1424,7 @@ $(eval $(call KernelPackage,mlx4-core)) define KernelPackage/mlx5-core SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Mellanox ConnectX(R) mlx5 core Network Driver - DEPENDS:=@PCI_SUPPORT +kmod-ptp +kmod-mlxfw +LINUX_6_6:kmod-hwmon-core + DEPENDS:=@PCI_SUPPORT +kmod-ptp +kmod-mlxfw +kmod-hwmon-core FILES:=$(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko KCONFIG:= CONFIG_MLX5_CORE \ CONFIG_MLX5_CORE_EN=y \ @@ -1594,7 +1625,7 @@ $(eval $(call KernelPackage,sfp)) define KernelPackage/pcs-xpcs SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Synopsis DesignWare PCS driver - DEPENDS:=+kmod-phylink + DEPENDS:=+kmod-phylink +kmod-mdio-devres KCONFIG:=CONFIG_PCS_XPCS FILES:=$(LINUX_DIR)/drivers/net/pcs/pcs_xpcs.ko AUTOLOAD:=$(call AutoLoad,20,pcs_xpcs) @@ -1606,7 +1637,7 @@ $(eval $(call KernelPackage,pcs-xpcs)) define KernelPackage/stmmac-core SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Synopsis Ethernet Controller core (NXP,STMMicro,others) - DEPENDS:=@TARGET_x86_64||TARGET_armsr_armv8 +kmod-pcs-xpcs +LINUX_6_6:kmod-of-mdio +kmod-ptp + DEPENDS:=@TARGET_x86_64||TARGET_armsr_armv8 +kmod-pcs-xpcs +kmod-of-mdio +kmod-ptp KCONFIG:=CONFIG_STMMAC_ETH \ CONFIG_STMMAC_SELFTESTS=n \ CONFIG_STMMAC_PLATFORM \ @@ -1806,7 +1837,7 @@ $(eval $(call KernelPackage,amazon-ena)) define KernelPackage/ngbe SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Wangxun(R) GbE PCI Express adapters support - DEPENDS:=@PCI_SUPPORT +kmod-libwx + DEPENDS:=@PCI_SUPPORT +kmod-libwx kmod-mdio-devres KCONFIG:=CONFIG_NGBE FILES:=$(LINUX_DIR)/drivers/net/ethernet/wangxun/ngbe/ngbe.ko AUTOLOAD:=$(call AutoProbe,ngbe) diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index ac455287e..d3baa3726 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -910,7 +910,6 @@ $(eval $(call KernelPackage,sched-ipset)) define KernelPackage/sched-mqprio-common SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=mqprio queue common dependencies support - DEPENDS:=@LINUX_6_6 HIDDEN:=1 KCONFIG:=CONFIG_NET_SCH_MQPRIO_LIB FILES:=$(LINUX_DIR)/net/sched/sch_mqprio_lib.ko @@ -926,7 +925,7 @@ $(eval $(call KernelPackage,sched-mqprio-common)) define KernelPackage/sched-mqprio SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Multi-queue priority scheduler (MQPRIO) - DEPENDS:=+kmod-sched-core +LINUX_6_6:kmod-sched-mqprio-common + DEPENDS:=+kmod-sched-core +kmod-sched-mqprio-common KCONFIG:=CONFIG_NET_SCH_MQPRIO FILES:=$(LINUX_DIR)/net/sched/sch_mqprio.ko AUTOLOAD:=$(call AutoProbe, sch_mqprio) @@ -1359,6 +1358,7 @@ $(eval $(call KernelPackage,mpls)) define KernelPackage/9pnet SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Plan 9 Resource Sharing Support (9P2000) + DEPENDS:=+LINUX_6_11:kmod-fs-netfs KCONFIG:= \ CONFIG_NET_9P \ CONFIG_NET_9P_DEBUG=n \ diff --git a/openwrt/patch/openwrt-6.x/modules/nls.mk b/openwrt/patch/openwrt-6.x/modules/nls.mk index 893ec9c23..e4817af61 100644 --- a/openwrt/patch/openwrt-6.x/modules/nls.mk +++ b/openwrt/patch/openwrt-6.x/modules/nls.mk @@ -344,7 +344,6 @@ $(eval $(call KernelPackage,nls-utf8)) define KernelPackage/nls-ucs2-utils SUBMENU:=Native Language Support TITLE:=UCS-2 common library - DEPENDS+=@LINUX_6_6 HIDDEN:=1 KCONFIG:=CONFIG_NLS_UCS2_UTILS FILES:=$(LINUX_DIR)/fs/nls/nls_ucs2_utils.ko diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index e27e036e0..98bb8a01f 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -148,7 +148,7 @@ define KernelPackage/dma-buf KCONFIG:=CONFIG_DMA_SHARED_BUFFER ifeq ($(strip $(CONFIG_EXTERNAL_KERNEL_TREE)),"") ifeq ($(strip $(CONFIG_KERNEL_GIT_CLONE_URI)),"") - FILES:=$(LINUX_DIR)/drivers/dma-buf/dma-shared-buffer.ko + FILES:=$(LINUX_DIR)/drivers/dma-buf/dma-shared-buffer.ko@le6.6 endif endif AUTOLOAD:=$(call AutoLoad,20,dma-shared-buffer) diff --git a/openwrt/patch/openwrt-6.x/modules/sound.mk b/openwrt/patch/openwrt-6.x/modules/sound.mk index 623f65ac5..e8d86809a 100644 --- a/openwrt/patch/openwrt-6.x/modules/sound.mk +++ b/openwrt/patch/openwrt-6.x/modules/sound.mk @@ -378,7 +378,8 @@ define KernelPackage/sound-hda-codec-realtek KCONFIG:= \ CONFIG_SND_HDA_CODEC_REALTEK FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-realtek.ko + $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-realtek.ko \ + $(LINUX_DIR)/sound/pci/hda/snd-hda-scodec-component.ko@ge6.11 AUTOLOAD:=$(call AutoProbe,snd-hda-codec-realtek) $(call AddDepends/sound,kmod-sound-hda-core) endef diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index 9bea8093c..24ae03668 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -661,7 +661,6 @@ define KernelPackage/usb-serial-ch348 KCONFIG:=CONFIG_USB_SERIAL_CH348 FILES:=$(LINUX_DIR)/drivers/usb/serial/ch348.ko AUTOLOAD:=$(call AutoProbe,ch348) - DEPENDS:=@LINUX_6_6 $(call AddDepends/usb-serial) endef @@ -1201,7 +1200,7 @@ define KernelPackage/usb-net-asix TITLE:=Kernel module for USB-to-Ethernet Asix convertors DEPENDS:= \ +kmod-libphy +kmod-net-selftests +kmod-mdio-devres +kmod-phy-ax88796b \ - +LINUX_6_1:kmod-phylink +LINUX_6_6:kmod-phylink + +LINUX_6_1:kmod-phylink +kmod-phylink KCONFIG:=CONFIG_USB_NET_AX8817X FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/asix.ko AUTOLOAD:=$(call AutoProbe,asix) @@ -1622,7 +1621,7 @@ define KernelPackage/usb-hid-mcp2221 SUBMENU:=$(USB_MENU) TITLE:=Microchip USB 2.0 to I2C/UART Protocol Converter with GPIO KCONFIG:=CONFIG_HID_MCP2221 - DEPENDS:=@GPIO_SUPPORT +kmod-usb-hid +kmod-i2c-core +LINUX_6_6:kmod-iio-core + DEPENDS:=@GPIO_SUPPORT +kmod-usb-hid +kmod-i2c-core +kmod-iio-core FILES:=$(LINUX_DIR)/drivers/hid/hid-mcp2221.ko AUTOLOAD:=$(call AutoProbe,hid-mcp2221) endef diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index c9533d5e7..a29c19fd9 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -102,7 +102,7 @@ define KernelPackage/fb CONFIG_VT_CONSOLE=y \ CONFIG_VT_HW_CONSOLE_BINDING=y FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb.ko \ - $(LINUX_DIR)/drivers/video/fbdev/core/fb_io_fops.ko \ + $(LINUX_DIR)/drivers/video/fbdev/core/fb_io_fops.ko@lt6.11 \ $(LINUX_DIR)/lib/fonts/font.ko AUTOLOAD:=$(call AutoLoad,06,fb font) endef @@ -112,7 +112,7 @@ define KernelPackage/fb/description endef define KernelPackage/fb/x86 - FILES+=$(LINUX_DIR)/arch/x86/video/fbdev.ko + FILES+=$(LINUX_DIR)/arch/x86/video/fbdev.ko@lt6.11 AUTOLOAD:=$(call AutoLoad,06,fbdev fb font) endef @@ -170,7 +170,9 @@ define KernelPackage/fb-sys-fops SUBMENU:=$(VIDEO_MENU) TITLE:=Framebuffer software sys ops support DEPENDS:=+kmod-fb - KCONFIG:=CONFIG_FB_SYS_FOPS + KCONFIG:= \ + CONFIG_FB_SYS_FOPS@lt6.11 \ + CONFIG_FB_SYSMEM_FOPS@ge6.11 FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb_sys_fops.ko AUTOLOAD:=$(call AutoLoad,07,fb_sys_fops) endef @@ -283,7 +285,7 @@ $(eval $(call KernelPackage,drm)) define KernelPackage/drm-buddy SUBMENU:=$(VIDEO_MENU) TITLE:=A page based buddy allocator - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm @LINUX_6_1||LINUX_6_6 + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm KCONFIG:=CONFIG_DRM_BUDDY FILES:= $(LINUX_DIR)/drivers/gpu/drm/drm_buddy.ko AUTOLOAD:=$(call AutoProbe,drm_buddy) @@ -298,7 +300,7 @@ $(eval $(call KernelPackage,drm-buddy)) define KernelPackage/drm-display-helper SUBMENU:=$(VIDEO_MENU) TITLE:=DRM helpers for display adapters drivers - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper @LINUX_6_1||LINUX_6_6 + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper KCONFIG:=CONFIG_DRM_DISPLAY_HELPER FILES:=$(LINUX_DIR)/drivers/gpu/drm/display/drm_display_helper.ko AUTOLOAD:=$(call AutoProbe,drm_display_helper) @@ -313,7 +315,7 @@ $(eval $(call KernelPackage,drm-display-helper)) define KernelPackage/drm-gem-shmem-helper SUBMENU:=$(VIDEO_MENU) TITLE:=GEM shmem helper functions - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm +kmod-drm-kms-helper +kmod-fb-sys-fops +kmod-fb-sys-ram KCONFIG:=CONFIG_DRM_GEM_SHMEM_HELPER FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_shmem_helper.ko AUTOLOAD:=$(call AutoProbe,drm_shmem_helper) @@ -325,7 +327,7 @@ define KernelPackage/drm-exec SUBMENU:=$(VIDEO_MENU) HIDDEN:=1 TITLE:=Execution context for command submissions - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm @LINUX_6_6 + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm KCONFIG:=CONFIG_DRM_EXEC FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_exec.ko AUTOLOAD:=$(call AutoProbe,drm_exec) @@ -389,7 +391,7 @@ define KernelPackage/drm-suballoc-helper SUBMENU:=$(VIDEO_MENU) HIDDEN:=1 TITLE:=DRM suballocation helper - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm @LINUX_6_6 + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm KCONFIG:=CONFIG_DRM_SUBALLOC_HELPER FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_suballoc_helper.ko AUTOLOAD:=$(call AutoProbe,drm_suballoc_helper) @@ -407,7 +409,7 @@ define KernelPackage/drm-amdgpu DEPENDS:=@TARGET_x86 @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-ttm \ +kmod-drm-ttm-helper +kmod-drm-kms-helper +kmod-i2c-algo-bit +amdgpu-firmware \ +kmod-drm-display-helper +kmod-drm-buddy +kmod-acpi-video \ - +LINUX_6_6:kmod-drm-exec +LINUX_6_6:kmod-drm-suballoc-helper + +kmod-drm-exec +kmod-drm-suballoc-helper KCONFIG:=CONFIG_DRM_AMDGPU \ CONFIG_DRM_AMDGPU_SI=y \ CONFIG_DRM_AMDGPU_CIK=y \ @@ -570,7 +572,7 @@ define KernelPackage/drm-radeon TITLE:=Radeon DRM support DEPENDS:=@TARGET_x86 @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-kms-helper \ +kmod-drm-ttm +kmod-drm-ttm-helper +kmod-i2c-algo-bit +radeon-firmware \ - +kmod-drm-display-helper +kmod-acpi-video +LINUX_6_6:kmod-drm-suballoc-helper + +kmod-drm-display-helper +kmod-acpi-video +kmod-drm-suballoc-helper KCONFIG:=CONFIG_DRM_RADEON FILES:=$(LINUX_DIR)/drivers/gpu/drm/radeon/radeon.ko AUTOLOAD:=$(call AutoProbe,radeon) @@ -1335,7 +1337,7 @@ define KernelPackage/drm-i915 SUBMENU:=$(VIDEO_MENU) TITLE:=Intel GPU drm support DEPENDS:=@TARGET_x86 +kmod-drm-buddy +kmod-drm-ttm +kmod-drm-kms-helper +i915-firmware \ - +LINUX_6_6:kmod-drm-display-helper +LINUX_6_6:kmod-acpi-video + +kmod-drm-display-helper +kmod-acpi-video KCONFIG:= \ CONFIG_INTEL_GTT \ CONFIG_DRM_I915 \ diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.11 b/openwrt/patch/openwrt-6.x/x86/64/config-6.11 new file mode 100644 index 000000000..211bdc52e --- /dev/null +++ b/openwrt/patch/openwrt-6.x/x86/64/config-6.11 @@ -0,0 +1,664 @@ +CONFIG_64BIT=y +# CONFIG_ACER_WMI is not set +CONFIG_ACPI_AC=y +CONFIG_ACPI_BATTERY=y +# CONFIG_ACPI_BGRT is not set +CONFIG_ACPI_BUTTON=y +# CONFIG_ACPI_CMPC is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_CPPC_LIB=y +CONFIG_ACPI_CPU_FREQ_PSS=y +# CONFIG_ACPI_DEBUGGER is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_DOCK is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +CONFIG_ACPI_FAN=y +# CONFIG_ACPI_FFH is not set +# CONFIG_ACPI_FPDT is not set +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_MADT_WAKEUP=y +CONFIG_ACPI_PCC=y +# CONFIG_ACPI_PCI_SLOT is not set +# CONFIG_ACPI_PFRUT is not set +CONFIG_ACPI_PRMT=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y +# CONFIG_ACPI_SBS is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_THERMAL_LIB=y +CONFIG_ACPI_THERMAL=y +# CONFIG_ACPI_TOSHIBA is not set +CONFIG_ACPI_VIDEO=y +CONFIG_ACPI_VIOT=y +CONFIG_ACPI_WMI=y +CONFIG_ACPI=y +# CONFIG_ACRN_GUEST is not set +# CONFIG_ADDRESS_MASKING is not set +# CONFIG_ADV_SWBUTTON is not set +# CONFIG_AGP_AMD64 is not set +CONFIG_AGP_INTEL=y +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_VIA is not set +CONFIG_AGP=y +# CONFIG_AMD_HSMP is not set +CONFIG_AMD_IOMMU_V2=y +CONFIG_AMD_IOMMU=y +# CONFIG_AMD_PMC is not set +# CONFIG_AMD_PMF is not set +# CONFIG_AMD_PTDMA is not set +# CONFIG_AMD_SFH_HID is not set +CONFIG_APERTURE_HELPERS=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_ASUS_TF103C_DOCK is not set +# CONFIG_ASUS_WMI is not set +CONFIG_AUDIT_ARCH=y +CONFIG_AUXILIARY_BUS=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BALLOON_COMPACTION=y +CONFIG_BLK_DEV_BSG_COMMON=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY_T10=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_NVME=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_PM=y +CONFIG_BOOT_VESA_SUPPORT=y +CONFIG_BTT=y +CONFIG_CALL_DEPTH_TRACKING=y +CONFIG_CALL_PADDING=y +# CONFIG_CALL_THUNKS_DEBUG is not set +CONFIG_CALL_THUNKS=y +CONFIG_CDROM=y +CONFIG_CONNECTOR=y +CONFIG_CONTEXT_TRACKING_IDLE=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_IBPB_ENTRY=y +CONFIG_CPU_IBRS_ENTRY=y +# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set +CONFIG_CPU_RMAP=y +CONFIG_CPU_SRSO=y +CONFIG_CPU_UNRET_ENTRY=y +CONFIG_CRC64_ROCKSOFT=y +CONFIG_CRC64=y +CONFIG_CRC_T10DIF=y +CONFIG_CRYPTO_AES_NI_INTEL=y +CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y +# CONFIG_CRYPTO_ARIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_ARIA_GFNI_AVX512_X86_64 is not set +CONFIG_CRYPTO_BLAKE2S_X86=y +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +CONFIG_CRYPTO_CRC64_ROCKSOFT=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_CRYPTD=y +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +CONFIG_CRYPTO_LRW=y +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_POLYVAL_CLMUL_NI is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +CONFIG_CRYPTO_SIMD=y +# CONFIG_CRYPTO_SM3_AVX_X86_64 is not set +# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +CONFIG_CRYPTO_XTS=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_OPS=y +CONFIG_DMAR_TABLE=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DRM_AMDGPU_WERROR is not set +# CONFIG_DRM_AMD_SECURE_DISPLAY is not set +CONFIG_DRM_BOCHS=y +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_BUDDY=y +CONFIG_DRM_DISPLAY_DP_HELPER=y +CONFIG_DRM_DISPLAY_HDCP_HELPER=y +CONFIG_DRM_DISPLAY_HDMI_HELPER=y +CONFIG_DRM_DISPLAY_HELPER=y +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +CONFIG_DRM_GEM_SHMEM_HELPER=y +# CONFIG_DRM_HYPERV is not set +CONFIG_DRM_I915_FENCE_TIMEOUT=10000 +CONFIG_DRM_I915_FORCE_PROBE="" +CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500 +CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000 +CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 +CONFIG_DRM_I915_REQUEST_TIMEOUT=20000 +CONFIG_DRM_I915_STOP_TIMEOUT=100 +CONFIG_DRM_I915_TIMESLICE_DURATION=1 +CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 +CONFIG_DRM_KMS_HELPER=y +CONFIG_DRM_MIPI_DSI=y +CONFIG_DRM_PANEL_BRIDGE=y +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y +CONFIG_DRM_PANEL=y +CONFIG_DRM_TTM_HELPER=y +CONFIG_DRM_TTM=y +CONFIG_DRM_VIRTIO_GPU_KMS=y +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_DRM_VRAM_HELPER=y +CONFIG_DRM=y +CONFIG_DYNAMIC_PHYSICAL_MASK=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_COCO_SECRET is not set +# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# CONFIG_EFI_DISABLE_RUNTIME is not set +CONFIG_EFI_DXE_MEM_ATTRIBUTES=y +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_ESRT=y +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_HANDOVER_PROTOCOL=y +# CONFIG_EFI_MIXED is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_EFI_RCI2_TABLE is not set +CONFIG_EFI_RUNTIME_MAP=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_SECRET is not set +CONFIG_EFI_STUB=y +# CONFIG_EFI_TEST is not set +CONFIG_EFIVAR_FS=m +# CONFIG_EFI_VARS is not set +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set +# CONFIG_EFI_VARS_PSTORE is not set +CONFIG_EFI=y +CONFIG_FAILOVER=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CORE=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_DEVICE=y +CONFIG_FB_EFI=y +CONFIG_FB_HYPERV=y +# CONFIG_FB_INTEL is not set +CONFIG_FB_IOMEM_FOPS=y +CONFIG_FB_IOMEM_HELPERS=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_SIMPLE=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_SYS_IMAGEBLIT=y +CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y +CONFIG_FB_SYSMEM_HELPERS=y +CONFIG_FB_TILEBLITTING=y +# CONFIG_FB_VESA is not set +CONFIG_FB=y +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FREEZER=y +CONFIG_FUSION_SAS=y +CONFIG_FW_CACHE=y +CONFIG_GART_IOMMU=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CPU=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_GIGABYTE_WMI is not set +# CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT is not set +# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set +# CONFIG_GOOGLE_SMI is not set +CONFIG_GPIO_ACPI=y +CONFIG_GPIO_ICH=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_SCH=y +CONFIG_GUEST_PERF_EVENTS=y +CONFIG_HALTPOLL_CPUIDLE=y +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +CONFIG_HDMI=y +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HID_GENERIC=y +CONFIG_HID_HYPERV_MOUSE=y +CONFIG_HOTPLUG_CORE_SYNC_DEAD=y +CONFIG_HOTPLUG_CORE_SYNC_FULL=y +CONFIG_HOTPLUG_CORE_SYNC=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HOTPLUG_PARALLEL=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_PCIE is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_SMT=y +CONFIG_HOTPLUG_SPLIT_STARTUP=y +# CONFIG_HP_ACCEL is not set +CONFIG_HPET_MMAP=y +CONFIG_HPET=y +# CONFIG_HUAWEI_WMI is not set +CONFIG_HVC_DRIVER=y +CONFIG_HVC_IRQ=y +CONFIG_HVC_XEN_FRONTEND=y +CONFIG_HVC_XEN=y +CONFIG_HWMON_VID=y +CONFIG_HWMON=y +CONFIG_HW_RANDOM_AMD=y +CONFIG_HW_RANDOM_INTEL=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HYPERV_BALLOON=y +CONFIG_HYPERV_IOMMU=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_HYPERV_KEYBOARD=y +CONFIG_HYPERV_NET=y +CONFIG_HYPERV_STORAGE=y +# CONFIG_HYPERV_TESTING is not set +CONFIG_HYPERV_TIMER=y +CONFIG_HYPERV_UTILS=y +# CONFIG_HYPERV_VSOCKETS is not set +# CONFIG_HYPERV_VTL_MODE is not set +CONFIG_HYPERV=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_AMD_MP2 is not set +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_HID_ACPI is not set +# CONFIG_I2C_MULTI_INSTANTIATE is not set +CONFIG_I2C=y +# CONFIG_I8K is not set +# CONFIG_IA32_EMULATION is not set +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y +CONFIG_INTEL_GTT=y +CONFIG_INTEL_IDLE=y +# CONFIG_INTEL_IDXD_COMPAT is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IFS is not set +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +CONFIG_INTEL_IOMMU_PERF_EVENTS=y +# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set +# CONFIG_INTEL_IOMMU_SVM is not set +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_MEI_GSC_PROXY is not set +# CONFIG_INTEL_MEI_HDCP is not set +# CONFIG_INTEL_MEI_PXP is not set +# CONFIG_INTEL_MENLOW is not set +CONFIG_INTEL_PCH_THERMAL=y +# CONFIG_INTEL_SAR_INT1092 is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +CONFIG_INTEL_SOC_DTS_IOSF_CORE=y +CONFIG_INTEL_SOC_DTS_THERMAL=y +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +CONFIG_INTEL_TCC=y +CONFIG_INTEL_TDX_GUEST=y +# CONFIG_INTEL_TURBO_MAX_3 is not set +# CONFIG_INTEL_TXT is not set +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set +# CONFIG_INTEL_WMI_THUNDERBOLT is not set +CONFIG_INTERVAL_TREE=y +CONFIG_IOMMU_API=y +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEBUG is not set +CONFIG_IOMMU_DEFAULT_DMA_LAZY=y +# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_IOMMU_DMA=y +# CONFIG_IOMMUFD is not set +CONFIG_IOMMU_HELPER=y +CONFIG_IOMMU_IO_PGTABLE=y +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_SUPPORT=y +# CONFIG_IOSF_MBI_DEBUG is not set +CONFIG_IOSF_MBI=y +# CONFIG_IPU_BRIDGE is not set +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_IRQ_REMAP=y +# CONFIG_ISCSI_IBFT is not set +CONFIG_ISO9660_FS=y +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KCMP=y +# CONFIG_KMSAN is not set +CONFIG_KVM_GUEST=y +# CONFIG_KVM_XEN is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEGACY_VSYSCALL_EMULATE is not set +CONFIG_LEGACY_VSYSCALL_NONE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LENOVO_YMC is not set +# CONFIG_LG_LAPTOP is not set +CONFIG_LIBNVDIMM=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LPC_ICH=y +CONFIG_LPC_SCH=y +CONFIG_MAILBOX=y +# CONFIG_MAXSMP is not set +CONFIG_MEMORY_BALLOON=y +CONFIG_MEMREGION=y +# CONFIG_MERAKI_MX100 is not set +CONFIG_MFD_CORE=y +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_CQHCI=y +CONFIG_MMC_RICOH_MMC=y +CONFIG_MMC_SDHCI_ACPI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_PCI=y +# CONFIG_MMC_SDHCI_PLTFM is not set +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_WBSD is not set +CONFIG_MMC=y +CONFIG_MMU_NOTIFIER=y +CONFIG_MODULES_USE_ELF_RELA=y +# CONFIG_MPSC is not set +# CONFIG_MSI_EC is not set +# CONFIG_MSI_WMI is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_MXM_WMI is not set +CONFIG_ND_CLAIM=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_SG_DMA_FLAGS=y +CONFIG_NET_FAILOVER=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NITRO_ENCLAVES is not set +CONFIG_NR_CPUS=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +# CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set +CONFIG_NVME_CORE=y +CONFIG_NVME_HWMON=y +CONFIG_NVME_MULTIPATH=y +CONFIG_OBJTOOL=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_P2SB=y +CONFIG_PADATA=y +CONFIG_PAGE_REPORTING=y +CONFIG_PAGE_TABLE_ISOLATION=y +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_PARAVIRT_DEBUG is not set +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_PARAVIRT_XXL=y +CONFIG_PARAVIRT=y +CONFIG_PATA_AMD=y +CONFIG_PATA_ATIIXP=y +CONFIG_PATA_MPIIX=y +CONFIG_PATA_OLDPIIX=y +CONFIG_PATA_TIMINGS=y +CONFIG_PATA_VIA=y +CONFIG_PCC=y +# CONFIG_PCENGINES_APU2 is not set +CONFIG_PCIEAER=y +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_PERFORMANCE is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEASPM=y +CONFIG_PCIE_PME=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCI_HYPERV_INTERFACE=y +CONFIG_PCI_HYPERV=y +# CONFIG_PCI_MMCONFIG is not set +CONFIG_PCI_PASID=y +CONFIG_PCI_PRI=y +CONFIG_PCI_XEN=y +CONFIG_PER_VMA_LOCK=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_PINCTRL_ALDERLAKE=y +CONFIG_PINCTRL_BAYTRAIL=y +CONFIG_PINCTRL_BROXTON=y +CONFIG_PINCTRL_CANNONLAKE=y +CONFIG_PINCTRL_CHERRYVIEW=y +CONFIG_PINCTRL_DENVERTON=y +CONFIG_PINCTRL_ELKHARTLAKE=y +CONFIG_PINCTRL_EMMITSBURG=y +CONFIG_PINCTRL_GEMINILAKE=y +CONFIG_PINCTRL_INTEL=y +CONFIG_PINCTRL_JASPERLAKE=y +CONFIG_PINCTRL_LAKEFIELD=y +CONFIG_PINCTRL_LEWISBURG=y +CONFIG_PINCTRL_LYNXPOINT=y +CONFIG_PINCTRL_METEORLAKE=y +CONFIG_PINCTRL_SUNRISEPOINT=y +CONFIG_PINCTRL_TIGERLAKE=y +CONFIG_PINCTRL=y +CONFIG_PM_CLK=y +# CONFIG_PMIC_OPREGION is not set +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_PM=y +CONFIG_PNPACPI=y +CONFIG_PNP_DEBUG_MESSAGES=y +CONFIG_PNP=y +CONFIG_PPS=y +CONFIG_PREFIX_SYMBOLS=y +CONFIG_PROC_EVENTS=y +CONFIG_PTP_1588_CLOCK_KVM=y +CONFIG_PTP_1588_CLOCK_VMW=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PVH=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_RAS=y +CONFIG_RELAY=y +CONFIG_RELOCATABLE=y +CONFIG_RESET_ATTACK_MITIGATION=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SAMSUNG_Q10 is not set +CONFIG_SATA_AHCI=y +# CONFIG_SCHED_CORE is not set +CONFIG_SCHED_MC_PRIO=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_VIRTIO=y +# CONFIG_SEL3350_PLATFORM is not set +# CONFIG_SENSORS_ASUS_EC is not set +# CONFIG_SENSORS_ASUS_WMI is not set +CONFIG_SENSORS_CORETEMP=y +CONFIG_SENSORS_FAM15H_POWER=y +# CONFIG_SENSORS_HP_WMI is not set +CONFIG_SENSORS_I5500=y +CONFIG_SENSORS_K10TEMP=y +CONFIG_SENSORS_K8TEMP=y +# CONFIG_SENSORS_OXP is not set +CONFIG_SENSORS_VIA_CPUTEMP=y +CONFIG_SERIAL_8250_PNP=y +# CONFIG_SERIAL_MULTI_INSTANTIATE is not set +CONFIG_SLS=y +CONFIG_SMP=y +# CONFIG_SND_HDA_CTL_DEV_ID is not set +# CONFIG_SND_HDA_SCODEC_CS35L41_I2C is not set +# CONFIG_SND_HDA_SCODEC_CS35L41_SPI is not set +# CONFIG_SND_HDA_SCODEC_CS35L56_I2C is not set +# CONFIG_SND_HDA_SCODEC_CS35L56_SPI is not set +# CONFIG_SND_HDA_SCODEC_TAS2781_I2C is not set +# CONFIG_SND_SOC_AMD_ACP6x is not set +# CONFIG_SND_SOC_AMD_ACP_COMMON is not set +# CONFIG_SND_SOC_AMD_PS is not set +# CONFIG_SND_SOC_AMD_RPL_ACP6x is not set +# CONFIG_SND_SOC_INTEL_AVS is not set +CONFIG_SOCK_RX_QUEUE_MAPPING=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +# CONFIG_SPARSEMEM_VMEMMAP is not set +CONFIG_SPARSEMEM=y +CONFIG_STACK_VALIDATION=y +CONFIG_SWIOTLB_XEN=y +CONFIG_SWIOTLB=y +CONFIG_SYNC_FILE=y +CONFIG_SYSFB=y +CONFIG_SYS_HYPERVISOR=y +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TDX_GUEST_DRIVER is not set +CONFIG_THERMAL_ACPI=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +# CONFIG_THINKPAD_LMI is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_WMI is not set +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +# CONFIG_UACCE is not set +# CONFIG_UCLAMP_TASK is not set +CONFIG_UCS2_STRING=y +CONFIG_UNACCEPTED_MEMORY=y +# CONFIG_UNWINDER_ORC is not set +CONFIG_USB_STORAGE=y +CONFIG_VIDEO_CMDLINE=y +# CONFIG_VIDEO_IPU3_CIO2 is not set +CONFIG_VIDEO_NOMODESET=y +CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO_ANCHOR=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_DMA_SHARED_BUFFER=y +CONFIG_VIRTIO_IOMMU=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PCI_LIB_LEGACY=y +CONFIG_VIRTIO_PCI_LIB=y +CONFIG_VIRTIO_PCI=y +# CONFIG_VIRTIO_PMEM is not set +CONFIG_VIRTIO_VSOCKETS_COMMON=y +# CONFIG_VIRTIO_VSOCKETS is not set +CONFIG_VIRTIO=y +CONFIG_VMAP_PFN=y +CONFIG_VMAP_STACK=y +# CONFIG_VMD is not set +CONFIG_VMGENID=y +CONFIG_VMWARE_BALLOON=y +CONFIG_VMWARE_PVSCSI=y +CONFIG_VMWARE_VMCI_VSOCKETS=y +CONFIG_VMWARE_VMCI=y +CONFIG_VMXNET3=y +CONFIG_VSOCKETS_LOOPBACK=y +CONFIG_VSOCKETS=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WIRELESS_HOTKEY is not set +# CONFIG_WMI_BMOF is not set +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_64_SMP=y +CONFIG_X86_64=y +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +CONFIG_X86_ACPI_CPUFREQ=y +CONFIG_X86_AMD_FREQ_SENSITIVITY=y +CONFIG_X86_AMD_PLATFORM_DEVICE=y +CONFIG_X86_AMD_PSTATE_DEFAULT_MODE=3 +# CONFIG_X86_AMD_PSTATE_UT is not set +CONFIG_X86_AMD_PSTATE=y +CONFIG_X86_CPUID=y +CONFIG_X86_DIRECT_GBPAGES=y +CONFIG_X86_HV_CALLBACK_VECTOR=y +CONFIG_X86_INTEL_LPSS=y +# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set +CONFIG_X86_INTEL_PSTATE=y +# CONFIG_X86_KERNEL_IBT is not set +CONFIG_X86_MEM_ENCRYPT=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +# CONFIG_X86_PCC_CPUFREQ is not set +CONFIG_X86_PKG_TEMP_THERMAL=y +# CONFIG_X86_PMEM_LEGACY is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_SGX is not set +# CONFIG_X86_USER_SHADOW_STACK is not set +# CONFIG_X86_VSYSCALL_EMULATION is not set +CONFIG_X86_X2APIC=y +# CONFIG_X86_X32_ABI is not set +# CONFIG_X86_X32 is not set +CONFIG_XEN_512GB=y +CONFIG_XEN_ACPI_PROCESSOR=y +CONFIG_XEN_ACPI=y +CONFIG_XEN_AUTO_XLATE=y +# CONFIG_XEN_BACKEND is not set +CONFIG_XEN_BALLOON=y +CONFIG_XEN_BLKDEV_FRONTEND=y +CONFIG_XEN_COMPAT_XENFS=y +CONFIG_XEN_DEBUG_FS=y +CONFIG_XEN_DEV_EVTCHN=y +CONFIG_XEN_DOM0=y +CONFIG_XEN_EFI=y +CONFIG_XEN_FBDEV_FRONTEND=y +CONFIG_XENFS=y +CONFIG_XEN_GNTDEV=y +CONFIG_XEN_GRANT_DEV_ALLOC=y +CONFIG_XEN_GRANT_DMA_OPS=y +CONFIG_XEN_HAVE_PVMMU=y +CONFIG_XEN_HAVE_VPMU=y +# CONFIG_XEN_MCE_LOG is not set +CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_PCIDEV_FRONTEND=y +# CONFIG_XEN_PRIVCMD_IRQFD is not set +CONFIG_XEN_PRIVCMD=y +CONFIG_XEN_PV_DOM0=y +CONFIG_XEN_PVHVM_GUEST=y +CONFIG_XEN_PVHVM_SMP=y +CONFIG_XEN_PVHVM=y +CONFIG_XEN_PVH=y +CONFIG_XEN_PV_MSR_SAFE=y +CONFIG_XEN_PV_SMP=y +CONFIG_XEN_PV=y +CONFIG_XEN_SAVE_RESTORE=y +CONFIG_XEN_SCSI_FRONTEND=y +CONFIG_XEN_SYMS=y +CONFIG_XEN_SYS_HYPERVISOR=y +# CONFIG_XEN_VIRTIO_FORCE_GRANT is not set +CONFIG_XEN_VIRTIO=y +CONFIG_XEN_WDT=y +CONFIG_XEN_XENBUS_FRONTEND=y +CONFIG_XEN=y +# CONFIG_XIAOMI_WMI is not set +CONFIG_XPS=y +# CONFIG_YOGABOOK is not set +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZONE_DMA32=y diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.11 b/openwrt/patch/openwrt-6.x/x86/config-6.11 new file mode 100644 index 000000000..342a3d614 --- /dev/null +++ b/openwrt/patch/openwrt-6.x/x86/config-6.11 @@ -0,0 +1,515 @@ +# CONFIG_60XX_WDT is not set +# CONFIG_64BIT is not set +# CONFIG_ACPI is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_EC_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIX is not set +CONFIG_AMD_NB=y +# CONFIG_AMD_WBRF is not set +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPLIT_ARG64=y +CONFIG_ARCH_STACKWALK=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_ARCH_WANTS_NO_INSTR=y +CONFIG_ATA_GENERIC=y +CONFIG_ATA_PIIX=y +CONFIG_ATA=y +# CONFIG_BARCO_P50_GPIO is not set +# CONFIG_BASE_SMALL is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BOUNCE=y +CONFIG_BUFFER_HEAD=y +CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" +CONFIG_CC_NO_ARRAY_BOUNDS=y +CONFIG_CLKBLD_I8253=y +CONFIG_CLKEVT_I8253=y +CONFIG_CLKSRC_I8253=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100 +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_COMPAT_32=y +# CONFIG_COMPAT_VDSO is not set +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_CPU5_WDT is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_MITIGATIONS=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_CPU_SUP_CYRIX_32=y +CONFIG_CPU_SUP_HYGON=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_TRANSMETA_32=y +CONFIG_CPU_SUP_UMC_32=y +CONFIG_CPU_SUP_VORTEX_32=y +CONFIG_CPU_SUP_ZHAOXIN=y +CONFIG_CRASH_CORE=y +# CONFIG_CRASH_HOTPLUG is not set +CONFIG_CRC16=y +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +CONFIG_CRYPTO_LIB_GF128MUL=y +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1 +CONFIG_CRYPTO_LIB_SHA1=y +CONFIG_CRYPTO_LIB_UTILS=y +# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set +# CONFIG_CX_ECAT is not set +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_DEBUG_ENTRY is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP is not set +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_MISC=y +# CONFIG_DEBUG_NMI_SELFTEST is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DMADEVICES=y +CONFIG_DMIID=y +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +CONFIG_DMI_SYSFS=y +CONFIG_DMI=y +CONFIG_DNOTIFY=y +# CONFIG_DRM_AMD_ISP is not set +# CONFIG_DRM_I915_DEBUG_WAKEREF is not set +# CONFIG_DRM_I915_GVT_KVMGT is not set +# CONFIG_DRM_I915_REPLAY_GPU_HANGS_API is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DYNAMIC_SIGFRAME=y +# CONFIG_EARLY_PRINTK_DBGP is not set +CONFIG_EARLY_PRINTK=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +# CONFIG_EDD is not set +# CONFIG_EISA is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_EXAR_WDT is not set +CONFIG_EXCLUSIVE_SYSTEM_RAM=y +CONFIG_EXT4_FS=y +CONFIG_F2FS_FS=y +# CONFIG_F71808E_WDT is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FRAME_POINTER=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FUNCTION_ALIGNMENT=16 +CONFIG_FUNCTION_ALIGNMENT_16B=y +CONFIG_FUNCTION_PADDING_BYTES=16 +CONFIG_FUNCTION_PADDING_CFI=11 +# CONFIG_FUN_ETH is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LOGGING is not set +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SPI=y +CONFIG_FUSION=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_FW_LOADER_SYSFS=y +CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y +# CONFIG_GDS_FORCE_MITIGATION is not set +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_ENTRY=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_VDSO_32=y +# CONFIG_GEOS is not set +CONFIG_GLOB=y +CONFIG_GPIO_CDEV=y +# CONFIG_GPIO_DS4520 is not set +# CONFIG_GPIO_ELKHARTLAKE is not set +# CONFIG_GPIO_SIM is not set +# CONFIG_GPIO_VIRTIO is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_HARDENED_USERCOPY is not set +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_IOPORT=y +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPET_TIMER=y +# CONFIG_HP_WATCHDOG is not set +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM_GEODE=y +CONFIG_HW_RANDOM_VIA=y +CONFIG_HW_RANDOM=y +# CONFIG_HYPERVISOR_GUEST is not set +CONFIG_HZ_PERIODIC=y +CONFIG_I8253_LOCK=y +CONFIG_IA32_FEAT_CTL=y +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_IBM_RTL is not set +# CONFIG_IE6XX_WDT is not set +CONFIG_ILLEGAL_POINTER_VALUE=0 +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_VIVALDIFMAP=y +CONFIG_INPUT=y +# CONFIG_INSPUR_PLATFORM_PROFILE is not set +CONFIG_INSTRUCTION_DECODER=y +# CONFIG_INTEL_HFI_THERMAL is not set +# CONFIG_INTEL_LDMA is not set +# CONFIG_INTEL_PCH_THERMAL is not set +# CONFIG_INTEL_POWERCLAMP is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_TCC_COOLING is not set +# CONFIG_INTEL_VSEC is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IOSF_MBI is not set +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_ISA_DMA_API=y +# CONFIG_ISA is not set +# CONFIG_IT8712F_WDT is not set +# CONFIG_IT87_WDT is not set +# CONFIG_ITCO_WDT is not set +CONFIG_JBD2=y +CONFIG_KALLSYMS=y +CONFIG_KEXEC_CORE=y +CONFIG_KEXEC=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KMAP_LOCAL=y +# CONFIG_KVM_PROVE_MMU is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_M486 is not set +# CONFIG_M486SX is not set +# CONFIG_M586 is not set +# CONFIG_M586MMX is not set +# CONFIG_M586TSC is not set +CONFIG_M686=y +# CONFIG_MACHZ_WDT is not set +# CONFIG_MATOM is not set +# CONFIG_MCORE2 is not set +# CONFIG_MCRUSOE is not set +# CONFIG_MCYRIXIII is not set +# CONFIG_MEEGOPAD_ANX7428 is not set +# CONFIG_MEFFICEON is not set +# CONFIG_MELAN is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +# CONFIG_MICROCODE_LATE_FORCE_MINREV is not set +CONFIG_MICROCODE_LATE_LOADING=y +CONFIG_MICROCODE=y +CONFIG_MIGRATION=y +# CONFIG_MITIGATION_GDS_FORCE is not set +# CONFIG_MITIGATION_IBPB_ENTRY is not set +# CONFIG_MITIGATION_IBRS_ENTRY is not set +# CONFIG_MITIGATION_PAGE_TABLE_ISOLATION is not set +# CONFIG_MITIGATION_RETPOLINE is not set +CONFIG_MITIGATION_RFDS=y +# CONFIG_MITIGATION_SLS is not set +CONFIG_MITIGATION_SPECTRE_BHI=y +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +CONFIG_MMU_GATHER_MERGE_VMAS=y +CONFIG_MMU_LAZY_TLB_REFCOUNT=y +# CONFIG_MODIFY_LDT_SYSCALL is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MPENTIUM4 is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MTD is not set +# CONFIG_MTRR_SANITIZER is not set +CONFIG_MTRR=y +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MWINCHIPC6 is not set +CONFIG_NAMESPACES=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_KM=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_NEED_SG_DMA_LENGTH=y +# CONFIG_NET5501 is not set +CONFIG_NET_EGRESS=y +CONFIG_NET_INGRESS=y +# CONFIG_NET_NS is not set +# CONFIG_NET_VENDOR_META is not set +CONFIG_NET_XGRESS=y +CONFIG_NLS=y +# CONFIG_NMI_CHECK_CPU is not set +# CONFIG_NOHIGHMEM is not set +CONFIG_NR_CPUS=1 +CONFIG_NR_CPUS_DEFAULT=1 +CONFIG_NR_CPUS_RANGE_BEGIN=1 +CONFIG_NR_CPUS_RANGE_END=1 +# CONFIG_NSC_GPIO is not set +# CONFIG_NSM is not set +CONFIG_NVRAM=y +# CONFIG_OCTEON_EP is not set +# CONFIG_OF is not set +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +# CONFIG_OLPC is not set +CONFIG_OUTPUT_FORMAT="elf32-i386" +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PAGE_POOL=y +CONFIG_PAGE_SIZE_LESS_THAN_256KB=y +CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y +CONFIG_PC104=y +# CONFIG_PC8736x_GPIO is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_PCENGINES_APU2 is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_BIOS=y +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_GOANY=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +# CONFIG_PCI_GOMMCONFIG is not set +CONFIG_PCI_IOV=y +CONFIG_PCI_LABEL=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_MSI=y +CONFIG_PCI=y +CONFIG_PCSPKR_PLATFORM=y +# CONFIG_PERF_EVENTS_AMD_BRS is not set +# CONFIG_PERF_EVENTS_AMD_UNCORE is not set +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS=y +CONFIG_PGTABLE_LEVELS=2 +# CONFIG_PHY_INTEL_LGM_EMMC is not set +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_PHYSICAL_START=0x1000000 +# CONFIG_PINCTRL_INTEL_PLATFORM is not set +# CONFIG_PINCTRL_METEORPOINT is not set +# CONFIG_PM_USERSPACE_AUTOSLEEP is not set +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POWER_SUPPLY=y +CONFIG_PREEMPT_NONE_BUILD=y +# CONFIG_PROCESSOR_SELECT is not set +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_PID_ARCH_STATUS=y +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +CONFIG_PTP_1588_CLOCK_OPTIONAL=y +# CONFIG_PUNIT_ATOM_DEBUG is not set +# CONFIG_RANDOM_KMALLOC_CACHES is not set +CONFIG_RANDSTRUCT_NONE=y +CONFIG_RATIONAL=y +CONFIG_RD_BZIP2=y +CONFIG_RD_GZIP=y +CONFIG_RETHUNK=y +CONFIG_RETPOLINE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_SATA_HOST=y +# CONFIG_SBC7240_WDT is not set +# CONFIG_SBC8360_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set +# CONFIG_SC1200_WDT is not set +CONFIG_SCSI_COMMON=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI=y +# CONFIG_SCx200_GPIO is not set +CONFIG_SCx200HR_TIMER=y +# CONFIG_SCx200_WDT is not set +CONFIG_SCx200=y +CONFIG_SERIAL_8250_PCILIB=y +CONFIG_SERIAL_8250_PCI=y +# CONFIG_SERIAL_LANTIQ is not set +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO=y +# CONFIG_SFC_SIENA is not set +CONFIG_SG_POOL=y +# CONFIG_SIEMENS_SIMATIC_IPC is not set +# CONFIG_SILICOM_PLATFORM is not set +# CONFIG_SLAB_BUCKETS is not set +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_SMSC_SCH311X_WDT is not set +CONFIG_SOFTIRQ_ON_OWN_STACK=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPARSEMEM_STATIC=y +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_STATIC_CALL_SELFTEST is not set +# CONFIG_STRICT_SIGALTSTACK_SIZE is not set +CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_SYSFB_SIMPLEFB is not set +# CONFIG_TELCLOCK is not set +# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set +# CONFIG_TEST_DHRY is not set +# CONFIG_TEST_FPU is not set +# CONFIG_TEST_MAPLE_TREE is not set +# CONFIG_TEST_OBJPOOL is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TINY_SRCU=y +# CONFIG_TMPFS_QUOTA is not set +CONFIG_TOOLS_SUPPORT_RELR=y +# CONFIG_TOSHIBA is not set +# CONFIG_TQMX86_WDT is not set +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_UNWINDER_FRAME_POINTER=y +# CONFIG_UNWINDER_GUESS is not set +CONFIG_UP_LATE_INIT=y +CONFIG_USB_COMMON=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_HID=y +# CONFIG_USB_LJCA is not set +CONFIG_USB_OHCI_HCD_PCI=y +# CONFIG_USB_OHCI_HCD_PLATFORM is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_PCI=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_XEN_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB=y +# CONFIG_USER_NS is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_VGA_CONSOLE=y +# CONFIG_VIA_WDT is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VT=y +# CONFIG_WAFER_WDT is not set +# CONFIG_WINMATE_FM07_KEYS is not set +# CONFIG_X86_32_IRIS is not set +CONFIG_X86_32=y +# CONFIG_X86_ANCIENT_MCE is not set +# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set +CONFIG_X86_CMOV=y +CONFIG_X86_CMPXCHG64=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_X86_CPUFREQ_NFORCE2 is not set +# CONFIG_X86_CPUID is not set +# CONFIG_X86_CPU_RESCTRL is not set +CONFIG_X86_DEBUGCTLMSR=y +# CONFIG_X86_DEBUG_FPU is not set +# CONFIG_X86_DECODER_SELFTEST is not set +# CONFIG_X86_EXTENDED_PLATFORM is not set +# CONFIG_X86_FRED is not set +CONFIG_X86_GENERIC=y +# CONFIG_X86_GX_SUSPMOD is not set +# CONFIG_X86_INTEL_PSTATE is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_IO_APIC=y +CONFIG_X86_IOPL_IOPERM=y +CONFIG_X86_L1_CACHE_SHIFT=6 +# CONFIG_X86_LEGACY_VM86 is not set +CONFIG_X86_LOCAL_APIC=y +# CONFIG_X86_LONGRUN is not set +CONFIG_X86_MCE_AMD=y +# CONFIG_X86_MCE_INJECT is not set +CONFIG_X86_MCE_INTEL=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE=y +CONFIG_X86_MINIMUM_CPU_FAMILY=6 +CONFIG_X86_MPPARSE=y +CONFIG_X86_MSR=y +# CONFIG_X86_P4_CLOCKMOD is not set +CONFIG_X86_PAT=y +CONFIG_X86_PLATFORM_DEVICES=y +# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set +# CONFIG_X86_PLATFORM_DRIVERS_HP is not set +# CONFIG_X86_POWERNOW_K6 is not set +# CONFIG_X86_POWERNOW_K7 is not set +# CONFIG_X86_REBOOTFIXUPS is not set +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_SPEEDSTEP_ICH is not set +# CONFIG_X86_SPEEDSTEP_SMI is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +CONFIG_X86_THERMAL_VECTOR=y +CONFIG_X86_TSC=y +CONFIG_X86_UMIP=y +CONFIG_X86_UP_APIC=y +CONFIG_X86_UP_IOAPIC=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_X86=y +# CONFIG_XEN_PRIVCMD_EVENTFD is not set +CONFIG_XZ_DEC_BCJ=y +CONFIG_XZ_DEC_X86=y +CONFIG_ZLIB_INFLATE=y diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch new file mode 100644 index 000000000..d4de2027b --- /dev/null +++ b/openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch @@ -0,0 +1,13 @@ +--- a/drivers/clocksource/timer-cs5535.c ++++ b/drivers/clocksource/timer-cs5535.c +@@ -127,7 +127,9 @@ static irqreturn_t mfgpt_tick(int irq, v + cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, + MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); + +- cs5535_clockevent.event_handler(&cs5535_clockevent); ++ if (cs5535_clockevent.event_handler) ++ cs5535_clockevent.event_handler(&cs5535_clockevent); ++ + return IRQ_HANDLED; + } + diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch new file mode 100644 index 000000000..4e1761b56 --- /dev/null +++ b/openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch @@ -0,0 +1,275 @@ +From 970d9af9015a387bb81841faf05dcc1a171eb97a Mon Sep 17 00:00:00 2001 +From: Philip Prindeville +Date: Sun, 1 Jan 2023 15:25:04 -0700 +Subject: [PATCH v3 1/1] x86: Support APU5 in PCEngines platform driver +To: platform-driver-x86@vger.kernel.org, linux-x86_64@vger.kernel.org +Cc: Ed Wildgoose , Andres Salomon , Andreas Eberlein , Paul Spooren + +PCEngines make a number of SBC. APU5 has 5 mpcie slots + MSATA. +It also has support for 3x LTE modems with 6x SIM slots (pairs with a +SIM switch device). Each mpcie slot for modems has a reset GPIO + +To ensure that the naming is sane between APU2-6 the GPIOS are +renamed to be modem1-reset, modem2-reset, etc. This is significant +because the slots that can be reset change between APU2 and APU3/4 + +GPIO for simswap is moved to the end of the list as it could be dropped +for APU2 boards (but causes no harm to leave it in, hardware could be +added to a future rev of the board). + +Structure of the GPIOs for APU5 is extremely similar to APU2-4, but +many lines are moved around and there are simply more +modems/resets/sim-swap lines to breakout. + +Also added APU6, which is essentially APU4 with a different ethernet +interface and SFP cage on eth0. + +Revision history: + +v1: originally titled, "apu6: add apu6 variation to apu2 driver family" +this dealt only with detecting the APUv6, which is otherwise identical +to the v4 excepting the SFP cage on eth0. + +v2: at Ed's request, merged with his previous pull-request titled +"x86: Support APU5 in PCEngines platform driver", and some cleanup +to that changeset (including dropping the table "apu5_driver_data" +which did not have a defined type "struct apu_driver_data"), but got +mistitled when the Subject of that commit got accidentally dropped. + +v3: retitled to match Ed's previous pull-request. + +Cc: platform-driver-x86@vger.kernel.org +Cc: linux-x86_64@vger.kernel.org +Reviewed-by: Andreas Eberlein +Reviewed-by: Paul Spooren +Signed-off-by: Ed Wildgoose +Sighed-off-by: Philip Prindeville +--- + drivers/leds/leds-apu.c | 2 +- + drivers/platform/x86/Kconfig | 4 +- + drivers/platform/x86/pcengines-apuv2.c | 118 ++++++++++++++++++++++--- + 3 files changed, 107 insertions(+), 17 deletions(-) + +--- a/drivers/leds/leds-apu.c ++++ b/drivers/leds/leds-apu.c +@@ -182,7 +182,7 @@ static int __init apu_led_init(void) + int err; + + if (!dmi_check_system(apu_led_dmi_table)) { +- pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n"); ++ pr_err("No PC Engines APUv1 board detected. For APUv2,3,4,5,6 support, enable CONFIG_PCENGINES_APU2\n"); + return -ENODEV; + } + +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -753,7 +753,7 @@ config XO1_RFKILL + laptop. + + config PCENGINES_APU2 +- tristate "PC Engines APUv2/3 front button and LEDs driver" ++ tristate "PC Engines APUv2/3/4/5/6 front button and LEDs driver" + depends on INPUT && INPUT_KEYBOARD && GPIOLIB + depends on LEDS_CLASS + select GPIO_AMD_FCH +@@ -761,7 +761,7 @@ config PCENGINES_APU2 + select LEDS_GPIO + help + This driver provides support for the front button and LEDs on +- PC Engines APUv2/APUv3 board. ++ PC Engines APUv2/APUv3/APUv4/APUv5/APUv6 board. + + To compile this driver as a module, choose M here: the module + will be called pcengines-apuv2. +--- a/drivers/platform/x86/pcengines-apuv2.c ++++ b/drivers/platform/x86/pcengines-apuv2.c +@@ -1,10 +1,12 @@ + // SPDX-License-Identifier: GPL-2.0+ + + /* +- * PC-Engines APUv2/APUv3 board platform driver ++ * PC-Engines APUv2-6 board platform driver + * for GPIO buttons and LEDs + * + * Copyright (C) 2018 metux IT consult ++ * Copyright (C) 2022 Ed Wildgoose ++ * Copyright (C) 2022 Philip Prindeville + * Author: Enrico Weigelt + */ + +@@ -22,38 +24,70 @@ + #include + + /* +- * NOTE: this driver only supports APUv2/3 - not APUv1, as this one ++ * NOTE: this driver only supports APUv2-6 - not APUv1, as this one + * has completely different register layouts. + */ + ++/* ++ * There are a number of APU variants, with differing features ++ * APU2 has SIM slots 1/2 mapping to mPCIe sockets 1/2 ++ * APU3/4 moved SIM slot 1 to mPCIe socket 3, ie logically reversed ++ * However, most APU3/4 have a SIM switch which we default on to reverse ++ * the order and keep physical SIM order matching physical modem order ++ * APU6 is approximately the same as APU4 with different ethernet layout ++ * ++ * APU5 has 3x SIM sockets, all with a SIM switch ++ * several GPIOs are shuffled (see schematic), including MODESW ++ */ ++ + /* Register mappings */ + #define APU2_GPIO_REG_LED1 AMD_FCH_GPIO_REG_GPIO57 + #define APU2_GPIO_REG_LED2 AMD_FCH_GPIO_REG_GPIO58 + #define APU2_GPIO_REG_LED3 AMD_FCH_GPIO_REG_GPIO59_DEVSLP1 + #define APU2_GPIO_REG_MODESW AMD_FCH_GPIO_REG_GPIO32_GE1 + #define APU2_GPIO_REG_SIMSWAP AMD_FCH_GPIO_REG_GPIO33_GE2 +-#define APU2_GPIO_REG_MPCIE2 AMD_FCH_GPIO_REG_GPIO55_DEVSLP0 +-#define APU2_GPIO_REG_MPCIE3 AMD_FCH_GPIO_REG_GPIO51 ++#define APU2_GPIO_REG_RESETM1 AMD_FCH_GPIO_REG_GPIO51 ++#define APU2_GPIO_REG_RESETM2 AMD_FCH_GPIO_REG_GPIO55_DEVSLP0 ++ ++#define APU5_GPIO_REG_MODESW AMT_FCH_GPIO_REG_GEVT22 ++#define APU5_GPIO_REG_SIMSWAP1 AMD_FCH_GPIO_REG_GPIO68 ++#define APU5_GPIO_REG_SIMSWAP2 AMD_FCH_GPIO_REG_GPIO32_GE1 ++#define APU5_GPIO_REG_SIMSWAP3 AMD_FCH_GPIO_REG_GPIO33_GE2 ++#define APU5_GPIO_REG_RESETM1 AMD_FCH_GPIO_REG_GPIO51 ++#define APU5_GPIO_REG_RESETM2 AMD_FCH_GPIO_REG_GPIO55_DEVSLP0 ++#define APU5_GPIO_REG_RESETM3 AMD_FCH_GPIO_REG_GPIO64 + + /* Order in which the GPIO lines are defined in the register list */ + #define APU2_GPIO_LINE_LED1 0 + #define APU2_GPIO_LINE_LED2 1 + #define APU2_GPIO_LINE_LED3 2 + #define APU2_GPIO_LINE_MODESW 3 +-#define APU2_GPIO_LINE_SIMSWAP 4 +-#define APU2_GPIO_LINE_MPCIE2 5 +-#define APU2_GPIO_LINE_MPCIE3 6 ++#define APU2_GPIO_LINE_RESETM1 4 ++#define APU2_GPIO_LINE_RESETM2 5 ++#define APU2_GPIO_LINE_SIMSWAP 6 ++ ++#define APU5_GPIO_LINE_LED1 0 ++#define APU5_GPIO_LINE_LED2 1 ++#define APU5_GPIO_LINE_LED3 2 ++#define APU5_GPIO_LINE_MODESW 3 ++#define APU5_GPIO_LINE_RESETM1 4 ++#define APU5_GPIO_LINE_RESETM2 5 ++#define APU5_GPIO_LINE_RESETM3 6 ++#define APU5_GPIO_LINE_SIMSWAP1 7 ++#define APU5_GPIO_LINE_SIMSWAP2 8 ++#define APU5_GPIO_LINE_SIMSWAP3 9 ++ + +-/* GPIO device */ ++/* GPIO device - APU2/3/4/6 */ + + static int apu2_gpio_regs[] = { + [APU2_GPIO_LINE_LED1] = APU2_GPIO_REG_LED1, + [APU2_GPIO_LINE_LED2] = APU2_GPIO_REG_LED2, + [APU2_GPIO_LINE_LED3] = APU2_GPIO_REG_LED3, + [APU2_GPIO_LINE_MODESW] = APU2_GPIO_REG_MODESW, ++ [APU2_GPIO_LINE_RESETM1] = APU2_GPIO_REG_RESETM1, ++ [APU2_GPIO_LINE_RESETM2] = APU2_GPIO_REG_RESETM2, + [APU2_GPIO_LINE_SIMSWAP] = APU2_GPIO_REG_SIMSWAP, +- [APU2_GPIO_LINE_MPCIE2] = APU2_GPIO_REG_MPCIE2, +- [APU2_GPIO_LINE_MPCIE3] = APU2_GPIO_REG_MPCIE3, + }; + + static const char * const apu2_gpio_names[] = { +@@ -61,9 +95,9 @@ static const char * const apu2_gpio_name + [APU2_GPIO_LINE_LED2] = "front-led2", + [APU2_GPIO_LINE_LED3] = "front-led3", + [APU2_GPIO_LINE_MODESW] = "front-button", ++ [APU2_GPIO_LINE_RESETM1] = "modem1-reset", ++ [APU2_GPIO_LINE_RESETM2] = "modem2-reset", + [APU2_GPIO_LINE_SIMSWAP] = "simswap", +- [APU2_GPIO_LINE_MPCIE2] = "mpcie2_reset", +- [APU2_GPIO_LINE_MPCIE3] = "mpcie3_reset", + }; + + static const struct amd_fch_gpio_pdata board_apu2 = { +@@ -72,6 +106,40 @@ static const struct amd_fch_gpio_pdata b + .gpio_names = apu2_gpio_names, + }; + ++/* GPIO device - APU5 */ ++ ++static int apu5_gpio_regs[] = { ++ [APU5_GPIO_LINE_LED1] = APU2_GPIO_REG_LED1, ++ [APU5_GPIO_LINE_LED2] = APU2_GPIO_REG_LED2, ++ [APU5_GPIO_LINE_LED3] = APU2_GPIO_REG_LED3, ++ [APU5_GPIO_LINE_MODESW] = APU5_GPIO_REG_MODESW, ++ [APU5_GPIO_LINE_RESETM1] = APU5_GPIO_REG_RESETM1, ++ [APU5_GPIO_LINE_RESETM2] = APU5_GPIO_REG_RESETM2, ++ [APU5_GPIO_LINE_RESETM3] = APU5_GPIO_REG_RESETM3, ++ [APU5_GPIO_LINE_SIMSWAP1] = APU5_GPIO_REG_SIMSWAP1, ++ [APU5_GPIO_LINE_SIMSWAP2] = APU5_GPIO_REG_SIMSWAP2, ++ [APU5_GPIO_LINE_SIMSWAP3] = APU5_GPIO_REG_SIMSWAP3, ++}; ++ ++static const char * const apu5_gpio_names[] = { ++ [APU5_GPIO_LINE_LED1] = "front-led1", ++ [APU5_GPIO_LINE_LED2] = "front-led2", ++ [APU5_GPIO_LINE_LED3] = "front-led3", ++ [APU5_GPIO_LINE_MODESW] = "front-button", ++ [APU5_GPIO_LINE_RESETM1] = "modem1-reset", ++ [APU5_GPIO_LINE_RESETM2] = "modem2-reset", ++ [APU5_GPIO_LINE_RESETM3] = "modem3-reset", ++ [APU5_GPIO_LINE_SIMSWAP1] = "simswap1", ++ [APU5_GPIO_LINE_SIMSWAP2] = "simswap2", ++ [APU5_GPIO_LINE_SIMSWAP3] = "simswap3", ++}; ++ ++static const struct amd_fch_gpio_pdata board_apu5 = { ++ .gpio_num = ARRAY_SIZE(apu5_gpio_regs), ++ .gpio_reg = apu5_gpio_regs, ++ .gpio_names = apu5_gpio_names, ++}; ++ + /* GPIO LEDs device */ + + static const struct gpio_led apu2_leds[] = { +@@ -215,6 +283,24 @@ static const struct dmi_system_id apu_gp + }, + .driver_data = (void *)&board_apu2, + }, ++ /* APU5 w/ mainline BIOS */ ++ { ++ .ident = "apu5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), ++ DMI_MATCH(DMI_BOARD_NAME, "apu5") ++ }, ++ .driver_data = (void *)&board_apu5, ++ }, ++ /* APU6 w/ mainline BIOS */ ++ { ++ .ident = "apu6", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), ++ DMI_MATCH(DMI_BOARD_NAME, "apu6") ++ }, ++ .driver_data = (void *)&board_apu2, ++ }, + {} + }; + +@@ -249,7 +335,7 @@ static int __init apu_board_init(void) + + id = dmi_first_match(apu_gpio_dmi_table); + if (!id) { +- pr_err("failed to detect APU board via DMI\n"); ++ pr_err("No APU board detected via DMI\n"); + return -ENODEV; + } + +@@ -288,7 +374,7 @@ module_init(apu_board_init); + module_exit(apu_board_exit); + + MODULE_AUTHOR("Enrico Weigelt, metux IT consult "); +-MODULE_DESCRIPTION("PC Engines APUv2/APUv3 board GPIO/LEDs/keys driver"); ++MODULE_DESCRIPTION("PC Engines APUv2-6 board GPIO/LEDs/keys driver"); + MODULE_LICENSE("GPL"); + MODULE_DEVICE_TABLE(dmi, apu_gpio_dmi_table); + MODULE_SOFTDEP("pre: platform:" AMD_FCH_GPIO_DRIVER_NAME " platform:leds-gpio platform:gpio_keys_polled"); diff --git a/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch b/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch new file mode 100644 index 000000000..4fded72fa --- /dev/null +++ b/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch @@ -0,0 +1,33 @@ +From 5e7121e45ff283d30097da381fd7e97c4bb61364 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= +Date: Sun, 10 Dec 2023 13:57:55 +0000 +Subject: [PATCH] Fix build for Linux 6.7-rc1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since Linux 6.7-rc1, no ahash algorithms set a nonzero alignmask, +and therefore `crypto_ahash_alignmask` has been removed. + +See also: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0f8660c82b79af595b056f6b9f4f227edeb88574 + https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c626910f3f1bbce6ad18bc613d895d2a089ed95e + +Signed-off-by: Joan Bruguera Micó +--- + cryptlib.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/cryptlib.c ++++ b/cryptlib.c +@@ -381,7 +381,11 @@ int cryptodev_hash_init(struct hash_data + } + + hdata->digestsize = crypto_ahash_digestsize(hdata->async.s); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)) + hdata->alignmask = crypto_ahash_alignmask(hdata->async.s); ++#else ++ hdata->alignmask = 0; ++#endif + + init_completion(&hdata->async.result.completion); + diff --git a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch new file mode 100644 index 000000000..3e5e21907 --- /dev/null +++ b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch @@ -0,0 +1,26 @@ +diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +index 6220ad1..9e83a29 100644 +--- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c ++++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +@@ -672,7 +672,11 @@ static void gpio_keys_irq_close(struct gpio_keys_button_dev *bdev) + } + } + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 11, 0) ++static void gpio_keys_remove(struct platform_device *pdev) ++#else + static int gpio_keys_remove(struct platform_device *pdev) ++#endif + { + struct gpio_keys_button_dev *bdev = platform_get_drvdata(pdev); + +@@ -683,7 +687,9 @@ static int gpio_keys_remove(struct platform_device *pdev) + else + gpio_keys_irq_close(bdev); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + return 0; ++#endif + } + + static struct platform_driver gpio_keys_driver = { diff --git a/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch b/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch new file mode 100644 index 000000000..6b1874d24 --- /dev/null +++ b/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch @@ -0,0 +1,41 @@ +diff --git a/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c b/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c +index f453a2b..8409515 100644 +--- a/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c ++++ b/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c +@@ -283,7 +283,11 @@ static int nct5104d_gpio_probe(struct platform_device *pdev) + bank->chip.parent = &pdev->dev; + bank->data = data; + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,11,0) ++ err = gpiochip_add_data(&bank->chip, bank); ++#else + err = gpiochip_add(&bank->chip); ++#endif + if (err) { + dev_err(&pdev->dev, + "Failed to register gpiochip %d: %d\n", +@@ -304,7 +308,13 @@ err_gpiochip: + return err; + } + +-static int nct5104d_gpio_remove(struct platform_device *pdev) ++static ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0) ++int ++#else ++void ++#endif ++nct5104d_gpio_remove(struct platform_device *pdev) + { + int i; + struct nct5104d_gpio_data *data = platform_get_drvdata(pdev); +@@ -315,7 +325,9 @@ static int nct5104d_gpio_remove(struct platform_device *pdev) + gpiochip_remove (&bank->chip); + } + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0) + return 0; ++#endif + } + + static int __init nct5104d_find(int addr, struct nct5104d_sio *sio) diff --git a/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch b/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch new file mode 100644 index 000000000..6cf58915f --- /dev/null +++ b/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch @@ -0,0 +1,74 @@ +--- a/nat46/modules/nat46-netdev.c ++++ b/nat46/modules/nat46-netdev.c +@@ -193,7 +193,11 @@ static struct net_device *find_dev(char + return NULL; + } + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) ++ rcu_read_lock(); ++#else + read_lock(&dev_base_lock); ++#endif + dev = first_net_device(&init_net); + while (dev) { + if((0 == strcmp(dev->name, name)) && is_nat46(dev)) { +@@ -205,7 +209,11 @@ static struct net_device *find_dev(char + } + dev = next_net_device(dev); + } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) ++ rcu_read_unlock(); ++#else + read_unlock(&dev_base_lock); ++#endif + return out; + } + +@@ -300,7 +308,11 @@ int nat46_remove(char *devname, char *bu + + void nat64_show_all_configs(struct seq_file *m) { + struct net_device *dev; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) ++ rcu_read_lock(); ++#else + read_lock(&dev_base_lock); ++#endif + dev = first_net_device(&init_net); + while (dev) { + if(is_nat46(dev)) { +@@ -323,7 +335,11 @@ void nat64_show_all_configs(struct seq_f + } + dev = next_net_device(dev); + } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) ++ rcu_read_unlock(); ++#else + read_unlock(&dev_base_lock); ++#endif + + } + +@@ -331,7 +347,11 @@ void nat46_destroy_all(void) { + struct net_device *dev; + struct net_device *nat46dev; + do { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) ++ rcu_read_lock(); ++#else + read_lock(&dev_base_lock); ++#endif + nat46dev = NULL; + dev = first_net_device(&init_net); + while (dev) { +@@ -340,7 +360,11 @@ void nat46_destroy_all(void) { + } + dev = next_net_device(dev); + } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) ++ rcu_read_unlock(); ++#else + read_unlock(&dev_base_lock); ++#endif + if(nat46dev) { + nat46_netdev_destroy(nat46dev); + } diff --git a/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch b/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch new file mode 100644 index 000000000..b3456527a --- /dev/null +++ b/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch @@ -0,0 +1,9 @@ +--- a/drivers/net/ovpn-dco/main.c ++++ b/drivers/net/ovpn-dco/main.c +@@ -268,4 +268,6 @@ MODULE_AUTHOR(DRV_COPYRIGHT); + MODULE_LICENSE("GPL"); + MODULE_VERSION(DRV_VERSION); + MODULE_ALIAS_RTNL_LINK(DRV_NAME); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + MODULE_ALIAS_GENL_FAMILY(OVPN_NL_NAME); ++#endif diff --git a/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch b/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch new file mode 100644 index 000000000..862f30ee8 --- /dev/null +++ b/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch @@ -0,0 +1,50 @@ +--- a/v4l2loopback.c ++++ b/v4l2loopback.c +@@ -714,7 +714,11 @@ static int vidioc_querycap(struct file * + ->devicenr; + __u32 capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + strlcpy(cap->driver, "v4l2 loopback", sizeof(cap->driver)); ++#else ++ strscpy(cap->driver, "v4l2 loopback", sizeof(cap->driver)); ++#endif + vidioc_fill_name(cap->card, sizeof(cap->card), devnr); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:v4l2loopback-%03d", devnr); +@@ -1220,7 +1224,11 @@ static int vidioc_queryctrl(struct file + if (!cnf) + BUG(); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + strlcpy(q->name, cnf->name, sizeof(q->name)); ++#else ++ strscpy(q->name, cnf->name, sizeof(q->name)); ++#endif + q->default_value = cnf->def; + q->type = cnf->type; + q->minimum = cnf->min; +@@ -1325,7 +1333,11 @@ static int vidioc_enum_output(struct fil + memset(outp, 0, sizeof(*outp)); + + outp->index = index; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + strlcpy(outp->name, "loopback in", sizeof(outp->name)); ++#else ++ strscpy(outp->name, "loopback in", sizeof(outp->name)); ++#endif + outp->type = V4L2_OUTPUT_TYPE_ANALOG; + outp->audioset = 0; + outp->modulator = 0; +@@ -1384,7 +1396,11 @@ static int vidioc_enum_input(struct file + memset(inp, 0, sizeof(*inp)); + + inp->index = index; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + strlcpy(inp->name, "loopback", sizeof(inp->name)); ++#else ++ strscpy(inp->name, "loopback", sizeof(inp->name)); ++#endif + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->audioset = 0; + inp->tuner = 0; diff --git a/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch b/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch new file mode 100644 index 000000000..15ebf12a4 --- /dev/null +++ b/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch @@ -0,0 +1,15 @@ +--- a/extensions/rtsp/nf_conntrack_rtsp.c ++++ b/extensions/rtsp/nf_conntrack_rtsp.c +@@ -735,8 +735,12 @@ init(void) + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + strlcpy(hlpr->name, tmpname, sizeof(hlpr->name)); + #else ++ strscpy(hlpr->name, tmpname, sizeof(hlpr->name)); ++#endif ++#else + hlpr->name = tmpname; + #endif + pr_debug("port #%d: %d\n", i, ports[i]); diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 6f21baf62..1e9bea9d7 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -39,6 +39,9 @@ curl -s https://$mirror/openwrt/patch/generic/0006-build-kernel-add-out-of-tree- # rootfs: Add support for local kmod installation sources curl -s https://$mirror/openwrt/patch/generic/0007-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 +# kernel: linux-6.11 config +curl -s https://$mirror/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 + # meson: add platform variable to cross-compilation file curl -s https://$mirror/openwrt/patch/generic/010-meson-add-platform-variable-to-cross-compilation-file.patch | patch -p1 @@ -161,6 +164,7 @@ if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then # firewall4 - master rm -rf package/network/config/firewall4 cp -a ../master/openwrt/package/network/config/firewall4 package/network/config/firewall4 + sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/network/config/firewall4/Makefile mkdir -p package/network/config/firewall4/patches # fix ct status dnat curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch > package/network/config/firewall4/patches/990-unconditionally-allow-ct-status-dnat.patch diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index c7fdc274f..99b75f8ad 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -6,13 +6,21 @@ rm -rf target/linux/rockchip git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b linux-6.6 -# x86_64 - target +# x86_64 - target 6.6 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.6 > target/linux/x86/64/config-6.6 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.6 > target/linux/x86/config-6.6 mkdir -p target/linux/x86/patches-6.6 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.6/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.6/100-fix_cs5535_clockevt.patch curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.6/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.6/103-pcengines_apu6_platform.patch -sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile +# x86_64 - target 6.11 +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.11 > target/linux/x86/64/config-6.11 +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.11 > target/linux/x86/config-6.11 +mkdir -p target/linux/x86/patches-6.11 +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.11/100-fix_cs5535_clockevt.patch +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.11/103-pcengines_apu6_platform.patch +# x86_64 - target +sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.6/" target/linux/x86/Makefile +sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.11' target/linux/x86/Makefile curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network @@ -28,16 +36,17 @@ git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/arm # kernel - 6.x curl -s https://$mirror/tags/kernel-6.6 > include/kernel-6.6 +curl -s https://$mirror/tags/kernel-6.11 > include/kernel-6.11 # kenrel Vermagic sed -ie 's/^\(.\).*vermagic$/\1cp $(TOPDIR)\/.vermagic $(LINUX_DIR)\/.vermagic/' include/kernel-defaults.mk -grep HASH include/kernel-6.6 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic +grep HASH include/kernel-$kernel_version | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic # kernel generic patches rm -rf target/linux/generic -kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-6.6) -release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-6.6 | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') -if [ "$kernel_version" = "$release_kernel_version" ]; then +local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-$kernel_version) +release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-$kernel_version | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') +if [ "$local_kernel_version" = "$release_kernel_version" ]; then git clone https://$github/sbwml/target_linux_generic -b main target/linux/generic --depth=1 else if [ "$(whoami)" = "runner" ]; then @@ -50,7 +59,7 @@ else fi # bcm53xx - fix build kernel with clang -[ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch +[ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch target/linux/generic/hack-6.11/220-arm-gc_sections.patch # kernel modules rm -rf package/kernel/linux @@ -83,77 +92,86 @@ pushd package/kernel/linux/modules curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/virt.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/w1.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/wpan.mk - [ "$platform" = "bcm53xx" ] && sed -i 's/tcp-bbr3/tcp-bbr/g' netsupport.mk - [ "$platform" = "bcm53xx" ] && sed -i 's/BBRv3/BBR/g' netsupport.mk popd -# BBRv3 - linux-6.6 -if [ "$platform" != "bcm53xx" ]; then - pushd target/linux/generic/backport-6.6 - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/bbr3_6.6/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch - popd -fi +# BBRv3 - linux-6.6/6.11 +pushd target/linux/generic/backport-"$kernel_version" + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch + [ "$TESTING_KERNEL" = "y" ] && curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch +popd -# LRNG v54 - linux-6.6 -pushd target/linux/generic/hack-6.6 - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0003-LRNG-proc-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.6/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch +# LRNG v54/56 - linux-6.6/6.11 +pushd target/linux/generic/hack-$kernel_version + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0003-LRNG-proc-interface.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch popd # linux-firmware: rtw89 / rtl8723d / rtl8821c /i915 firmware rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware -# rtl8812au-ct - fix linux-6.6 -rm -rf package/kernel/rtl8812au-ct -git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct - -# add rtl8812au-ac -git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac +if [ "$TESTING_KERNEL" = "y" ]; then + # rtl8812au-ct - fix linux-6.11 + rm -rf package/kernel/rtl8812au-ct + git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct -b v6.11 + # add rtl8812au-ac + git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac -b v6.11 +else + # rtl8812au-ct - fix linux-6.6 + rm -rf package/kernel/rtl8812au-ct + git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct + # add rtl8812au-ac + git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac +fi # mt76 - 2024-05-17 rm -rf package/kernel/mt76/patches +mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile +[ "$TESTING_KERNEL" = "y" ] && { + mkdir -p package/kernel/mt76/patches ; \ + curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +} # iwinfo: add mt7922 device id mkdir -p package/network/utils/iwinfo/patches @@ -169,27 +187,35 @@ curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > pa # mac80211 - fix linux 6.6 & add rtw89 rm -rf package/kernel/mac80211 -git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.9.9 +if [ "$TESTING_KERNEL" = "y" ]; then + git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 +else + git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.9.9 +fi # ath10k-ct rm -rf package/kernel/ath10k-ct -git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct +if [ "$TESTING_KERNEL" = "y" ]; then + git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.11 +else + git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct +fi # kernel patch # btf: silence btf module warning messages -curl -s https://$mirror/openwrt/patch/kernel-6.6/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-6.6/990-btf-silence-btf-module-warning-messages.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-$kernel_version/990-btf-silence-btf-module-warning-messages.patch # cpu model -curl -s https://$mirror/openwrt/patch/kernel-6.6/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/pending-6.6/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/pending-$kernel_version/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch # fullcone -curl -s https://$mirror/openwrt/patch/kernel-6.6/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-6.6/952-net-conntrack-events-support-multiple-registrant.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-$kernel_version/952-net-conntrack-events-support-multiple-registrant.patch # bcm-fullcone -curl -s https://$mirror/openwrt/patch/kernel-6.6/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-6.6/982-add-bcm-fullcone-support.patch -curl -s https://$mirror/openwrt/patch/kernel-6.6/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-6.6/983-add-bcm-fullcone-nft_masq-support.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-$kernel_version/982-add-bcm-fullcone-support.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-$kernel_version/983-add-bcm-fullcone-nft_masq-support.patch # shortcut-fe -curl -s https://$mirror/openwrt/patch/kernel-6.6/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-6.6/601-netfilter-export-udp_get_timeouts-function.patch -curl -s https://$mirror/openwrt/patch/kernel-6.6/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.6/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-$kernel_version/601-netfilter-export-udp_get_timeouts-function.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-$kernel_version/953-net-patch-linux-kernel-to-support-shortcut-fe.patch # backport - 6.8 fast-path-variables -if [ "$platform" != "bcm53xx" ]; then +if [ "$platform" != "bcm53xx" ] && [ "$TESTING_KERNEL" != "y" ]; then curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch > target/linux/generic/backport-6.6/901-v6.8-cache-enforce-cache-groups.patch curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch > target/linux/generic/backport-6.6/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch > target/linux/generic/backport-6.6/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index ae82eadcd..f602c68e1 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -5,12 +5,15 @@ # cryptodev-linux mkdir -p package/kernel/cryptodev-linux/patches curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/001-Fix-build-for-Linux-6.3-rc1.patch > package/kernel/cryptodev-linux/patches/001-Fix-build-for-Linux-6.3-rc1.patch +curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch > package/kernel/cryptodev-linux/patches/002-fix-build-for-linux-6.7-rc1.patch # gpio-button-hotplug curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch | patch -p1 # gpio-nct5104d curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch | patch -p1 # dmx_usb_module mkdir -p feeds/packages/libs/dmx_usb_module/patches @@ -27,6 +30,7 @@ curl -s https://$mirror/openwrt/patch/packages-patches/mdio-netlink/001-mdio-net mkdir -p feeds/packages/kernel/ovpn-dco/patches curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch > feeds/packages/kernel/ovpn-dco/patches/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch > feeds/packages/kernel/ovpn-dco/patches/900-fix-linux-6.6.patch +curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch > feeds/packages/kernel/ovpn-dco/patches/901-fix-linux-6.11.patch # siit rm -rf feeds/packages/net/siit @@ -42,6 +46,19 @@ pushd feeds/packages/libs/libpfring/patches curl -Os https://$mirror/openwrt/patch/packages-patches/libpfring/patches/900-fix-linux-6.6.patch popd +# nat46 +mkdir -p package/kernel/nat46/patches +curl -s https://$mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch > package/kernel/nat46/patches/100-fix-build-with-kernel-6.9.patch + +# v4l2loopback - 6.11 +mkdir -p feeds/packages/kernel/v4l2loopback/patches +curl -s https://$mirror/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch > feeds/packages/kernel/v4l2loopback/patches/100-fix-build-with-linux-6.11.patch + +# openvswitch +if [ "$TESTING_KERNEL" = "y" ]; then + sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile +fi + # packages pushd feeds/packages # xr_usb_serial_common @@ -56,6 +73,7 @@ popd # xtables-addons rm -rf feeds/packages/net/xtables-addons cp -a ../master/packages/net/xtables-addons feeds/packages/net/xtables-addons +curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.11.patch # telephony pushd feeds/telephony diff --git a/tags/kernel-6.11 b/tags/kernel-6.11 new file mode 100644 index 000000000..7c1260757 --- /dev/null +++ b/tags/kernel-6.11 @@ -0,0 +1,2 @@ +LINUX_VERSION-6.11 = +LINUX_KERNEL_HASH-6.11 = 55d2c6c025ebc27810c748d66325dd5bc601e8d32f8581d9e77673529bdacb2e diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index 8257a30dd..9fc65c964 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -10,3 +10,13 @@ TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` [ -z $TAG ] && TAG="" || TAG=.$TAG echo "LINUX_VERSION-6.6 = $TAG LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.6 + +# MAIN +KERNEL_VERSION=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | awk '{print $2}' | grep -E ^linux-6.11 | grep tar.xz | sed 's/linux-//g;s/.tar.xz//g' | tail -n 1` +KERNEL_HASH=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | grep linux-$KERNEL_VERSION | grep tar.xz | awk '{print $1}'` +TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` + +[ -z $TAG ] && TAG="" || TAG=.$TAG +echo "LINUX_VERSION-6.11 = $TAG +LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.11 + From 053d29ad901cb957efb4f91a6b1524b398bbb302 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Sep 2024 16:55:00 +0800 Subject: [PATCH 021/425] release: update to OpenWrt 23.05.5 Signed-off-by: sbwml --- tags/v23 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v23 b/tags/v23 index fb51fde99..769d17cf7 100644 --- a/tags/v23 +++ b/tags/v23 @@ -1 +1 @@ -23.05.4 +23.05.5 From 61014f283a7ca4fc9def93cc03268440d7cd4883 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Sep 2024 17:31:12 +0800 Subject: [PATCH 022/425] toolchain: GCC 15-20240922 Snapshot * This snapshot has been generated from the GCC 15 git branch with the following options: git://gcc.gnu.org/git/gcc.git branch master revision 0312b66677590471b8b783b81f62b2e36b1b7ac1 Signed-off-by: sbwml --- .../generic/202-toolchain-gcc-add-support-for-GCC-15.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch index 5325af227..18272cff3 100644 --- a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -55,7 +55,7 @@ index a1a5108..7ec50ad 100644 endif +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=4633621d7edc84b5e13c02c0d5f78a098e612321581b098319486b768055c7d9 ++ PKG_HASH:=56d5e11d0c75077f8c556e57f2f317d9d324b28070a868fc85dc1108bd0508b3 +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x From 94d21f5d2f4690c5ce00986dcb96f82154cd5a55 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Sep 2024 22:27:52 +0800 Subject: [PATCH 023/425] glibc: fix build Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 1 + openwrt/scripts/05-fix-source.sh | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 1e9bea9d7..8a351c3f8 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -142,6 +142,7 @@ curl -s https://$mirror/openwrt/patch/fstools/ntfs3.patch > package/system/fstoo curl -s https://$mirror/openwrt/patch/util-linux/util-linux_ntfs3.patch > package/utils/util-linux/patches/util-linux_ntfs3.patch # fstools - enable any device with non-MTD rootfs_data volume +sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/system/fstools/Makefile curl -s https://$mirror/openwrt/patch/fstools/block-mount-add-fstools-depends.patch | patch -p1 if [ "$ENABLE_GLIBC" = "y" ]; then curl -s https://$mirror/openwrt/patch/fstools/fstools-set-ntfs3-utf8-new.patch > package/system/fstools/patches/ntfs3-utf8.patch diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 99a7bfd65..52c083534 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -58,6 +58,7 @@ if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then if [ "$ENABLE_GLIBC" = "y" ]; then # perl sed -i "/Target perl/i\TARGET_CFLAGS_PERL += -Wno-implicit-function-declaration -Wno-int-conversion\n" feeds/packages/lang/perl/Makefile + sed -i '/HOST_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/lang/perl/Makefile # lucihttp sed -i "/TARGET_CFLAGS/i\TARGET_CFLAGS += -Wno-implicit-function-declaration" feeds/luci/contrib/package/lucihttp/Makefile # rpcd @@ -68,6 +69,9 @@ if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then sed -i "s/-DNDEBUG/-DNDEBUG -Wno-implicit-function-declaration/g" feeds/luci/modules/luci-base/src/Makefile # uhttpd sed -i "/Package\/uhttpd\/install/i\TARGET_CFLAGS += -Wno-implicit-function-declaration\n" package/network/services/uhttpd/Makefile + # shadow + sed -i '/TARGET_LDFLAGS/d' feeds/packages/utils/shadow/Makefile + sed -i 's/libxcrypt/openssl/g' feeds/packages/utils/shadow/Makefile fi # openssh - 9.8p1 if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then From 8c48fd283bcf1686a334d23bd5a57cdae2ee6295 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 02:45:08 +0800 Subject: [PATCH 024/425] linux-6.11: lrng: fix Jitter RNG Signed-off-by: sbwml --- ...-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch index 597c190f1..555d147ad 100644 --- a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch +++ b/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch @@ -16,8 +16,8 @@ Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 172 +++++++-------- drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_es_jent.c | 356 +++++++++++++++++++++++++++++++ - 3 files changed, 443 insertions(+), 86 deletions(-) + drivers/char/lrng/lrng_es_jent.c | 358 +++++++++++++++++++++++++++++++ + 3 files changed, 445 insertions(+), 86 deletions(-) create mode 100644 drivers/char/lrng/lrng_es_jent.c --- a/drivers/char/lrng/Kconfig @@ -212,7 +212,7 @@ Signed-off-by: Stephan Mueller obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o --- /dev/null +++ b/drivers/char/lrng/lrng_es_jent.c -@@ -0,0 +1,356 @@ +@@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG Fast Entropy Source: Jitter RNG @@ -366,6 +366,8 @@ Signed-off-by: Stephan Mueller + + pr_debug("Jitter RNG ES monitor: filled slot %u with %u bits of entropy\n", + i, requested_bits); ++ ++ schedule(); + } + + pr_debug("Jitter RNG block filling completed\n"); From ec881bc6365a0cbac1bceebfaf9a98242a8df024 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 03:01:17 +0800 Subject: [PATCH 025/425] build.sh: fixing mirror for my own workflow Signed-off-by: sbwml --- openwrt/build.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index bc0ec3fa0..a0a6e6855 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -25,7 +25,7 @@ endgroup() { ##################################### # IP Location -ip_info=`curl -s https://ip.cooluc.com`; +ip_info=`curl -sk https://ip.cooluc.com`; export isCN=`echo $ip_info | grep -Po 'country_code\":"\K[^"]+'`; # script url @@ -40,6 +40,9 @@ if [ "$(whoami)" = "runner" ] && [ -n "$GITHUB_REPO" ]; then export mirror=raw.githubusercontent.com/$GITHUB_REPO/master fi +# apply for sbwml/builder +[ -n "$git_password" ] && export mirror=init2.cooluc.com + # private gitea export gitea=git.cooluc.com From 32d48db9bc5c315640734fac660da7b6797fbf2f Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 04:54:52 +0800 Subject: [PATCH 026/425] build.sh: toolchain-cache zstd Signed-off-by: sbwml --- openwrt/build.sh | 53 +++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index a0a6e6855..66dac249b 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -103,25 +103,27 @@ fi [ -n "$LAN" ] && export LAN=$LAN || export LAN=10.0.0.1 # platform -[ "$2" = "nanopi-r4s" ] && export platform="rk3399" toolchain_arch="nanopi-r4s" -[ "$2" = "nanopi-r5s" ] && export platform="rk3568" toolchain_arch="nanopi-r5s" +[ "$2" = "armv8" ] && export platform="armv8" toolchain_arch="aarch64_generic" +[ "$2" = "nanopi-r4s" ] && export platform="rk3399" toolchain_arch="aarch64_generic" +[ "$2" = "nanopi-r5s" ] && export platform="rk3568" toolchain_arch="aarch64_generic" +[ "$2" = "netgear_r8500" ] && export platform="bcm53xx" toolchain_arch="arm_cortex-a9" [ "$2" = "x86_64" ] && export platform="x86_64" toolchain_arch="x86_64" -[ "$2" = "netgear_r8500" ] && export platform="bcm53xx" toolchain_arch="bcm53xx" -[ "$2" = "armv8" ] && export platform="armv8" toolchain_arch="armsr-armv8" # gcc13 & 14 & 15 if [ "$USE_GCC13" = y ]; then - export USE_GCC13=y + export USE_GCC13=y gcc_version=13 # use mold [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y elif [ "$USE_GCC14" = y ]; then - export USE_GCC14=y + export USE_GCC14=y gcc_version=14 # use mold [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y elif [ "$USE_GCC15" = y ]; then - export USE_GCC15=y + export USE_GCC15=y gcc_version=15 # use mold [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y +else + export gcc_version=11 fi # build.sh flags @@ -160,16 +162,7 @@ echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" rm -f kernel.txt echo -e "${GREEN_COLOR}Date: $CURRENT_DATE${RES}\r\n" - -if [ "$USE_GCC13" = "y" ]; then - echo -e "${GREEN_COLOR}GCC VERSION: 13${RES}" -elif [ "$USE_GCC14" = "y" ]; then - echo -e "${GREEN_COLOR}GCC VERSION: 14${RES}" -elif [ "$USE_GCC15" = "y" ]; then - echo -e "${GREEN_COLOR}GCC VERSION: 15${RES}" -else - echo -e "${GREEN_COLOR}GCC VERSION: 11${RES}" -fi +echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" [ -n "$LAN" ] && echo -e "${GREEN_COLOR}LAN: $LAN${RES}" || echo -e "${GREEN_COLOR}LAN: 10.0.0.1${RES}" [ "$ENABLE_GLIBC" = "y" ] && echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}glibc${RES}" || echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}musl${RES}" [ "$ENABLE_OTA" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_OTA: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_OTA:${RES} ${YELLOW_COLOR}false${RES}" @@ -398,19 +391,12 @@ if [ "$BUILD_FAST" = "y" ]; then if [ "$PLATFORM_ID" = "platform:el9" ]; then TOOLCHAIN_URL="http://127.0.0.1:8080" else - TOOLCHAIN_URL="$github_proxy"https://github.com/sbwml/toolchain-cache/releases/latest/download - fi - if [ "$USE_GCC13" = "y" ]; then - curl -L "$TOOLCHAIN_URL"/toolchain_"$LIBC"_"$toolchain_arch"_13.tar.gz -o toolchain.tar.gz $CURL_BAR - elif [ "$USE_GCC14" = "y" ]; then - curl -L "$TOOLCHAIN_URL"/toolchain_"$LIBC"_"$toolchain_arch"_14.tar.gz -o toolchain.tar.gz $CURL_BAR - elif [ "$USE_GCC15" = "y" ]; then - curl -L "$TOOLCHAIN_URL"/toolchain_"$LIBC"_"$toolchain_arch"_15.tar.gz -o toolchain.tar.gz $CURL_BAR - else - curl -L "$TOOLCHAIN_URL"/toolchain_"$LIBC"_"$toolchain_arch"_11.tar.gz -o toolchain.tar.gz $CURL_BAR + TOOLCHAIN_URL="$github_proxy"https://github.com/sbwml/openwrt_caches/releases/latest/download fi + curl -L "$TOOLCHAIN_URL"/toolchain_"$LIBC"_"$toolchain_arch"_gcc-"$gcc_version".tar.zst -o toolchain.tar.zst $CURL_BAR echo -e "\n${GREEN_COLOR}Process Toolchain ...${RES}" - tar -zxf toolchain.tar.gz && rm -f toolchain.tar.gz + tar -I "zstd" -xf toolchain.tar.zst + rm -f toolchain.tar.zst mkdir bin find ./staging_dir/ -name '*' -exec touch {} \; >/dev/null 2>&1 find ./tmp/ -name '*' -exec touch {} \; >/dev/null 2>&1 @@ -430,15 +416,8 @@ if [ "$BUILD_TOOLCHAIN" = "y" ]; then make -j$cores toolchain/compile || make -j$cores toolchain/compile V=s || exit 1 mkdir -p toolchain-cache [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl - if [ "$USE_GCC13" = "y" ]; then - tar -zcf toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_13.tar.gz ./{build_dir,dl,staging_dir,tmp} && echo -e "${GREEN_COLOR} Build success! ${RES}" - elif [ "$USE_GCC14" = "y" ]; then - tar -zcf toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_14.tar.gz ./{build_dir,dl,staging_dir,tmp} && echo -e "${GREEN_COLOR} Build success! ${RES}" - elif [ "$USE_GCC15" = "y" ]; then - tar -zcf toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_15.tar.gz ./{build_dir,dl,staging_dir,tmp} && echo -e "${GREEN_COLOR} Build success! ${RES}" - else - tar -zcf toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_11.tar.gz ./{build_dir,dl,staging_dir,tmp} && echo -e "${GREEN_COLOR} Build success! ${RES}" - fi + tar -I "zstd -19 -T$(nproc --all)" toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_gcc-"$gcc_version".tar.zst ./{build_dir,dl,staging_dir,tmp} + echo -e "${GREEN_COLOR} Build success! ${RES}" exit 0 else echo -e "\r\n${GREEN_COLOR}Building OpenWrt ...${RES}\r\n" From 15de73b9101f7ff5f3f58bb1d3016598e3ee34cc Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 06:17:44 +0800 Subject: [PATCH 027/425] build.sh: toolchain-cache: fix tar option Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 66dac249b..fe43fcea4 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -416,7 +416,7 @@ if [ "$BUILD_TOOLCHAIN" = "y" ]; then make -j$cores toolchain/compile || make -j$cores toolchain/compile V=s || exit 1 mkdir -p toolchain-cache [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl - tar -I "zstd -19 -T$(nproc --all)" toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_gcc-"$gcc_version".tar.zst ./{build_dir,dl,staging_dir,tmp} + tar -I "zstd -19 -T$(nproc --all)" -cf toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_gcc-"$gcc_version".tar.zst ./{build_dir,dl,staging_dir,tmp} echo -e "${GREEN_COLOR} Build success! ${RES}" exit 0 else From acc051e5949a60a7ed96ea977b8e2b3eaabd9944 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 10:37:11 +0800 Subject: [PATCH 028/425] build.sh: add ota support for test build Signed-off-by: sbwml --- openwrt/build.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index fe43fcea4..61518414e 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -442,6 +442,8 @@ else exit 1 fi +[ "$TESTING_KERNEL" = "y" ] && OTA_PREFIX="test-" || OTA_PREFIX="" + if [ "$platform" = "x86_64" ]; then if [ "$ALL_KMODS" = y ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name @@ -469,7 +471,7 @@ if [ "$platform" = "x86_64" ]; then { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-x86-64-generic-squashfs-combined-efi.img.gz" + "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-x86-64-generic-squashfs-combined-efi.img.gz" } ] } @@ -537,7 +539,7 @@ elif [ "$platform" = "bcm53xx" ]; then { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-bcm53xx-generic-netgear_r8500-squashfs.chk" + "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-bcm53xx-generic-netgear_r8500-squashfs.chk" } ] } @@ -569,7 +571,7 @@ else { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r4s-squashfs-sysupgrade.img.gz" + "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r4s-squashfs-sysupgrade.img.gz" } ] } @@ -584,14 +586,14 @@ EOF { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256_R5C", - "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5c-squashfs-sysupgrade.img.gz" + "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5c-squashfs-sysupgrade.img.gz" } ], "friendlyarm,nanopi-r5s": [ { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256_R5S", - "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5s-squashfs-sysupgrade.img.gz" + "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5s-squashfs-sysupgrade.img.gz" } ] } From 7381e5babbee5cfb070f290a3ceef882cc6cdd7f Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 16:21:54 +0800 Subject: [PATCH 029/425] ubootenv-nvram: make `ubootenv_remove` return void for linux-6.11 * openwrt-23.05.5 * fix build `CONFIG_ALL_KMODS=y` for linux 6.11 Signed-off-by: sbwml --- ...nv_remove-return-void-for-linux-6.11.patch | 42 +++++++++++++++++++ openwrt/scripts/04-fix_kmod.sh | 4 ++ 2 files changed, 46 insertions(+) create mode 100644 openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch diff --git a/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch b/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch new file mode 100644 index 000000000..c23f6395a --- /dev/null +++ b/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch @@ -0,0 +1,42 @@ +--- a/ubootenv-nvram.c ++++ b/ubootenv-nvram.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #define NAME "ubootenv" + +@@ -132,18 +133,30 @@ static int ubootenv_probe(struct platfor + return misc_register(&data->misc); + } + +-static int ubootenv_remove(struct platform_device *pdev) ++static ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) ++int ++#else ++void ++#endif ++ubootenv_remove(struct platform_device *pdev) + { + struct ubootenv_drvdata *data = platform_get_drvdata(pdev); + + data->env = NULL; + misc_deregister(&data->misc); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + return 0; ++#endif + } + + static struct platform_driver ubootenv_driver = { + .probe = ubootenv_probe, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) + .remove = ubootenv_remove, ++#else ++ .remove_new = ubootenv_remove, ++#endif + .driver = { + .name = NAME, + .owner = THIS_MODULE, diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index f602c68e1..587d20b3c 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -59,6 +59,10 @@ if [ "$TESTING_KERNEL" = "y" ]; then sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile fi +# ubootenv-nvram - 6.11 (openwrt-23.05.5) +mkdir -p package/kernel/ubootenv-nvram/patches +curl -s https://$mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.11.patch + # packages pushd feeds/packages # xr_usb_serial_common From cb7ecf58de8ebdeb436f66d0e41e01effba1511a Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 16:35:26 +0800 Subject: [PATCH 030/425] config: disable `CONFIG_PACKAGE_urngd` when LRNG is enabled * At times, `urngd` may heavily utilize CPU resources. Enable the LRNG kernel alone offers sufficient entropy, thereby disable `urngd` to mitigate overall CPU usage. Signed-off-by: sbwml --- openwrt/build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openwrt/build.sh b/openwrt/build.sh index 61518414e..464921542 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -341,6 +341,8 @@ fi if [ "$ENABLE_LRNG" = "y" ]; then echo -e "\n# Kernel - LRNG" >> .config echo "CONFIG_KERNEL_LRNG=y" >> .config + echo "# CONFIG_PACKAGE_urandom-seed is not set" >> .config + echo "# CONFIG_PACKAGE_urngd is not set" >> .config fi # local kmod From b0c07a88d750938311c20c2fab2a08711090f456 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Sep 2024 16:48:22 +0800 Subject: [PATCH 031/425] build.sh: ota: fix armsr_armv8 download URL Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 464921542..a507ba598 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -507,7 +507,7 @@ elif [ "$platform" = "armv8" ]; then { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "https://github.com/sbwml/builder/releases/download/v$VERSION/openwrt-$VERSION-armsr-armv8-generic-squashfs-combined-efi.img.gz" + "url": "https://github.com/sbwml/builder/releases/download/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-armsr-armv8-generic-squashfs-combined-efi.img.gz" } ] } From cd61bad78929d47345bc6b64d3d0e9b23c3baeba Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 26 Sep 2024 05:03:24 +0800 Subject: [PATCH 032/425] tools: add llvm/clang toolchain * Use the unified clang toolchain to make the SDK available. Signed-off-by: sbwml --- .github/workflows/build-release.yml | 3 -- README.md | 22 ---------- openwrt/patch/clang/Makefile | 42 +++++++++++++++++++ openwrt/patch/clang/README.md | 4 ++ .../0009-tools-add-llvm-clang-toolchain.patch | 35 ++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 5 +++ 6 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 openwrt/patch/clang/Makefile create mode 100644 openwrt/patch/clang/README.md create mode 100644 openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 880dd4dc2..59ac23a74 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -58,9 +58,6 @@ jobs: - name: Build System Setup uses: sbwml/actions@openwrt-build-setup - - name: Install LLVM - uses: sbwml/actions@install-llvm-19 - - name: Compile OpenWrt working-directory: /builder id: compile diff --git a/README.md b/README.md index 834294a5c..e6419b747 100644 --- a/README.md +++ b/README.md @@ -22,32 +22,10 @@ sudo apt-get update sudo apt-get install -y build-essential flex bison g++ gawk gcc-multilib g++-multilib gettext git libfuse-dev libncurses5-dev libssl-dev python3 python3-pip python3-ply python3-distutils python3-pyelftools rsync unzip zlib1g-dev file wget subversion patch upx-ucl autoconf automake curl asciidoc binutils bzip2 lib32gcc-s1 libc6-dev-i386 uglifyjs msmtp texinfo libreadline-dev libglib2.0-dev xmlto libelf-dev libtool autopoint antlr3 gperf ccache swig coreutils haveged scons libpython3-dev jq ``` -##### 安装 [LLVM/CLANG](https://github.com/sbwml/redhat-llvm-project) - 启用 `ENABLE_BPF` / `KERNEL_CLANG_LTO` 时需要 - -```shell -# 下载并解压 -sudo mkdir -p /opt/clang -curl -LO https://github.com/sbwml/redhat-llvm-project/releases/download/18.1.8/clang-18.1.8-x86_64-redhat-linux.tar.xz -sudo tar --strip-components=1 -C /opt/clang -xf clang-18.1.8-x86_64-redhat-linux.tar.xz -rm -rf clang-18.1.8-x86_64-redhat-linux.tar.xz - -# 添加 BIN 到系统变量 -export PATH="/opt/clang/bin:$PATH" - -# clang 版本验证 -clang --version - - clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff) - Target: x86_64-redhat-linux-gnu - Thread model: posix - InstalledDir: /opt/clang/bin -``` - --------------- ### 启用 [Clang/LLVM](https://docs.kernel.org/kbuild/llvm.html) 构建内核 ##### 脚本支持使用 Clang/LLVM 构建内核,NanoPi & X86_64 设备将同时启用 LLVM LTO 链接时优化,这会增加编译的时间,但会获得更优的性能 -##### 编译环境需要安装 Clang/LLVM 工具链,推荐使用 clang 16~18 版本 ##### 只需在构建固件前执行以下命令即可启用 Clang/LLVM 构建内核与内核模块 ``` diff --git a/openwrt/patch/clang/Makefile b/openwrt/patch/clang/Makefile new file mode 100644 index 000000000..0b87c2297 --- /dev/null +++ b/openwrt/patch/clang/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (C) 2006-2017 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=clang +PKG_VERSION:=19.1.0 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz +PKG_SOURCE_URL:=https://github.com/sbwml/redhat-llvm-project/releases/download/$(PKG_VERSION)/ +PKG_HASH:=21c9d10911eeccd31ab648da1beabe94048ecda441149bbba0a12302f105f337 + +PKG_MAINTAINER:=sbwml +PKG_LICENSE:=Apache-2.0 +PKG_LICENSE_FILES:=LICENSE + +include $(INCLUDE_DIR)/host-build.mk + +define Host/Prepare + $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz +endef + +define Host/Compile +endef + +define Host/Install + $(CP) $(HOST_BUILD_DIR)/{bin,include,lib,share} $(STAGING_DIR_HOST)/ +endef + +define Host/Uninstall + ( \ + rm -rf $(STAGING_DIR_HOST)/bin/{FileCheck,clang*,dsymutil,git-clang-format,*lld*,llc,llvm*,merge-fdata,opt,perf2bolt,run-clang-tidy,wasm-ld,yaml2obj} ; \ + rm -rf $(STAGING_DIR_HOST)/include/{c++,clang,clang-c,__libunwind_config.h,libunwind.h,libunwind.modulemap,lld,llvm,llvm-c,mach-o,unwind_arm_ehabi.h,unwind.h,unwind_itanium.h,x86_64-redhat-linux-gnu} ; \ + rm -rf $(STAGING_DIR_HOST)/lib/{bfd-plugins,clang,cmake,x86_64-redhat-linux-gnu,LLVMgold.so,libLLVM*,libLTO*,libPolly.a,libRemarks.so*,libclang*,libedit*,libfindAllSymbols.a,liblld*,liblzma*,libncurses*,libxml2*} ; \ + ) +endef + +$(eval $(call HostBuild)) diff --git a/openwrt/patch/clang/README.md b/openwrt/patch/clang/README.md new file mode 100644 index 000000000..8633c636f --- /dev/null +++ b/openwrt/patch/clang/README.md @@ -0,0 +1,4 @@ +# LLVM/CLANG toolchain + +available: `CONFIG_BPF_TOOLCHAIN_HOST=y` or `CONFIG_KERNEL_CC="clang"` +variable: `$(STAGING_DIR_HOST)/bin` diff --git a/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch new file mode 100644 index 000000000..f6c73759b --- /dev/null +++ b/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch @@ -0,0 +1,35 @@ +From 41292e8bd135e0f1d293deb2cde4973ca0e763e5 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 26 Sep 2024 04:48:45 +0800 +Subject: [PATCH] tools: add llvm/clang toolchain + +Signed-off-by: sbwml +--- + tools/Makefile | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tools/Makefile b/tools/Makefile +index 40c3ec1..c7f970b 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -29,6 +29,9 @@ endif + ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),) + BUILD_LZO_TOOLS = y + endif ++ifeq ($(or $(filter clang,$(CONFIG_KERNEL_CC)),$(filter y,$(CONFIG_BPF_TOOLCHAIN_HOST))),) ++ BUILD_CLANG_HOST = y ++endif + + tools-y += autoconf + tools-y += autoconf-archive +@@ -83,6 +86,7 @@ tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_TARGET_tegra),y) += cbootimage + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USES_MINOR),y) += kernel2minor + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_SPARSE),y) += sparse + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_LLVM_BUILD),y) += llvm-bpf ++tools-$(if $(BUILD_CLANG_HOST),y) += clang + + # builddir dependencies + $(curdir)/autoconf/compile := $(curdir)/m4/compile +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 8a351c3f8..3c8d4e4f6 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -42,6 +42,11 @@ curl -s https://$mirror/openwrt/patch/generic/0007-rootfs-Add-support-for-local- # kernel: linux-6.11 config curl -s https://$mirror/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 +# tools: add llvm/clang toolchain +curl -s https://$mirror/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch | patch -p1 +mkdir -p tools/clang +curl -s https://$mirror/openwrt/patch/clang/Makefile > tools/clang/Makefile + # meson: add platform variable to cross-compilation file curl -s https://$mirror/openwrt/patch/generic/010-meson-add-platform-variable-to-cross-compilation-file.patch | patch -p1 From 60e1b5ac8f937b43a81ac4a286ae9998547d5f72 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 26 Sep 2024 09:10:18 +0800 Subject: [PATCH 033/425] sctipt/patch: refresh general patches Signed-off-by: sbwml --- openwrt/patch/clang/Makefile | 42 -------- openwrt/patch/clang/README.md | 4 - .../0001-tools-add-llvm-clang-toolchain.patch | 88 +++++++++++++++++ .../generic/0002-tools-add-upx-tools.patch | 63 ++++++++++++ ...-rootfs-add-upx-compression-support.patch} | 4 +- ...rmissions-for-UCI-configuration-fil.patch} | 4 +- ...t-for-local-kmod-installation-sourc.patch} | 4 +- ...dd-MODULE_ALLOW_BTF_MISMATCH-option.patch} | 4 +- ...Add-support-for-llvm-clang-compiler.patch} | 4 +- ...th-Add-libquadmath-to-the-toolchain.patch} | 4 +- ...ernel-add-out-of-tree-kernel-config.patch} | 4 +- .../0009-tools-add-llvm-clang-toolchain.patch | 35 ------- ...rnel-add-miss-config-for-linux-6.11.patch} | 6 +- ...m-variable-to-cross-compilation-fil.patch} | 11 ++- .../200-toolchain-gcc-update-to-13.2.patch | 6 +- ...toolchain-gcc-add-support-for-GCC-14.patch | 19 +++- ...toolchain-gcc-add-support-for-GCC-15.patch | 17 +++- ...t-to-use-the-mold-linker-for-package.patch | 2 +- ...wide-opt-out-of-tree-wide-mold-usage.patch | 2 +- ...lchain-add-mold-as-additional-linker.patch | 2 +- .../0004-tools-add-mold-a-modern-linker.patch | 8 +- ...TRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch | 2 +- ...b-to-use-the-mold-linker-for-package.patch | 2 +- ...les-prepare-to-use-different-linkers.patch | 2 +- .../0008-tools-mold-update-to-2.34.0.patch} | 10 +- openwrt/patch/upx/Makefile | 31 ------ openwrt/scripts/00-prepare_base.sh | 96 +++++++++---------- 27 files changed, 274 insertions(+), 202 deletions(-) delete mode 100644 openwrt/patch/clang/Makefile delete mode 100644 openwrt/patch/clang/README.md create mode 100644 openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch create mode 100644 openwrt/patch/generic/0002-tools-add-upx-tools.patch rename openwrt/patch/generic/{0002-rootfs-add-upx-compression-support.patch => 0003-rootfs-add-upx-compression-support.patch} (89%) rename openwrt/patch/generic/{0005-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch => 0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch} (82%) rename openwrt/patch/generic/{0007-rootfs-Add-support-for-local-kmod-installation-sourc.patch => 0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch} (91%) rename openwrt/patch/generic/{0001-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch => 0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch} (91%) rename openwrt/patch/generic/{0003-kernel-Add-support-for-llvm-clang-compiler.patch => 0007-kernel-Add-support-for-llvm-clang-compiler.patch} (95%) rename openwrt/patch/generic/{0004-libquadmath-Add-libquadmath-to-the-toolchain.patch => 0008-libquadmath-Add-libquadmath-to-the-toolchain.patch} (95%) rename openwrt/patch/generic/{0006-build-kernel-add-out-of-tree-kernel-config.patch => 0009-build-kernel-add-out-of-tree-kernel-config.patch} (97%) delete mode 100644 openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch rename openwrt/patch/generic/{0008-include-kernel-add-miss-config-for-linux-6.11.patch => 0010-include-kernel-add-miss-config-for-linux-6.11.patch} (85%) rename openwrt/patch/generic/{010-meson-add-platform-variable-to-cross-compilation-file.patch => 0011-meson-add-platform-variable-to-cross-compilation-fil.patch} (84%) rename openwrt/patch/{openwrt-6.x => generic}/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch (93%) rename openwrt/patch/{openwrt-6.x => generic}/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch (97%) rename openwrt/patch/{openwrt-6.x => generic}/mold/0003-toolchain-add-mold-as-additional-linker.patch (96%) rename openwrt/patch/{openwrt-6.x => generic}/mold/0004-tools-add-mold-a-modern-linker.patch (91%) rename openwrt/patch/{openwrt-6.x => generic}/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch (96%) rename openwrt/patch/{openwrt-6.x => generic}/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch (97%) rename openwrt/patch/{openwrt-6.x => generic}/mold/0007-rules-prepare-to-use-different-linkers.patch (95%) rename openwrt/patch/{openwrt-6.x/mold/0008-tools-mold-update-to-2.32.1.patch => generic/mold/0008-tools-mold-update-to-2.34.0.patch} (76%) delete mode 100644 openwrt/patch/upx/Makefile diff --git a/openwrt/patch/clang/Makefile b/openwrt/patch/clang/Makefile deleted file mode 100644 index 0b87c2297..000000000 --- a/openwrt/patch/clang/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (C) 2006-2017 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=clang -PKG_VERSION:=19.1.0 - -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz -PKG_SOURCE_URL:=https://github.com/sbwml/redhat-llvm-project/releases/download/$(PKG_VERSION)/ -PKG_HASH:=21c9d10911eeccd31ab648da1beabe94048ecda441149bbba0a12302f105f337 - -PKG_MAINTAINER:=sbwml -PKG_LICENSE:=Apache-2.0 -PKG_LICENSE_FILES:=LICENSE - -include $(INCLUDE_DIR)/host-build.mk - -define Host/Prepare - $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz -endef - -define Host/Compile -endef - -define Host/Install - $(CP) $(HOST_BUILD_DIR)/{bin,include,lib,share} $(STAGING_DIR_HOST)/ -endef - -define Host/Uninstall - ( \ - rm -rf $(STAGING_DIR_HOST)/bin/{FileCheck,clang*,dsymutil,git-clang-format,*lld*,llc,llvm*,merge-fdata,opt,perf2bolt,run-clang-tidy,wasm-ld,yaml2obj} ; \ - rm -rf $(STAGING_DIR_HOST)/include/{c++,clang,clang-c,__libunwind_config.h,libunwind.h,libunwind.modulemap,lld,llvm,llvm-c,mach-o,unwind_arm_ehabi.h,unwind.h,unwind_itanium.h,x86_64-redhat-linux-gnu} ; \ - rm -rf $(STAGING_DIR_HOST)/lib/{bfd-plugins,clang,cmake,x86_64-redhat-linux-gnu,LLVMgold.so,libLLVM*,libLTO*,libPolly.a,libRemarks.so*,libclang*,libedit*,libfindAllSymbols.a,liblld*,liblzma*,libncurses*,libxml2*} ; \ - ) -endef - -$(eval $(call HostBuild)) diff --git a/openwrt/patch/clang/README.md b/openwrt/patch/clang/README.md deleted file mode 100644 index 8633c636f..000000000 --- a/openwrt/patch/clang/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# LLVM/CLANG toolchain - -available: `CONFIG_BPF_TOOLCHAIN_HOST=y` or `CONFIG_KERNEL_CC="clang"` -variable: `$(STAGING_DIR_HOST)/bin` diff --git a/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch new file mode 100644 index 000000000..c387227c4 --- /dev/null +++ b/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch @@ -0,0 +1,88 @@ +From bc462181d8f9d64841f5a68625070efd116bc655 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 26 Sep 2024 06:32:20 +0800 +Subject: [PATCH 01/11] tools: add llvm/clang toolchain + +Signed-off-by: sbwml +--- + tools/Makefile | 7 +++++++ + tools/clang/Makefile | 42 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 49 insertions(+) + create mode 100644 tools/clang/Makefile + +diff --git a/tools/Makefile b/tools/Makefile +index 40c3ec1..88250b3 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -29,6 +29,12 @@ endif + ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),) + BUILD_LZO_TOOLS = y + endif ++ifeq ($(CONFIG_KERNEL_CC),clang) ++ BUILD_CLANG_HOST = y ++endif ++ifeq ($(CONFIG_BPF_TOOLCHAIN_HOST),y) ++ BUILD_CLANG_HOST = y ++endif + + tools-y += autoconf + tools-y += autoconf-archive +@@ -68,6 +74,7 @@ tools-y += sstrip + tools-y += zip + tools-y += zlib + tools-y += zstd ++tools-$(if $(BUILD_CLANG_HOST),y) += clang + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS),y) += liblzo + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_B43_TOOLS),y) += b43-tools + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_BZIP2_TOOLS),y) += bzip2 +diff --git a/tools/clang/Makefile b/tools/clang/Makefile +new file mode 100644 +index 0000000..20927f7 +--- /dev/null ++++ b/tools/clang/Makefile +@@ -0,0 +1,42 @@ ++# ++# Copyright (C) 2006-2017 OpenWrt.org ++# ++# This is free software, licensed under the GNU General Public License v2. ++# See /LICENSE for more information. ++# ++ ++include $(TOPDIR)/rules.mk ++ ++PKG_NAME:=clang ++PKG_VERSION:=19.1.0 ++ ++PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz ++PKG_SOURCE_URL:=https://github.com/sbwml/redhat-llvm-project/releases/download/$(PKG_VERSION)/ ++PKG_HASH:=21c9d10911eeccd31ab648da1beabe94048ecda441149bbba0a12302f105f337 ++ ++PKG_MAINTAINER:=sbwml ++PKG_LICENSE:=Apache-2.0 ++PKG_LICENSE_FILES:=LICENSE ++ ++include $(INCLUDE_DIR)/host-build.mk ++ ++define Host/Prepare ++ $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz ++endef ++ ++define Host/Compile ++endef ++ ++define Host/Install ++ $(CP) $(HOST_BUILD_DIR)/{bin,include,lib,share} $(STAGING_DIR_HOST)/ ++endef ++ ++define Host/Uninstall ++ ( \ ++ rm -rf $(STAGING_DIR_HOST)/bin/{FileCheck,clang*,dsymutil,git-clang-format,*lld*,llc,llvm*,merge-fdata,opt,perf2bolt,run-clang-tidy,wasm-ld,yaml2obj} ; \ ++ rm -rf $(STAGING_DIR_HOST)/include/{c++,clang,clang-c,__libunwind_config.h,libunwind.h,libunwind.modulemap,lld,llvm,llvm-c,mach-o,unwind_arm_ehabi.h,unwind.h,unwind_itanium.h,x86_64-redhat-linux-gnu} ; \ ++ rm -rf $(STAGING_DIR_HOST)/lib/{bfd-plugins,clang,cmake,x86_64-redhat-linux-gnu,LLVMgold.so,libLLVM*,libLTO*,libPolly.a,libRemarks.so*,libclang*,libedit*,libfindAllSymbols.a,liblld*,liblzma*,libncurses*,libxml2*} ; \ ++ ) ++endef ++ ++$(eval $(call HostBuild)) +-- +2.43.5 + diff --git a/openwrt/patch/generic/0002-tools-add-upx-tools.patch b/openwrt/patch/generic/0002-tools-add-upx-tools.patch new file mode 100644 index 000000000..813a2a665 --- /dev/null +++ b/openwrt/patch/generic/0002-tools-add-upx-tools.patch @@ -0,0 +1,63 @@ +From b31fe0b43bc35d9bf640b92375db9ec31d543721 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 26 Sep 2024 06:38:58 +0800 +Subject: [PATCH 02/11] tools: add upx tools + +Signed-off-by: sbwml +--- + tools/Makefile | 1 + + tools/upx/Makefile | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 31 insertions(+) + create mode 100644 tools/upx/Makefile + +diff --git a/tools/Makefile b/tools/Makefile +index 88250b3..e4afc87 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -71,6 +71,7 @@ tools-y += pkgconf + tools-y += quilt + tools-y += squashfs4 + tools-y += sstrip ++tools-y += upx + tools-y += zip + tools-y += zlib + tools-y += zstd +diff --git a/tools/upx/Makefile b/tools/upx/Makefile +new file mode 100644 +index 0000000..9004514 +--- /dev/null ++++ b/tools/upx/Makefile +@@ -0,0 +1,30 @@ ++include $(TOPDIR)/rules.mk ++ ++PKG_NAME:=upx ++PKG_VERSION:=4.2.4 ++ ++PKG_SOURCE:=upx-$(PKG_VERSION)-src.tar.xz ++PKG_SOURCE_URL:=https://github.com/upx/upx/releases/download/v$(PKG_VERSION)/ ++PKG_HASH:=5ed6561607d27fb4ef346fc19f08a93696fa8fa127081e7a7114068306b8e1c4 ++ ++HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)-src ++HOST_BUILD_PARALLEL:=1 ++ ++include $(INCLUDE_DIR)/host-build.mk ++ ++define Host/Compile ++ $(MAKE) -C $(HOST_BUILD_DIR)/src \ ++ LDFLAGS="$(HOST_LDFLAGS)" \ ++ CXX="$(HOSTCXX)" ++endef ++ ++define Host/Install ++ $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin ++ $(INSTALL_BIN) $(HOST_BUILD_DIR)/build/release/upx $(STAGING_DIR_HOST)/bin/upx ++endef ++ ++define Host/Clean ++ rm -f $(STAGING_DIR_HOST)/bin/upx ++endef ++ ++$(eval $(call HostBuild)) +-- +2.43.5 + diff --git a/openwrt/patch/generic/0002-rootfs-add-upx-compression-support.patch b/openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch similarity index 89% rename from openwrt/patch/generic/0002-rootfs-add-upx-compression-support.patch rename to openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch index 9a334425a..4a5aced69 100644 --- a/openwrt/patch/generic/0002-rootfs-add-upx-compression-support.patch +++ b/openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch @@ -1,7 +1,7 @@ -From 79765552324d8c08e31e7ab80a53b1a29654d473 Mon Sep 17 00:00:00 2001 +From 986b21972b58606f861d284f370c35bffa9b51b8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 7 Apr 2024 04:08:40 +0800 -Subject: [PATCH 2/7] rootfs: add upx compression support +Subject: [PATCH 03/11] rootfs: add upx compression support * When the upx_list.txt file exists in the source code root directory, it will be compressed by upx. diff --git a/openwrt/patch/generic/0005-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch b/openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch similarity index 82% rename from openwrt/patch/generic/0005-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch rename to openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch index 18bec73ed..3709a3ca8 100644 --- a/openwrt/patch/generic/0005-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch +++ b/openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch @@ -1,7 +1,7 @@ -From 42f9a52f66ef69a0085055facf8a14cab3f279ce Mon Sep 17 00:00:00 2001 +From 0bfe29ac8cefc3335184e93e5ae0a03bdaaff336 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 30 Jun 2024 21:58:24 +0800 -Subject: [PATCH 5/7] rootfs: add r/w permissions for UCI configuration files +Subject: [PATCH 04/11] rootfs: add r/w permissions for UCI configuration files Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic/0007-rootfs-Add-support-for-local-kmod-installation-sourc.patch b/openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch similarity index 91% rename from openwrt/patch/generic/0007-rootfs-Add-support-for-local-kmod-installation-sourc.patch rename to openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch index 70a36db41..ac2b84b98 100644 --- a/openwrt/patch/generic/0007-rootfs-Add-support-for-local-kmod-installation-sourc.patch +++ b/openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch @@ -1,7 +1,7 @@ -From 910f99cb7ede0303321b1062507681685b660925 Mon Sep 17 00:00:00 2001 +From 8125e1abca321f218b90c797b0cc887d418f055c Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 14 Jul 2024 12:43:06 +0800 -Subject: [PATCH 7/7] rootfs: Add support for local kmod installation sources +Subject: [PATCH 05/11] rootfs: Add support for local kmod installation sources * CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES=y diff --git a/openwrt/patch/generic/0001-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch b/openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch similarity index 91% rename from openwrt/patch/generic/0001-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch rename to openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch index 672f07bce..788c4b02d 100644 --- a/openwrt/patch/generic/0001-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch +++ b/openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch @@ -1,7 +1,7 @@ -From b0f013ccfa66842e9739c6e11b81eadc44a2f8eb Mon Sep 17 00:00:00 2001 +From a28478cd750d5295a80eb84d74522bbec5d25f1c Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Tue, 16 May 2023 12:38:53 +0800 -Subject: [PATCH 1/7] kernel: add MODULE_ALLOW_BTF_MISMATCH option +Subject: [PATCH 06/11] kernel: add MODULE_ALLOW_BTF_MISMATCH option BTF mismatch can occur for a separately-built module even when the ABI is otherwise compatible and nothing else would prevent successfully diff --git a/openwrt/patch/generic/0003-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch similarity index 95% rename from openwrt/patch/generic/0003-kernel-Add-support-for-llvm-clang-compiler.patch rename to openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch index cfb799e0d..456d9f1e6 100644 --- a/openwrt/patch/generic/0003-kernel-Add-support-for-llvm-clang-compiler.patch +++ b/openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch @@ -1,7 +1,7 @@ -From 59e101ebf7ac9ffe7b9dfd82a6e41050dbc5d13f Mon Sep 17 00:00:00 2001 +From 57df3edf99312bbe39647d0dd9fd36896a9a3e09 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 6 May 2024 03:21:07 +0800 -Subject: [PATCH 3/7] kernel: Add support for llvm/clang compiler +Subject: [PATCH 07/11] kernel: Add support for llvm/clang compiler Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic/0004-libquadmath-Add-libquadmath-to-the-toolchain.patch b/openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch similarity index 95% rename from openwrt/patch/generic/0004-libquadmath-Add-libquadmath-to-the-toolchain.patch rename to openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch index be2aec5fe..a1607c732 100644 --- a/openwrt/patch/generic/0004-libquadmath-Add-libquadmath-to-the-toolchain.patch +++ b/openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch @@ -1,7 +1,7 @@ -From 6547a0bb12550411d4bf880e718759d5ea81db1e Mon Sep 17 00:00:00 2001 +From 71414ef6e0847d4f9d546b45630633054e072ea4 Mon Sep 17 00:00:00 2001 From: Carlos Miguel Ferreira Date: Wed, 12 Jun 2024 01:20:59 +0100 -Subject: [PATCH 4/7] libquadmath: Add libquadmath to the toolchain +Subject: [PATCH 08/11] libquadmath: Add libquadmath to the toolchain This commit makes the libquadmath library available to the GCC toolchain. This library is important for libraries such as diff --git a/openwrt/patch/generic/0006-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch similarity index 97% rename from openwrt/patch/generic/0006-build-kernel-add-out-of-tree-kernel-config.patch rename to openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch index c309684b6..9e842ae46 100644 --- a/openwrt/patch/generic/0006-build-kernel-add-out-of-tree-kernel-config.patch +++ b/openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch @@ -1,7 +1,7 @@ -From 3f003e591567a7640b2d61f0bffc11ac9ff7c7dc Mon Sep 17 00:00:00 2001 +From b30be7ae94d7e846e2037b1f73aaff8d559756ab Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 7 Jul 2024 18:51:18 +0800 -Subject: [PATCH 6/7] build: kernel: add out-of-tree kernel config +Subject: [PATCH 09/11] build: kernel: add out-of-tree kernel config Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch deleted file mode 100644 index f6c73759b..000000000 --- a/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 41292e8bd135e0f1d293deb2cde4973ca0e763e5 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 26 Sep 2024 04:48:45 +0800 -Subject: [PATCH] tools: add llvm/clang toolchain - -Signed-off-by: sbwml ---- - tools/Makefile | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/tools/Makefile b/tools/Makefile -index 40c3ec1..c7f970b 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -29,6 +29,9 @@ endif - ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),) - BUILD_LZO_TOOLS = y - endif -+ifeq ($(or $(filter clang,$(CONFIG_KERNEL_CC)),$(filter y,$(CONFIG_BPF_TOOLCHAIN_HOST))),) -+ BUILD_CLANG_HOST = y -+endif - - tools-y += autoconf - tools-y += autoconf-archive -@@ -83,6 +86,7 @@ tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_TARGET_tegra),y) += cbootimage - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USES_MINOR),y) += kernel2minor - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_SPARSE),y) += sparse - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_LLVM_BUILD),y) += llvm-bpf -+tools-$(if $(BUILD_CLANG_HOST),y) += clang - - # builddir dependencies - $(curdir)/autoconf/compile := $(curdir)/m4/compile --- -2.43.5 - diff --git a/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch similarity index 85% rename from openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch rename to openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch index 4797de0a6..590380f1b 100644 --- a/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch +++ b/openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch @@ -1,7 +1,7 @@ -From dfd7696d643a76cf94ba267f888c2f3dc59fd626 Mon Sep 17 00:00:00 2001 +From c6f2d815fb9c4ed906831fb89d4a0bac4c00df3f Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 21 Sep 2024 04:08:14 +0800 -Subject: [PATCH] include: kernel: add miss config for linux-6.11 +Subject: [PATCH 10/11] include: kernel: add miss config for linux-6.11 Signed-off-by: sbwml --- @@ -21,5 +21,5 @@ index 408bf2f..8422004 100644 mv $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.old grep -v CONFIG_LTO $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/generic/010-meson-add-platform-variable-to-cross-compilation-file.patch b/openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch similarity index 84% rename from openwrt/patch/generic/010-meson-add-platform-variable-to-cross-compilation-file.patch rename to openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch index 26b16ab4f..fcd30a405 100644 --- a/openwrt/patch/generic/010-meson-add-platform-variable-to-cross-compilation-file.patch +++ b/openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch @@ -1,7 +1,7 @@ -From ff6ba001d151cf07a25af592e30a28df0b50ff19 Mon Sep 17 00:00:00 2001 +From dcdf87bf2596f1df7805390df133d429b74892ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Kocur?= Date: Wed, 31 Jan 2024 15:17:51 +0100 -Subject: [PATCH] meson: add platform variable to cross-compilation file +Subject: [PATCH 11/11] meson: add platform variable to cross-compilation file This patch adds the "platform" variable to the meson cross-compilation file for the ARM SoC. This variable is necessary to compile DPDK framework on ARM SoCs.(https://doc.dpdk.org/guides/linux_gsg/cross_build_dpdk_for_arm64.html) --- @@ -10,7 +10,7 @@ This patch adds the "platform" variable to the meson cross-compilation file for 2 files changed, 2 insertions(+) diff --git a/include/meson.mk b/include/meson.mk -index 7d67dcf298b3e..5a7c7a36fb4de 100644 +index 7d67dcf..5a7c7a3 100644 --- a/include/meson.mk +++ b/include/meson.mk @@ -89,6 +89,7 @@ define Meson/CreateCrossFile @@ -22,7 +22,7 @@ index 7d67dcf298b3e..5a7c7a36fb4de 100644 < $(MESON_DIR)/openwrt-cross.txt.in \ > $(1) diff --git a/tools/meson/files/openwrt-cross.txt.in b/tools/meson/files/openwrt-cross.txt.in -index ec4b027f1b783..e7cbcd0872111 100644 +index ec4b027..e7cbcd0 100644 --- a/tools/meson/files/openwrt-cross.txt.in +++ b/tools/meson/files/openwrt-cross.txt.in @@ -22,4 +22,5 @@ cpu = '@CPU@' @@ -31,3 +31,6 @@ index ec4b027f1b783..e7cbcd0872111 100644 [properties] +platform = '@PLAT@' needs_exe_wrapper = true +-- +2.43.5 + diff --git a/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch b/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch index 31e048c3c..4b2febe03 100644 --- a/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch +++ b/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch @@ -1,7 +1,7 @@ -From bd47c3f6ab80a3ebd69f7793de94ef3fc1592c1f Mon Sep 17 00:00:00 2001 +From 5a900bab61fcf9930d13c911004150345cdebc22 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 16 Feb 2024 23:44:25 +0800 -Subject: [PATCH] toolchain: gcc: update to 13.2 +Subject: [PATCH 1/3] toolchain: gcc: update to 13.2 Signed-off-by: sbwml --- @@ -2202,5 +2202,5 @@ index 8af05c9..4138e79 100644 @option{-Wno-pointer-sign}. -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch b/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch index 7dd83f268..74a9ec8db 100644 --- a/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch +++ b/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch @@ -1,3 +1,15 @@ +From 9e5c2ff4ad3358ff9ef7584c8a315ddd4995ffe8 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 26 Sep 2024 07:11:19 +0800 +Subject: [PATCH 2/3] toolchain: gcc: add support for GCC 14 + +Signed-off-by: sbwml +--- + toolchain/gcc/Config.in | 3 +++ + toolchain/gcc/Config.version | 5 +++++ + toolchain/gcc/common.mk | 4 ++++ + 3 files changed, 12 insertions(+) + diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in index 9156f9c..ca89051 100644 --- a/toolchain/gcc/Config.in @@ -13,7 +25,7 @@ index 9156f9c..ca89051 100644 config GCC_USE_GRAPHITE diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version -index 92033af..200a356 100644 +index 92033af..7ff5bc0 100644 --- a/toolchain/gcc/Config.version +++ b/toolchain/gcc/Config.version @@ -6,10 +6,15 @@ config GCC_VERSION_13 @@ -33,7 +45,7 @@ index 92033af..200a356 100644 config GCC_USE_DEFAULT_VERSION diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index cdbf9fa..f5db99f 100644 +index cdbf9fa..a1a5108 100644 --- a/toolchain/gcc/common.mk +++ b/toolchain/gcc/common.mk @@ -42,6 +42,10 @@ ifeq ($(PKG_VERSION),13.2.0) @@ -47,3 +59,6 @@ index cdbf9fa..f5db99f 100644 PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x BUGURL=http://bugs.openwrt.org/ +-- +2.43.5 + diff --git a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch index 18272cff3..ab5aef54f 100644 --- a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -1,3 +1,15 @@ +From 8d1db41ed127a9aa614dd5c1cb17c4bb8a7005a0 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 26 Sep 2024 07:12:34 +0800 +Subject: [PATCH 3/3] toolchain: gcc: add support for GCC 15 + +Signed-off-by: sbwml +--- + toolchain/gcc/Config.in | 3 +++ + toolchain/gcc/Config.version | 5 +++++ + toolchain/gcc/common.mk | 10 +++++++++- + 3 files changed, 17 insertions(+), 1 deletion(-) + diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in index ca89051..510c813 100644 --- a/toolchain/gcc/Config.in @@ -34,7 +46,7 @@ index 7ff5bc0..7d8ee09 100644 config GCC_USE_DEFAULT_VERSION diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index a1a5108..7ec50ad 100644 +index a1a5108..feae36a 100644 --- a/toolchain/gcc/common.mk +++ b/toolchain/gcc/common.mk @@ -26,7 +26,11 @@ PKG_VERSION:=$(firstword $(subst +, ,$(GCC_VERSION))) @@ -61,3 +73,6 @@ index a1a5108..7ec50ad 100644 PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x BUGURL=http://bugs.openwrt.org/ +-- +2.43.5 + diff --git a/openwrt/patch/openwrt-6.x/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch b/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch similarity index 93% rename from openwrt/patch/openwrt-6.x/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch rename to openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch index 8a416e299..fba38b980 100644 --- a/openwrt/patch/openwrt-6.x/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch +++ b/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch @@ -1,4 +1,4 @@ -From 92b82f0545fa658e358a85db8c7acee706c5c520 Mon Sep 17 00:00:00 2001 +From 09a3ce6cd32555c06db829f5b56b23b0d47b5ebe Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Fri, 27 Jan 2023 16:35:46 +0100 Subject: [PATCH 1/8] build: add support to use the mold linker for packages diff --git a/openwrt/patch/openwrt-6.x/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch b/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch similarity index 97% rename from openwrt/patch/openwrt-6.x/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch rename to openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch index 2c450056f..e4f12af50 100644 --- a/openwrt/patch/openwrt-6.x/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch +++ b/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch @@ -1,4 +1,4 @@ -From 149aef90a292c51bd820554ad7cc4c233f400c97 Mon Sep 17 00:00:00 2001 +From 9a4fc4505a6cd8e74bd05df02ef8cc88662a8be7 Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Fri, 27 Jan 2023 18:22:43 +0100 Subject: [PATCH 2/8] treewide: opt-out of tree-wide mold usage diff --git a/openwrt/patch/openwrt-6.x/mold/0003-toolchain-add-mold-as-additional-linker.patch b/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch similarity index 96% rename from openwrt/patch/openwrt-6.x/mold/0003-toolchain-add-mold-as-additional-linker.patch rename to openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch index 819280982..2e09bcfa5 100644 --- a/openwrt/patch/openwrt-6.x/mold/0003-toolchain-add-mold-as-additional-linker.patch +++ b/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch @@ -1,4 +1,4 @@ -From 6a9bd83f7b3f513bebb142ef07392cf5ed218a65 Mon Sep 17 00:00:00 2001 +From 0de92a05246317259aa4e071689b0fca26e108db Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Fri, 27 Jan 2023 17:53:02 +0100 Subject: [PATCH 3/8] toolchain: add mold as additional linker diff --git a/openwrt/patch/openwrt-6.x/mold/0004-tools-add-mold-a-modern-linker.patch b/openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch similarity index 91% rename from openwrt/patch/openwrt-6.x/mold/0004-tools-add-mold-a-modern-linker.patch rename to openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch index d9a61ac29..ea93b799a 100644 --- a/openwrt/patch/openwrt-6.x/mold/0004-tools-add-mold-a-modern-linker.patch +++ b/openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch @@ -1,4 +1,4 @@ -From 5c32e0a110bd6269136ff90ade852c783d169ecf Mon Sep 17 00:00:00 2001 +From fdadb3131437c1f64d801ca7cf65c527f69a8a5f Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Fri, 27 Jan 2023 17:53:02 +0100 Subject: [PATCH 4/8] tools: add mold, a modern linker @@ -19,10 +19,10 @@ Signed-off-by: Andre Heider create mode 100644 tools/mold/Makefile diff --git a/tools/Makefile b/tools/Makefile -index feae919..231706c 100644 +index e4afc87..6f27de5 100644 --- a/tools/Makefile +++ b/tools/Makefile -@@ -84,6 +84,7 @@ tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_TARGET_tegra),y) += cbootimage +@@ -91,6 +91,7 @@ tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_TARGET_tegra),y) += cbootimage tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USES_MINOR),y) += kernel2minor tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_SPARSE),y) += sparse tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_LLVM_BUILD),y) += llvm-bpf @@ -30,7 +30,7 @@ index feae919..231706c 100644 # builddir dependencies $(curdir)/autoconf/compile := $(curdir)/m4/compile -@@ -115,6 +116,7 @@ $(curdir)/meson/compile := $(curdir)/ninja/compile +@@ -122,6 +123,7 @@ $(curdir)/meson/compile := $(curdir)/ninja/compile $(curdir)/missing-macros/compile := $(curdir)/autoconf/compile $(curdir)/mkimage/compile += $(curdir)/bison/compile $(curdir)/libressl/compile $(curdir)/mklibs/compile := $(curdir)/libtool/compile diff --git a/openwrt/patch/openwrt-6.x/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch b/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch similarity index 96% rename from openwrt/patch/openwrt-6.x/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch rename to openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch index d4554926d..ac6139e93 100644 --- a/openwrt/patch/openwrt-6.x/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch +++ b/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch @@ -1,4 +1,4 @@ -From 9cadac681ca14daeb97a8ebfaa32d13c0a375ff2 Mon Sep 17 00:00:00 2001 +From a5f1c52a8ce42243323a9a79bbd29128af1920a2 Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Sat, 28 Jan 2023 21:16:16 +0100 Subject: [PATCH 5/8] build: replace SSTRIP_ARGS with diff --git a/openwrt/patch/openwrt-6.x/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch b/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch similarity index 97% rename from openwrt/patch/openwrt-6.x/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch rename to openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch index 825d61c40..36a7dbf75 100644 --- a/openwrt/patch/openwrt-6.x/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch +++ b/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch @@ -1,4 +1,4 @@ -From 9494bba487dc290f0fa3cf51f3deac8ea4bd8080 Mon Sep 17 00:00:00 2001 +From 5840abe142ba5e5e6bfcaa6435887990f2568cec Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Fri, 27 Jan 2023 17:13:15 +0100 Subject: [PATCH 6/8] config: add a knob to use the mold linker for packages diff --git a/openwrt/patch/openwrt-6.x/mold/0007-rules-prepare-to-use-different-linkers.patch b/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch similarity index 95% rename from openwrt/patch/openwrt-6.x/mold/0007-rules-prepare-to-use-different-linkers.patch rename to openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch index 4bf03ed2d..2b2d75558 100644 --- a/openwrt/patch/openwrt-6.x/mold/0007-rules-prepare-to-use-different-linkers.patch +++ b/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch @@ -1,4 +1,4 @@ -From 8086e16507bf6e510c01f616a07282632bd97897 Mon Sep 17 00:00:00 2001 +From def4db1bbcef727db78dbce12dc95df9903f135f Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Fri, 27 Jan 2023 16:32:31 +0100 Subject: [PATCH 7/8] rules: prepare to use different linkers diff --git a/openwrt/patch/openwrt-6.x/mold/0008-tools-mold-update-to-2.32.1.patch b/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch similarity index 76% rename from openwrt/patch/openwrt-6.x/mold/0008-tools-mold-update-to-2.32.1.patch rename to openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch index 796be63b3..3641d2af5 100644 --- a/openwrt/patch/openwrt-6.x/mold/0008-tools-mold-update-to-2.32.1.patch +++ b/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch @@ -1,7 +1,7 @@ -From b9575ea4cfe2acf4e7e19635f7bf6a5a40ea75ca Mon Sep 17 00:00:00 2001 +From 76471b08d9e1b5e9686b4444c5db53dd9c56bcfe Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 17 Jul 2024 08:51:39 +0800 -Subject: [PATCH 8/8] tools/mold: update to 2.32.1 +Subject: [PATCH 8/8] tools/mold: update to 2.34.0 Signed-off-by: sbwml --- @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/mold/Makefile b/tools/mold/Makefile -index e8fcecb..f6efb80 100644 +index e8fcecb..d0b4443 100644 --- a/tools/mold/Makefile +++ b/tools/mold/Makefile @@ -3,12 +3,11 @@ @@ -17,14 +17,14 @@ index e8fcecb..f6efb80 100644 PKG_NAME:=mold -PKG_VERSION:=1.11.0 -+PKG_VERSION:=2.32.1 ++PKG_VERSION:=2.34.0 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz -PKG_SOURCE_URL:=https://github.com/rui314/mold/archive/refs/tags -PKG_HASH:=99318eced81b09a77e4c657011076cc8ec3d4b6867bd324b8677974545bc4d6f +PKG_SOURCE_URL:=https://codeload.github.com/rui314/mold/tar.gz/v$(PKG_VERSION)? -+PKG_HASH:=f3c9a527d884c635834fe7d79b3de959b00783bf9446280ea274d996f0335825 ++PKG_HASH:=6067f41f624c32cb0f4e959ae7fabee5dd71dd06771e2c069c2b3a6a8eca3c8c include $(INCLUDE_DIR)/host-build.mk include $(INCLUDE_DIR)/cmake.mk diff --git a/openwrt/patch/upx/Makefile b/openwrt/patch/upx/Makefile deleted file mode 100644 index e01375d6d..000000000 --- a/openwrt/patch/upx/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=upx -PKG_VERSION:=4.2.4 - -PKG_SOURCE:=upx-$(PKG_VERSION)-src.tar.xz -PKG_SOURCE_URL:=https://github.com/upx/upx/releases/download/v$(PKG_VERSION)/ -PKG_HASH:=5ed6561607d27fb4ef346fc19f08a93696fa8fa127081e7a7114068306b8e1c4 - -HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)-src -HOST_BUILD_PARALLEL:=1 - -include $(INCLUDE_DIR)/host-build.mk - -define Host/Compile - UPX_UCLDIR=$(STAGING_DIR_HOST) \ - $(MAKE) -C $(HOST_BUILD_DIR)/src \ - LDFLAGS="$(HOST_LDFLAGS)" \ - CXX="$(HOSTCXX)" -endef - -define Host/Install - $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin - $(INSTALL_BIN) $(HOST_BUILD_DIR)/build/release/upx $(STAGING_DIR_HOST)/bin/upx -endef - -define Host/Clean - rm -f $(STAGING_DIR_HOST)/bin/upx -endef - -$(eval $(call HostBuild)) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 3c8d4e4f6..d30bb1867 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -10,45 +10,59 @@ else git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip -b 0419 fi -# BTF: fix failed to validate module -# config/Config-kernel.in patch -curl -s https://$mirror/openwrt/patch/generic/0001-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch | patch -p1 +######## OpenWrt Patches ######## + +# tools: add llvm/clang toolchain +curl -s https://$mirror/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch | patch -p1 # tools: add upx tools -mkdir -p tools/upx -curl -s https://$mirror/openwrt/patch/upx/Makefile > tools/upx/Makefile -sed -i "/tools-y += sstrip/atools-y += upx" tools/Makefile +curl -s https://$mirror/openwrt/patch/generic/0002-tools-add-upx-tools.patch | patch -p1 # rootfs: upx compression # include/rootfs.mk -curl -s https://$mirror/openwrt/patch/generic/0002-rootfs-add-upx-compression-support.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch | patch -p1 + +# rootfs: add r/w (0600) permissions for UCI configuration files +# include/rootfs.mk +curl -s https://$mirror/openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 + +# rootfs: Add support for local kmod installation sources +curl -s https://$mirror/openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 + +# BTF: fix failed to validate module +# config/Config-kernel.in patch +curl -s https://$mirror/openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch | patch -p1 # kernel: Add support for llvm/clang compiler -curl -s https://$mirror/openwrt/patch/generic/0003-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 # toolchain: Add libquadmath to the toolchain -curl -s https://$mirror/openwrt/patch/generic/0004-libquadmath-Add-libquadmath-to-the-toolchain.patch | patch -p1 - -# rootfs: add r/w (0600) permissions for UCI configuration files -# include/rootfs.mk -curl -s https://$mirror/openwrt/patch/generic/0005-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch | patch -p1 # build: kernel: add out-of-tree kernel config -curl -s https://$mirror/openwrt/patch/generic/0006-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 - -# rootfs: Add support for local kmod installation sources -curl -s https://$mirror/openwrt/patch/generic/0007-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 # kernel: linux-6.11 config -curl -s https://$mirror/openwrt/patch/generic/0008-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 - -# tools: add llvm/clang toolchain -curl -s https://$mirror/openwrt/patch/generic/0009-tools-add-llvm-clang-toolchain.patch | patch -p1 -mkdir -p tools/clang -curl -s https://$mirror/openwrt/patch/clang/Makefile > tools/clang/Makefile +curl -s https://$mirror/openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 # meson: add platform variable to cross-compilation file -curl -s https://$mirror/openwrt/patch/generic/010-meson-add-platform-variable-to-cross-compilation-file.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 + +# mold +if [ "$ENABLE_MOLD" = "y" ]; then + curl -s https://$mirror/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch | patch -p1 + # no-mold + sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile +fi + +######## OpenWrt Patches End ######## # dwarves: Fix a dwarf type DW_ATE_unsigned_1024 to btf encoding issue mkdir -p tools/dwarves/patches @@ -91,6 +105,16 @@ else curl -s https://$mirror/openwrt/patch/target-modify_for_rockchip.patch | patch -p1 fi +# DPDK & NUMACTL +if [ "$ENABLE_DPDK" = "y" ]; then + mkdir -p package/new/{dpdk/patches,numactl} + curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Makefile > package/new/dpdk/Makefile + curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Config.in > package/new/dpdk/Config.in + curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch > package/new/dpdk/patches/010-dpdk_arm_build_platform_fix.patch + curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch > package/new/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch + curl -s https://$mirror/openwrt/patch/dpdk/numactl/Makefile > package/new/numactl/Makefile +fi + # IF USE GLIBC if [ "$ENABLE_GLIBC" = "y" ]; then # musl-libc @@ -111,30 +135,6 @@ if [ "$ENABLE_GLIBC" = "y" ]; then sed -i "/disable-profile/d" toolchain/glibc/common.mk fi -# DPDK & NUMACTL -if [ "$ENABLE_DPDK" = "y" ]; then - mkdir -p package/new/{dpdk/patches,numactl} - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Makefile > package/new/dpdk/Makefile - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Config.in > package/new/dpdk/Config.in - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch > package/new/dpdk/patches/010-dpdk_arm_build_platform_fix.patch - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch > package/new/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch - curl -s https://$mirror/openwrt/patch/dpdk/numactl/Makefile > package/new/numactl/Makefile -fi - -# mold -if [ "$ENABLE_MOLD" = "y" ]; then - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0003-toolchain-add-mold-as-additional-linker.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0004-tools-add-mold-a-modern-linker.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0007-rules-prepare-to-use-different-linkers.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/mold/0008-tools-mold-update-to-2.30.0.patch | patch -p1 - # no-mold - sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile -fi - # Mbedtls AES & GCM Crypto Extensions if [ ! "$platform" = "x86_64" ]; then curl -s https://$mirror/openwrt/patch/mbedtls-23.05/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch > package/libs/mbedtls/patches/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch From 5af1890e15b0b71e08eb74ea8e9611665417783a Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 26 Sep 2024 21:53:09 +0800 Subject: [PATCH 034/425] tools/clang: clean the build directory Signed-off-by: sbwml --- .../generic/0001-tools-add-llvm-clang-toolchain.patch | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch index c387227c4..9f58efeb2 100644 --- a/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch +++ b/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch @@ -6,8 +6,8 @@ Subject: [PATCH 01/11] tools: add llvm/clang toolchain Signed-off-by: sbwml --- tools/Makefile | 7 +++++++ - tools/clang/Makefile | 42 ++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 49 insertions(+) + tools/clang/Makefile | 43 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+) create mode 100644 tools/clang/Makefile diff --git a/tools/Makefile b/tools/Makefile @@ -37,10 +37,10 @@ index 40c3ec1..88250b3 100644 tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_BZIP2_TOOLS),y) += bzip2 diff --git a/tools/clang/Makefile b/tools/clang/Makefile new file mode 100644 -index 0000000..20927f7 +index 0000000..0fcd4d0 --- /dev/null +++ b/tools/clang/Makefile -@@ -0,0 +1,42 @@ +@@ -0,0 +1,43 @@ +# +# Copyright (C) 2006-2017 OpenWrt.org +# @@ -71,7 +71,8 @@ index 0000000..20927f7 +endef + +define Host/Install -+ $(CP) $(HOST_BUILD_DIR)/{bin,include,lib,share} $(STAGING_DIR_HOST)/ ++ $(CP) -a $(HOST_BUILD_DIR)/{bin,include,lib,share} $(STAGING_DIR_HOST)/ ++ $(RM) -rf $(HOST_BUILD_DIR)/{bin,include,lib,share} +endef + +define Host/Uninstall From c8e90fe97bccffd7df62f94255d9a4871e184562 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 28 Sep 2024 17:58:41 +0800 Subject: [PATCH 035/425] tools/clang: update llvm optimized version * reduce kernel compilation time Signed-off-by: sbwml --- .../0001-tools-add-llvm-clang-toolchain.patch | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch index 9f58efeb2..bb5deace2 100644 --- a/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch +++ b/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch @@ -51,11 +51,11 @@ index 0000000..0fcd4d0 +include $(TOPDIR)/rules.mk + +PKG_NAME:=clang -+PKG_VERSION:=19.1.0 ++PKG_VERSION:=19.0.1 + -+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz -+PKG_SOURCE_URL:=https://github.com/sbwml/redhat-llvm-project/releases/download/$(PKG_VERSION)/ -+PKG_HASH:=21c9d10911eeccd31ab648da1beabe94048ecda441149bbba0a12302f105f337 ++PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz ++PKG_SOURCE_URL:=https://github.com/sbwml/openwrt-llvm-toolchain/releases/download/$(PKG_VERSION)/ ++PKG_HASH:=a73c5ec6d62e0f47fd3cf25e3904b5818b18695b7302a9b404e411f2085110a3 + +PKG_MAINTAINER:=sbwml +PKG_LICENSE:=Apache-2.0 @@ -64,22 +64,22 @@ index 0000000..0fcd4d0 +include $(INCLUDE_DIR)/host-build.mk + +define Host/Prepare -+ $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-redhat-linux.tar.xz ++ $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz +endef + +define Host/Compile +endef + +define Host/Install -+ $(CP) -a $(HOST_BUILD_DIR)/{bin,include,lib,share} $(STAGING_DIR_HOST)/ -+ $(RM) -rf $(HOST_BUILD_DIR)/{bin,include,lib,share} ++ $(CP) -a $(HOST_BUILD_DIR)/{bin,include,lib} $(STAGING_DIR_HOST)/ ++ $(RM) -rf $(HOST_BUILD_DIR)/{bin,include,lib,libexec,share} +endef + +define Host/Uninstall + ( \ -+ rm -rf $(STAGING_DIR_HOST)/bin/{FileCheck,clang*,dsymutil,git-clang-format,*lld*,llc,llvm*,merge-fdata,opt,perf2bolt,run-clang-tidy,wasm-ld,yaml2obj} ; \ -+ rm -rf $(STAGING_DIR_HOST)/include/{c++,clang,clang-c,__libunwind_config.h,libunwind.h,libunwind.modulemap,lld,llvm,llvm-c,mach-o,unwind_arm_ehabi.h,unwind.h,unwind_itanium.h,x86_64-redhat-linux-gnu} ; \ -+ rm -rf $(STAGING_DIR_HOST)/lib/{bfd-plugins,clang,cmake,x86_64-redhat-linux-gnu,LLVMgold.so,libLLVM*,libLTO*,libPolly.a,libRemarks.so*,libclang*,libedit*,libfindAllSymbols.a,liblld*,liblzma*,libncurses*,libxml2*} ; \ ++ rm -rf $(STAGING_DIR_HOST)/bin/{*clang*,dsymutil,find-all-symbols,*lld*,llc,lli,llvm*,merge-fdata,opt,perf2bolt,wasm-ld} ; \ ++ rm -rf $(STAGING_DIR_HOST)/include/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,c++,clang*,i386-unknown-linux-gnu,i686-unknown-linux-musl,lld,llvm*,mach-o,polly,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ ++ rm -rf $(STAGING_DIR_HOST)/lib/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,bfd-plugins,clang,cmake,i386-unknown-linux-gnu,i686-unknown-linux-musl,libbolt*,libfindAllSymbols.a,liblld*,*LLVM*,libPolly*,libRemarks.so,libxml2*,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ + ) +endef + From 930c34a37783818193c14a559a37503cd0ec8ca8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 28 Sep 2024 19:54:58 +0800 Subject: [PATCH 036/425] build.sh: do not include clang into the toolchain cache * Exceeding GitHub's single file size :( Signed-off-by: sbwml --- openwrt/build.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index a507ba598..71bf35717 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -416,12 +416,18 @@ fi if [ "$BUILD_TOOLCHAIN" = "y" ]; then echo -e "\r\n${GREEN_COLOR}Building Toolchain ...${RES}\r\n" make -j$cores toolchain/compile || make -j$cores toolchain/compile V=s || exit 1 + make tools/clang/clean + rm -f dl/clang-* mkdir -p toolchain-cache [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl tar -I "zstd -19 -T$(nproc --all)" -cf toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_gcc-"$gcc_version".tar.zst ./{build_dir,dl,staging_dir,tmp} - echo -e "${GREEN_COLOR} Build success! ${RES}" + echo -e "\n${GREEN_COLOR} Build success! ${RES}" exit 0 else + if [ "$BUILD_FAST" = "y" ]; then + echo -e "\r\n${GREEN_COLOR}Building tools/clang ...${RES}\r\n" + make tools/clang/compile -j$cores + fi echo -e "\r\n${GREEN_COLOR}Building OpenWrt ...${RES}\r\n" sed -i "/BUILD_DATE/d" package/base-files/files/usr/lib/os-release sed -i "/BUILD_ID/aBUILD_DATE=\"$CURRENT_DATE\"" package/base-files/files/usr/lib/os-release From 41f8e7f878af2af08c1016ffc57f92f9d851dc20 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 28 Sep 2024 20:28:41 +0800 Subject: [PATCH 037/425] script: using a private repository for my own build Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 99b75f8ad..16dda0ea3 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -46,12 +46,11 @@ grep HASH include/kernel-$kernel_version | awk -F'HASH-' '{print $2}' | awk '{pr rm -rf target/linux/generic local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-$kernel_version) release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-$kernel_version | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') -if [ "$local_kernel_version" = "$release_kernel_version" ]; then +if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ]; then git clone https://$github/sbwml/target_linux_generic -b main target/linux/generic --depth=1 else if [ "$(whoami)" = "runner" ]; then git_name=private - git_password="$git_password" git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b main target/linux/generic --depth=1 elif [ "$(whoami)" = "sbwml" ]; then git clone https://$gitea/sbwml/target_linux_generic -b main target/linux/generic --depth=1 From c3526a6b1c439b1975c72045ffb72813990bf3b5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 29 Sep 2024 05:10:33 +0800 Subject: [PATCH 038/425] ci: enable `KERNEL_CLANG_LTO` by default Signed-off-by: sbwml --- .github/workflows/build-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 59ac23a74..def0bfba1 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,7 +17,7 @@ on: build_options: description: 'Build options (separate multiple options with spaces)' required: false - default: 'BUILD_FAST=y ENABLE_LTO=y ENABLE_MOLD=y ENABLE_LRNG=y ENABLE_BPF=y USE_GCC14=y' + default: 'BUILD_FAST=y ENABLE_BPF=y ENABLE_LTO=y ENABLE_LRNG=y ENABLE_MOLD=y KERNEL_CLANG_LTO=y USE_GCC14=y' type: string jobs: From 6311d24363bc23a8e28546ed46ffdaecde6be787 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 30 Sep 2024 03:55:24 +0800 Subject: [PATCH 039/425] mac80211: update version to 6.11 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 16dda0ea3..fb40009c8 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -186,19 +186,12 @@ curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > pa # mac80211 - fix linux 6.6 & add rtw89 rm -rf package/kernel/mac80211 -if [ "$TESTING_KERNEL" = "y" ]; then - git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 -else - git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.9.9 -fi +git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 +[ "$TESTING_KERNEL" = "y" ] && rm -f package/kernel/mac80211/patches/build/140-trace_backport.patch # ath10k-ct rm -rf package/kernel/ath10k-ct -if [ "$TESTING_KERNEL" = "y" ]; then - git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.11 -else - git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -fi +git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.11 # kernel patch # btf: silence btf module warning messages From 7b4acc159758b8ed56b77bf4aeb7b6b5bf718c66 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 30 Sep 2024 03:56:42 +0800 Subject: [PATCH 040/425] mt76: update to 2024-09-29 Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 79 +++++++- ...ix-build-with-mac80211-6.11-backport.patch | 189 ------------------ openwrt/scripts/01-prepare_base-mainline.sh | 9 +- 3 files changed, 77 insertions(+), 200 deletions(-) diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 4589a7e87..e35cd6114 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2024-09-05 -PKG_SOURCE_VERSION:=65cc3daf2a332cc658e9f7438cdadde4392e672e -PKG_MIRROR_HASH:=fa4f75d2b7414b638f01374a6bd149681dac1cc8bbd3f2aa0b2e46415521fc97 +PKG_SOURCE_DATE:=2024-09-29 +PKG_SOURCE_VERSION:=680bc70f161fde0f167e2ae50c771be4775eb50a +PKG_MIRROR_HASH:=dff0656a68f05779f9563baee8abb55faeeda79dbc24b99c1f4904af5a69821a PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 @@ -323,10 +323,34 @@ define KernelPackage/mt7996e AUTOLOAD:=$(call AutoProbe,mt7996e) endef +define KernelPackage/mt7992-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7992 firmware + DEPENDS+=+kmod-mt7996e +endef + +define KernelPackage/mt7992-23-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996 firmware (2+3 antenna variant) + DEPENDS+=+kmod-mt7996e +endef + +define KernelPackage/mt7996-firmware-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996 firmware (common files) + HIDDEN:=1 +endef + define KernelPackage/mt7996-firmware $(KernelPackage/mt76-default) TITLE:=MediaTek MT7996 firmware - DEPENDS+=+kmod-mt7996e + DEPENDS+=+kmod-mt7996e +kmod-mt7996-firmware-common +endef + +define KernelPackage/mt7996-233-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996 firmware (2+3+3 antenna variant) + DEPENDS+=+kmod-mt7996e +kmod-mt7996-firmware-common endef define KernelPackage/mt7925-firmware @@ -630,17 +654,58 @@ define KernelPackage/mt7925-firmware/install $(1)/lib/firmware/mediatek/mt7925 endef -define KernelPackage/mt7996-firmware/install +define KernelPackage/mt7992-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define KernelPackage/mt7992-23-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm_23.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define KernelPackage/mt7996-firmware-common/install $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 cp \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_dsp.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define KernelPackage/mt7996-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_2i5i6i.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_rom_patch.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wa.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wm.bin \ $(1)/lib/firmware/mediatek/mt7996 endef +define KernelPackage/mt7996-233-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_233.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_233_2i5i6i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_rom_patch_233.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wa_233.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wm_233.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + define Package/mt76-test/install mkdir -p $(1)/usr/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/tools/mt76-test $(1)/usr/sbin @@ -691,6 +756,10 @@ $(eval $(call KernelPackage,mt7921e)) $(eval $(call KernelPackage,mt7925u)) $(eval $(call KernelPackage,mt7925e)) $(eval $(call KernelPackage,mt7996e)) +$(eval $(call KernelPackage,mt7992-firmware)) +$(eval $(call KernelPackage,mt7992-23-firmware)) +$(eval $(call KernelPackage,mt7996-firmware-common)) $(eval $(call KernelPackage,mt7996-firmware)) +$(eval $(call KernelPackage,mt7996-233-firmware)) $(eval $(call KernelPackage,mt76)) $(eval $(call BuildPackage,mt76-test)) diff --git a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch index b897c2690..ef08a3494 100644 --- a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +++ b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch @@ -9,17 +9,6 @@ .nid = NUMA_NO_NODE, .dev = dev->dma_dev, }; ---- a/mt7603/main.c -+++ b/mt7603/main.c -@@ -23,7 +23,7 @@ mt7603_start(struct ieee80211_hw *hw) - } - - static void --mt7603_stop(struct ieee80211_hw *hw) -+mt7603_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt7603_dev *dev = hw->priv; - --- a/mt7603/soc.c +++ b/mt7603/soc.c @@ -52,15 +52,12 @@ error: @@ -48,17 +37,6 @@ .driver = { .name = "mt76_wmac", .of_match_table = of_wmac_match, ---- a/mt7615/main.c -+++ b/mt7615/main.c -@@ -91,7 +91,7 @@ out: - return ret; - } - --static void mt7615_stop(struct ieee80211_hw *hw) -+static void mt7615_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt7615_dev *dev = mt7615_hw_dev(hw); - struct mt7615_phy *phy = mt7615_hw_phy(hw); --- a/mt7615/mt7615_trace.h +++ b/mt7615/mt7615_trace.h @@ -14,7 +14,7 @@ @@ -96,39 +74,6 @@ }; MODULE_FIRMWARE(MT7622_FIRMWARE_N9); ---- a/mt7615/usb.c -+++ b/mt7615/usb.c -@@ -79,7 +79,7 @@ static void mt7663u_copy(struct mt76_dev - mutex_unlock(&usb->usb_ctrl_mtx); - } - --static void mt7663u_stop(struct ieee80211_hw *hw) -+static void mt7663u_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt7615_phy *phy = mt7615_hw_phy(hw); - struct mt7615_dev *dev = hw->priv; ---- a/mt76x0/pci.c -+++ b/mt76x0/pci.c -@@ -44,7 +44,7 @@ static void mt76x0e_stop_hw(struct mt76x - mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN); - } - --static void mt76x0e_stop(struct ieee80211_hw *hw) -+static void mt76x0e_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt76x02_dev *dev = hw->priv; - ---- a/mt76x0/usb.c -+++ b/mt76x0/usb.c -@@ -77,7 +77,7 @@ static void mt76x0u_cleanup(struct mt76x - mt76u_queues_deinit(&dev->mt76); - } - --static void mt76x0u_stop(struct ieee80211_hw *hw) -+static void mt76x0u_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt76x02_dev *dev = hw->priv; - --- a/mt76x02_trace.h +++ b/mt76x02_trace.h @@ -14,7 +14,7 @@ @@ -140,140 +85,6 @@ wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) #define DEV_PR_FMT "%s" #define DEV_PR_ARG __entry->wiphy_name ---- a/mt76x2/pci_main.c -+++ b/mt76x2/pci_main.c -@@ -24,7 +24,7 @@ mt76x2_start(struct ieee80211_hw *hw) - } - - static void --mt76x2_stop(struct ieee80211_hw *hw) -+mt76x2_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt76x02_dev *dev = hw->priv; - ---- a/mt76x2/usb_main.c -+++ b/mt76x2/usb_main.c -@@ -22,7 +22,7 @@ static int mt76x2u_start(struct ieee8021 - return 0; - } - --static void mt76x2u_stop(struct ieee80211_hw *hw) -+static void mt76x2u_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt76x02_dev *dev = hw->priv; - ---- a/mt7915/main.c -+++ b/mt7915/main.c -@@ -108,7 +108,7 @@ static int mt7915_start(struct ieee80211 - return ret; - } - --static void mt7915_stop(struct ieee80211_hw *hw) -+static void mt7915_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt7915_dev *dev = mt7915_hw_dev(hw); - struct mt7915_phy *phy = mt7915_hw_phy(hw); ---- a/mt7915/mcu.c -+++ b/mt7915/mcu.c -@@ -335,7 +335,7 @@ mt7915_mcu_cca_finish(void *priv, u8 *ma - if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) - return; - -- ieee80211_color_change_finish(vif); -+ ieee80211_color_change_finish(vif, 0); - } - - static void ---- a/mt7921/main.c -+++ b/mt7921/main.c -@@ -268,7 +268,7 @@ static int mt7921_start(struct ieee80211 - return err; - } - --static void mt7921_stop(struct ieee80211_hw *hw) -+static void mt7921_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - int err = 0; -@@ -281,7 +281,7 @@ static void mt7921_stop(struct ieee80211 - return; - } - -- mt792x_stop(hw); -+ mt792x_stop(hw, false); - } - - static int ---- a/mt792x.h -+++ b/mt792x.h -@@ -337,7 +337,7 @@ static inline bool mt792x_dma_need_reini - #define mt792x_mutex_release(dev) \ - mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) - --void mt792x_stop(struct ieee80211_hw *hw); -+void mt792x_stop(struct ieee80211_hw *hw, bool suspend); - void mt792x_pm_wake_work(struct work_struct *work); - void mt792x_pm_power_save_work(struct work_struct *work); - void mt792x_reset(struct mt76_dev *mdev); -@@ -457,7 +457,7 @@ void mt792xu_wr(struct mt76_dev *dev, u3 - u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val); - void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len); - void mt792xu_disconnect(struct usb_interface *usb_intf); --void mt792xu_stop(struct ieee80211_hw *hw); -+void mt792xu_stop(struct ieee80211_hw *hw, bool suspend); - - static inline void - mt792x_skb_add_usb_sdio_hdr(struct mt792x_dev *dev, struct sk_buff *skb, ---- a/mt792x_core.c -+++ b/mt792x_core.c -@@ -113,7 +113,7 @@ void mt792x_tx(struct ieee80211_hw *hw, - } - EXPORT_SYMBOL_GPL(mt792x_tx); - --void mt792x_stop(struct ieee80211_hw *hw) -+void mt792x_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt792x_phy *phy = mt792x_hw_phy(hw); ---- a/mt792x_usb.c -+++ b/mt792x_usb.c -@@ -285,12 +285,12 @@ int mt792xu_init_reset(struct mt792x_dev - } - EXPORT_SYMBOL_GPL(mt792xu_init_reset); - --void mt792xu_stop(struct ieee80211_hw *hw) -+void mt792xu_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - - mt76u_stop_tx(&dev->mt76); -- mt792x_stop(hw); -+ mt792x_stop(hw, false); - } - EXPORT_SYMBOL_GPL(mt792xu_stop); - ---- a/mt7996/main.c -+++ b/mt7996/main.c -@@ -93,7 +93,7 @@ static int mt7996_start(struct ieee80211 - return ret; - } - --static void mt7996_stop(struct ieee80211_hw *hw) -+static void mt7996_stop(struct ieee80211_hw *hw, bool suspend) - { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); ---- a/mt7996/mcu.c -+++ b/mt7996/mcu.c -@@ -421,7 +421,7 @@ mt7996_mcu_cca_finish(void *priv, u8 *ma - if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) - return; - -- ieee80211_color_change_finish(vif); -+ ieee80211_color_change_finish(vif, 0); - } - - static void --- a/trace.h +++ b/trace.h @@ -14,7 +14,7 @@ diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index fb40009c8..105f7f35f 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -163,14 +163,11 @@ else git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac fi -# mt76 - 2024-05-17 -rm -rf package/kernel/mt76/patches +# mt76 - 2024-09-29 +rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile -[ "$TESTING_KERNEL" = "y" ] && { - mkdir -p package/kernel/mt76/patches ; \ - curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch -} +curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch # iwinfo: add mt7922 device id mkdir -p package/network/utils/iwinfo/patches From d3275eb08f6624e5d63fc8e032abc52488c31484 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 30 Sep 2024 04:32:22 +0800 Subject: [PATCH 041/425] config: create config-firmware Signed-off-by: sbwml --- openwrt/23-config-musl-armsr-armv8 | 8 -------- openwrt/23-config-musl-r5s | 11 ----------- openwrt/23-config-musl-x86 | 11 ----------- openwrt/build.sh | 15 +++++++-------- openwrt/generic/config-firmware | 11 +++++++++++ 5 files changed, 18 insertions(+), 38 deletions(-) create mode 100644 openwrt/generic/config-firmware diff --git a/openwrt/23-config-musl-armsr-armv8 b/openwrt/23-config-musl-armsr-armv8 index 663c30b53..b50523d80 100644 --- a/openwrt/23-config-musl-armsr-armv8 +++ b/openwrt/23-config-musl-armsr-armv8 @@ -20,11 +20,3 @@ CONFIG_COREMARK_NUMBER_OF_THREADS=16 ### Utilities CONFIG_PACKAGE_qemu-ga=y - -### RTL8723D / RTL8821C / RTW89 firmware -CONFIG_PACKAGE_rtl8723de-firmware=m -CONFIG_PACKAGE_rtl8821ce-firmware=m -CONFIG_PACKAGE_rtl8851be-firmware=m -CONFIG_PACKAGE_rtl8852ae-firmware=m -CONFIG_PACKAGE_rtl8852be-firmware=m -CONFIG_PACKAGE_rtl8852ce-firmware=m diff --git a/openwrt/23-config-musl-r5s b/openwrt/23-config-musl-r5s index ca5e9b674..d39a9c132 100644 --- a/openwrt/23-config-musl-r5s +++ b/openwrt/23-config-musl-r5s @@ -24,14 +24,3 @@ CONFIG_COREMARK_NUMBER_OF_THREADS=6 ### Video Support CONFIG_PACKAGE_kmod-drm-rockchip=y CONFIG_PACKAGE_kmod-drm-panfrost=y - -### RTL8723D / RTL8821C / RTW89 firmware -CONFIG_PACKAGE_rtl8723de-firmware=m -CONFIG_PACKAGE_rtl8821ce-firmware=m -CONFIG_PACKAGE_rtl8851be-firmware=m -CONFIG_PACKAGE_rtl8852ae-firmware=m -CONFIG_PACKAGE_rtl8852be-firmware=m -CONFIG_PACKAGE_rtl8852ce-firmware=m - -### MT76 firmware -CONFIG_PACKAGE_mt7925-firmware=m diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 41c71c6d9..092bdaae3 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -60,14 +60,3 @@ CONFIG_PACKAGE_kmod-video-videobuf2=y ### Virtualization CONFIG_PACKAGE_kmod-kvm-intel=y CONFIG_PACKAGE_kmod-kvm-x86=y - -### RTL8723D / RTL8821C / RTW89 firmware -CONFIG_PACKAGE_rtl8723de-firmware=m -CONFIG_PACKAGE_rtl8821ce-firmware=m -CONFIG_PACKAGE_rtl8851be-firmware=m -CONFIG_PACKAGE_rtl8852ae-firmware=m -CONFIG_PACKAGE_rtl8852be-firmware=m -CONFIG_PACKAGE_rtl8852ce-firmware=m - -### MT76 firmware -CONFIG_PACKAGE_mt7925-firmware=m diff --git a/openwrt/build.sh b/openwrt/build.sh index 71bf35717..21f9e8000 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -277,20 +277,16 @@ rm -rf ../master # Load devices Config if [ "$platform" = "x86_64" ]; then curl -s https://$mirror/openwrt/23-config-musl-x86 > .config - ALL_KMODS=y elif [ "$platform" = "bcm53xx" ]; then if [ "$MINIMAL_BUILD" = "y" ]; then curl -s https://$mirror/openwrt/23-config-musl-r8500-minimal > .config else curl -s https://$mirror/openwrt/23-config-musl-r8500 > .config fi - ALL_KMODS=y elif [ "$platform" = "rk3568" ]; then curl -s https://$mirror/openwrt/23-config-musl-r5s > .config - ALL_KMODS=y elif [ "$platform" = "armv8" ]; then curl -s https://$mirror/openwrt/23-config-musl-armsr-armv8 > .config - ALL_KMODS=y else curl -s https://$mirror/openwrt/23-config-musl-r4s > .config fi @@ -304,6 +300,9 @@ else [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi +# config-firmware +[ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ] && curl -s https://$mirror/openwrt/generic/config-firmware >> .config + # ota [ "$ENABLE_OTA" = "y" ] && [ "$version" = "rc2" ] && echo 'CONFIG_PACKAGE_luci-app-ota=y' >> .config @@ -453,7 +452,7 @@ fi [ "$TESTING_KERNEL" = "y" ] && OTA_PREFIX="test-" || OTA_PREFIX="" if [ "$platform" = "x86_64" ]; then - if [ "$ALL_KMODS" = y ]; then + if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* # driver firmware @@ -492,7 +491,7 @@ EOF fi exit 0 elif [ "$platform" = "armv8" ]; then - if [ "$ALL_KMODS" = y ]; then + if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/armsr/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* # driver firmware @@ -521,7 +520,7 @@ EOF fi exit 0 elif [ "$platform" = "bcm53xx" ]; then - if [ "$ALL_KMODS" = y ]; then + if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/bcm53xx/generic/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* # driver firmware @@ -555,7 +554,7 @@ EOF fi exit 0 else - if [ "$ALL_KMODS" = y ]; then + if [ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ]; then cp -a bin/targets/rockchip/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* # driver firmware diff --git a/openwrt/generic/config-firmware b/openwrt/generic/config-firmware new file mode 100644 index 000000000..a193a5dec --- /dev/null +++ b/openwrt/generic/config-firmware @@ -0,0 +1,11 @@ + +### RTL Firmware +CONFIG_PACKAGE_rtl8723de-firmware=m +CONFIG_PACKAGE_rtl8821ce-firmware=m +CONFIG_PACKAGE_rtl8851be-firmware=m +CONFIG_PACKAGE_rtl8852ae-firmware=m +CONFIG_PACKAGE_rtl8852be-firmware=m +CONFIG_PACKAGE_rtl8852ce-firmware=m + +### MT76 Firmware +CONFIG_PACKAGE_mt7988-2p5g-phy-firmware=m From 7c2af8528ca1518c82fb4076951e708e410b5b7d Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Oct 2024 00:12:28 +0800 Subject: [PATCH 042/425] linux-6.6: bump to 6.6.53 Signed-off-by: sbwml --- tags/kernel-6.6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index 094066fe7..d096bfabd 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .52 -LINUX_KERNEL_HASH-6.6.52 = 1591ab348399d4aa53121158525056a69c8cf0fe0e90935b0095e9a58e37b4b8 +LINUX_VERSION-6.6 = .53 +LINUX_KERNEL_HASH-6.6.53 = 285d181d1b252b0bf905f040d094215cf183ac98c31a17f9cce9f3537ef4d779 From 14cb827d35c6b62423edca850719eb26db93c3e7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Oct 2024 00:18:29 +0800 Subject: [PATCH 043/425] Begin journey to Linux 6.12 Signed-off-by: sbwml --- openwrt/23-config-musl-armsr-armv8 | 3 --- openwrt/build.sh | 2 +- ...el-name-in-proc-cpuinfo-for-64bit-ta.patch | 2 +- ...den-app-limited-rate-sample-detectio.patch | 2 +- ...hrink-delivered_mstamp-first_tx_msta.patch | 0 ...napshot-packets-in-flight-at-transmi.patch | 6 ++--- ...ount-packets-lost-over-TCP-rate-samp.patch | 2 +- ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 2 +- ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 2 +- ...djust-skb-tx.in_flight-upon-merge-in.patch | 0 ...djust-skb-tx.in_flight-upon-split-in.patch | 2 +- ...ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 4 +-- ...alize-TSO-sizing-in-TCP-CC-module-AP.patch | 2 +- ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 4 +-- ...ecord-app-limited-status-of-TLP-repa.patch | 2 +- ...nform-CC-module-of-losses-repaired-b.patch | 2 +- ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 2 +- ...r-route-feature-RTAX_FEATURE_ECN_LOW.patch | 2 +- ...pdate-TCP-bbr-congestion-control-mod.patch | 4 +-- ...nsure-ECN-enabled-BBR-flows-set-ECT-.patch | 0 ...OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 2 +- ...tso_segs-and-skb_marked_lost-to-bpf_.patch | 4 +-- ...-silence-btf-module-warning-messages.patch | 2 +- ...LRNG-Entropy-Source-and-DRNG-Manager.patch | 0 ...cate-one-DRNG-instance-per-NUMA-node.patch | 0 .../011-LRNG-0003-LRNG-proc-interface.patch | 0 ...004-LRNG-add-switchable-DRNG-support.patch | 0 ...LRNG-add-common-generic-hash-support.patch | 0 ...-externalize-DRBG-functions-for-LRNG.patch | 0 ...07-LRNG-add-SP800-90A-DRBG-extension.patch | 0 ...add-kernel-crypto-API-PRNG-extension.patch | 0 ...-LRNG-add-atomic-DRNG-implementation.patch | 0 ...mmon-timer-based-entropy-source-code.patch | 0 ...11-LRNG-add-interrupt-entropy-source.patch | 0 ...-scheduler-add-entropy-sampling-hook.patch | 2 +- ...G-add-scheduler-based-entropy-source.patch | 0 ...add-SP800-90B-compliant-health-tests.patch | 0 ...-add-random.c-entropy-source-support.patch | 0 ...11-LRNG-0016-LRNG-CPU-entropy-source.patch | 0 ...RNG-add-Jitter-RNG-fast-noise-source.patch | 0 ...to-enable-runtime-entropy-rate-confi.patch | 0 ...terface-for-gathering-of-raw-entropy.patch | 0 ...-add-power-on-and-runtime-self-tests.patch | 0 ...0021-LRNG-sysctls-and-proc-interface.patch | 0 ...add-drop-in-replacement-random-4-API.patch | 0 ...LRNG-add-kernel-crypto-API-interface.patch | 0 ...RNG-add-dev-lrng-device-file-support.patch | 0 ...-LRNG-add-hwrand-framework-interface.patch | 0 ...ter-export-udp_get_timeouts-function.patch | 0 ...k-events-support-multiple-registrant.patch | 8 +++--- ...-linux-kernel-to-support-shortcut-fe.patch | 15 +++++------ .../net/982-add-bcm-fullcone-support.patch | 0 ...83-add-bcm-fullcone-nft_masq-support.patch | 14 +++++----- .../net/README.md | 0 openwrt/patch/openwrt-6.x/modules/hwmon.mk | 4 +-- openwrt/patch/openwrt-6.x/modules/i2c.mk | 4 +-- openwrt/patch/openwrt-6.x/modules/iio.mk | 2 +- .../patch/openwrt-6.x/modules/netdevices.mk | 10 +++---- .../patch/openwrt-6.x/modules/netsupport.mk | 2 +- openwrt/patch/openwrt-6.x/modules/other.mk | 1 + .../x86/64/{config-6.11 => config-6.12} | 0 .../x86/{config-6.11 => config-6.12} | 1 - ...TIF_F_NETNS_LOCAL-to-dev-netns_local.patch | 16 ++++++++++++ ...-linux-6.11.patch => fix-linux-6.12.patch} | 0 ...1.patch => fix-build-for-linux-6.12.patch} | 0 .../101-fix-build-with-kernel-6.12.patch | 12 +++++++++ .../ovpn-dco/902-fix-linux-6.12.patch | 14 ++++++++++ ...v_remove-return-void-for-linux-6.12.patch} | 0 ...ch => 100-fix-build-with-linux-6.12.patch} | 0 ...ch => 301-fix-build-with-linux-6.12.patch} | 0 openwrt/scripts/01-prepare_base-mainline.sh | 26 +++++++++---------- openwrt/scripts/04-fix_kmod.sh | 20 ++++++++------ tags/kernel-6.11 | 2 -- tags/kernel-6.12 | 2 ++ tags/kernel-tag.sh | 10 ------- 75 files changed, 125 insertions(+), 93 deletions(-) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch (94%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch (96%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch (96%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch (98%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch (97%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch (97%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch (98%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch (95%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch (98%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch (95%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch (96%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch (97%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch (98%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch (98%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch (99%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch (95%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch (90%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/btf/990-btf-silence-btf-module-warning-messages.patch (90%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0003-LRNG-proc-interface.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch (94%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/net/601-netfilter-export-udp_get_timeouts-function.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/net/952-net-conntrack-events-support-multiple-registrant.patch (97%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch (95%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/net/982-add-bcm-fullcone-support.patch (100%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/net/983-add-bcm-fullcone-nft_masq-support.patch (88%) rename openwrt/patch/{kernel-6.11 => kernel-6.12}/net/README.md (100%) rename openwrt/patch/openwrt-6.x/x86/64/{config-6.11 => config-6.12} (100%) rename openwrt/patch/openwrt-6.x/x86/{config-6.11 => config-6.12} (99%) create mode 100644 openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch rename openwrt/patch/packages-patches/gpio-button-hotplug/{fix-linux-6.11.patch => fix-linux-6.12.patch} (100%) rename openwrt/patch/packages-patches/gpio-nct5104d/{fix-build-for-linux-6.11.patch => fix-build-for-linux-6.12.patch} (100%) create mode 100644 openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch create mode 100644 openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch rename openwrt/patch/packages-patches/ubootenv-nvram/{010-make-ubootenv_remove-return-void-for-linux-6.11.patch => 010-make-ubootenv_remove-return-void-for-linux-6.12.patch} (100%) rename openwrt/patch/packages-patches/v4l2loopback/{100-fix-build-with-linux-6.11.patch => 100-fix-build-with-linux-6.12.patch} (100%) rename openwrt/patch/packages-patches/xtables-addons/{301-fix-build-with-linux-6.11.patch => 301-fix-build-with-linux-6.12.patch} (100%) delete mode 100644 tags/kernel-6.11 create mode 100644 tags/kernel-6.12 diff --git a/openwrt/23-config-musl-armsr-armv8 b/openwrt/23-config-musl-armsr-armv8 index b50523d80..d98c3971b 100644 --- a/openwrt/23-config-musl-armsr-armv8 +++ b/openwrt/23-config-musl-armsr-armv8 @@ -17,6 +17,3 @@ CONFIG_TARGET_KERNEL_PARTSIZE=64 CONFIG_TARGET_ROOTFS_PARTSIZE=944 CONFIG_COREMARK_NUMBER_OF_THREADS=16 # CONFIG_KERNEL_KALLSYMS is not set - -### Utilities -CONFIG_PACKAGE_qemu-ga=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 21f9e8000..9504a6212 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -136,7 +136,7 @@ export \ TESTING_KERNEL=$TESTING_KERNEL \ # kernel version -[ "$TESTING_KERNEL" = "y" ] && export kernel_version=6.11 || export kernel_version=6.6 +[ "$TESTING_KERNEL" = "y" ] && export kernel_version=6.12 || export kernel_version=6.6 # print version echo -e "\r\n${GREEN_COLOR}Building $branch${RES}\r\n" diff --git a/openwrt/patch/kernel-6.11/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch b/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch similarity index 94% rename from openwrt/patch/kernel-6.11/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch rename to openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch index 67467025b..32c1f8752 100644 --- a/openwrt/patch/kernel-6.11/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch +++ b/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch @@ -18,7 +18,7 @@ Signed-off-by: Sumit Gupta --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c -@@ -205,9 +205,8 @@ static int c_show(struct seq_file *m, vo +@@ -206,9 +206,8 @@ static int c_show(struct seq_file *m, vo * "processor". Give glibc what it expects. */ seq_printf(m, "processor\t: %d\n", i); diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch similarity index 96% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index 4eaa0840b..9ad100372 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade * is in window. --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c -@@ -689,6 +689,7 @@ void tcp_write_timer_handler(struct sock +@@ -690,6 +690,7 @@ void tcp_write_timer_handler(struct sock return; } diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch similarity index 100% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch similarity index 96% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index a5d56b08c..f9122447e 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -38,7 +38,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1136,6 +1140,7 @@ struct rate_sample { +@@ -1137,6 +1141,7 @@ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ @@ -46,7 +46,7 @@ Signed-off-by: Alexandre Frade s32 delivered; /* number of packets delivered over interval */ s32 delivered_ce; /* number of packets delivered w/ CE marks*/ long interval_us; /* time for tp->delivered to incr "delivered" */ -@@ -1258,6 +1263,7 @@ static inline void tcp_ca_event(struct s +@@ -1259,6 +1264,7 @@ static inline void tcp_ca_event(struct s void tcp_set_ca_state(struct sock *sk, const u8 ca_state); /* From tcp_rate.c */ @@ -56,7 +56,7 @@ Signed-off-by: Alexandre Frade struct rate_sample *rs); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2767,6 +2767,7 @@ static bool tcp_write_xmit(struct sock * +@@ -2768,6 +2768,7 @@ static bool tcp_write_xmit(struct sock * skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); tcp_init_tso_segs(skb, mss_now); diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch similarity index 98% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch index 69e9f35d9..0554f920f 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1138,11 +1139,13 @@ struct ack_sample { +@@ -1139,11 +1140,13 @@ struct ack_sample { */ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch similarity index 97% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index 3aff3d52e..9ad86848c 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -18,7 +18,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1157,6 +1157,7 @@ struct rate_sample { +@@ -1158,6 +1158,7 @@ struct rate_sample { bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ bool is_ack_delayed; /* is this (likely) a delayed ACK? */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch similarity index 97% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index c6916bb2d..99139bcc6 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -30,7 +30,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1184,6 +1184,9 @@ struct tcp_congestion_ops { +@@ -1185,6 +1185,9 @@ struct tcp_congestion_ops { /* override sysctl_tcp_min_tso_segs */ u32 (*min_tso_segs)(struct sock *sk); diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch similarity index 100% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch similarity index 98% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch index 5bd2fe09f..918f5f630 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1283,6 +1283,21 @@ static inline bool tcp_skb_sent_after(u6 +@@ -1284,6 +1284,21 @@ static inline bool tcp_skb_sent_after(u6 return t1 > t2 || (t1 == t2 && after(seq1, seq2)); } diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch similarity index 95% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch index 36eb1a373..6bf00dbaf 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch @@ -23,7 +23,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1119,7 +1119,11 @@ enum tcp_ca_ack_event_flags { +@@ -1120,7 +1120,11 @@ enum tcp_ca_ack_event_flags { #define TCP_CONG_NON_RESTRICTED 0x1 /* Requires ECN/ECT set on all packets */ #define TCP_CONG_NEEDS_ECN 0x2 @@ -36,7 +36,7 @@ Signed-off-by: Alexandre Frade union tcp_cc_info; -@@ -1251,6 +1255,14 @@ static inline char *tcp_ca_get_name_by_k +@@ -1252,6 +1256,14 @@ static inline char *tcp_ca_get_name_by_k } #endif diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch similarity index 98% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch index 07ad69959..3a6918530 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1185,8 +1185,8 @@ struct tcp_congestion_ops { +@@ -1186,8 +1186,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch similarity index 95% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index f2a9f15fa..8d2218476 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -3123,6 +3123,7 @@ int tcp_disconnect(struct sock *sk, int +@@ -3384,6 +3384,7 @@ int tcp_disconnect(struct sock *sk, int tp->rx_opt.dsack = 0; tp->rx_opt.num_sacks = 0; tp->rcv_ooopack = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5736,13 +5736,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5743,13 +5743,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch similarity index 96% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch index 1a2b75f6b..35cd6d0f1 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -3005,6 +3005,7 @@ void tcp_send_loss_probe(struct sock *sk +@@ -3006,6 +3006,7 @@ void tcp_send_loss_probe(struct sock *sk if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch similarity index 97% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index 07a81e053..21a505ac8 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1097,6 +1097,7 @@ enum tcp_ca_event { +@@ -1098,6 +1098,7 @@ enum tcp_ca_event { CA_EVENT_LOSS, /* loss timeout */ CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch similarity index 98% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index 51dd16b51..8a6829803 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -21,7 +21,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1161,6 +1161,7 @@ struct rate_sample { +@@ -1162,6 +1162,7 @@ struct rate_sample { u32 last_end_seq; /* end_seq of most recently ACKed packet */ bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch similarity index 98% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch index 06249605f..3adcf7d60 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch @@ -77,7 +77,7 @@ Signed-off-by: Alexandre Frade __u8 proto; --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c -@@ -459,6 +459,8 @@ void tcp_ca_openreq_child(struct sock *s +@@ -462,6 +462,8 @@ void tcp_ca_openreq_child(struct sock *s u32 ca_key = dst_metric(dst, RTAX_CC_ALGO); bool ca_got_dst = false; diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch similarity index 99% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch index 4c71cb850..4e3707dfc 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -153,7 +153,7 @@ Signed-off-by: Alexandre Frade #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -2473,7 +2473,7 @@ struct tcp_plb_state { +@@ -2474,7 +2474,7 @@ struct tcp_plb_state { u8 consec_cong_rounds:5, /* consecutive congested rounds */ unused:3; u32 pause_until; /* jiffies32 when PLB can resume rerouting */ @@ -196,7 +196,7 @@ Signed-off-by: Alexandre Frade union tcp_cc_info { --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig -@@ -668,15 +668,18 @@ config TCP_CONG_BBR +@@ -669,15 +669,18 @@ config TCP_CONG_BBR default n help diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch similarity index 100% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch similarity index 95% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch index eb1762553..e4e5369fe 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade * Sender's congestion state indicating normal or abnormal situations --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -3850,6 +3850,8 @@ void tcp_get_info(struct sock *sk, struc +@@ -4111,6 +4111,8 @@ void tcp_get_info(struct sock *sk, struc info->tcpi_options |= TCPI_OPT_ECN; if (tp->ecn_flags & TCP_ECN_SEEN) info->tcpi_options |= TCPI_OPT_ECN_SEEN; diff --git a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch similarity index 90% rename from openwrt/patch/kernel-6.11/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch rename to openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch index 9715997c8..9c22df321 100644 --- a/openwrt/patch/kernel-6.11/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch @@ -10,7 +10,7 @@ Subject: [PATCH 19/19] x86/cfi,bpf: Add tso_segs and skb_marked_lost to --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c -@@ -305,11 +305,15 @@ static void bpf_tcp_ca_pkts_acked(struct +@@ -280,11 +280,15 @@ static void bpf_tcp_ca_pkts_acked(struct { } @@ -27,7 +27,7 @@ Subject: [PATCH 19/19] x86/cfi,bpf: Add tso_segs and skb_marked_lost to static void bpf_tcp_ca_cong_control(struct sock *sk, u32 ack, int flag, const struct rate_sample *rs) { -@@ -340,7 +344,8 @@ static struct tcp_congestion_ops __bpf_o +@@ -315,7 +319,8 @@ static struct tcp_congestion_ops __bpf_o .cwnd_event = bpf_tcp_ca_cwnd_event, .in_ack_event = bpf_tcp_ca_in_ack_event, .pkts_acked = bpf_tcp_ca_pkts_acked, diff --git a/openwrt/patch/kernel-6.11/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch similarity index 90% rename from openwrt/patch/kernel-6.11/btf/990-btf-silence-btf-module-warning-messages.patch rename to openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch index 013337eb9..4e09795cb 100644 --- a/openwrt/patch/kernel-6.11/btf/990-btf-silence-btf-module-warning-messages.patch +++ b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch @@ -10,7 +10,7 @@ Signed-off-by: sbwml --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c -@@ -7847,8 +7847,6 @@ static int btf_module_notify(struct noti +@@ -7878,8 +7878,6 @@ static int btf_module_notify(struct noti pr_warn("failed to validate module [%s] BTF: %ld\n", mod->name, PTR_ERR(btf)); err = PTR_ERR(btf); diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0003-LRNG-proc-interface.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0003-LRNG-proc-interface.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch similarity index 94% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch index cfe8ea407..53a43adc5 100644 --- a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -24,7 +24,7 @@ Signed-off-by: Stephan Mueller #include #include #include -@@ -3515,6 +3516,8 @@ ttwu_stat(struct task_struct *p, int cpu +@@ -3604,6 +3605,8 @@ ttwu_stat(struct task_struct *p, int cpu { struct rq *rq; diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch diff --git a/openwrt/patch/kernel-6.11/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch similarity index 100% rename from openwrt/patch/kernel-6.11/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch rename to openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch diff --git a/openwrt/patch/kernel-6.11/net/601-netfilter-export-udp_get_timeouts-function.patch b/openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch similarity index 100% rename from openwrt/patch/kernel-6.11/net/601-netfilter-export-udp_get_timeouts-function.patch rename to openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch diff --git a/openwrt/patch/kernel-6.11/net/952-net-conntrack-events-support-multiple-registrant.patch b/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch similarity index 97% rename from openwrt/patch/kernel-6.11/net/952-net-conntrack-events-support-multiple-registrant.patch rename to openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch index 15e16ae73..798d456af 100644 --- a/openwrt/patch/kernel-6.11/net/952-net-conntrack-events-support-multiple-registrant.patch +++ b/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch @@ -123,7 +123,7 @@ Signed-off-by: Zhi Chen depends on NETFILTER_ADVANCED --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c -@@ -2789,6 +2789,10 @@ int nf_conntrack_init_net(struct net *ne +@@ -2750,6 +2750,10 @@ int nf_conntrack_init_net(struct net *ne nf_conntrack_ecache_pernet_init(net); nf_conntrack_proto_pernet_init(net); @@ -299,7 +299,7 @@ Signed-off-by: Zhi Chen void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state) --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c -@@ -724,12 +724,19 @@ static size_t ctnetlink_nlmsg_size(const +@@ -721,12 +721,19 @@ static size_t ctnetlink_nlmsg_size(const } static int @@ -319,7 +319,7 @@ Signed-off-by: Zhi Chen struct nf_conn *ct = item->ct; struct sk_buff *skb; unsigned int type; -@@ -3760,11 +3767,17 @@ static int ctnetlink_stat_exp_cpu(struct +@@ -3754,11 +3761,17 @@ static int ctnetlink_stat_exp_cpu(struct } #ifdef CONFIG_NF_CONNTRACK_EVENTS @@ -337,7 +337,7 @@ Signed-off-by: Zhi Chen static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { [IPCTNL_MSG_CT_NEW] = { -@@ -3863,8 +3876,12 @@ static int __net_init ctnetlink_net_init +@@ -3857,8 +3870,12 @@ static int __net_init ctnetlink_net_init static void ctnetlink_net_pre_exit(struct net *net) { #ifdef CONFIG_NF_CONNTRACK_EVENTS diff --git a/openwrt/patch/kernel-6.11/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch similarity index 95% rename from openwrt/patch/kernel-6.11/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch rename to openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index fea7ef88e..70dcf3b0c 100644 --- a/openwrt/patch/kernel-6.11/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -29,14 +29,13 @@ Signed-off-by: Xiaoping Fan struct list_head *br_ip_list); --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -1009,6 +1009,10 @@ struct sk_buff { +@@ -1011,6 +1011,9 @@ struct sk_buff { __u8 csum_not_inet:1; #endif - + __u8 unreadable:1; +#ifdef CONFIG_SHORTCUT_FE + __u8 fast_forwarded:1; +#endif -+ #if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS) __u16 tc_index; /* traffic control index */ #endif @@ -53,7 +52,7 @@ Signed-off-by: Xiaoping Fan const struct nf_ct_event_notifier *nb); --- a/net/Kconfig +++ b/net/Kconfig -@@ -506,6 +506,9 @@ config FAILOVER +@@ -512,6 +512,9 @@ config FAILOVER migration of VMs with direct attached VFs by failing over to the paravirtual datapath when the VF is unplugged. @@ -94,7 +93,7 @@ Signed-off-by: Xiaoping Fan struct net_bridge_port *p; --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -3572,8 +3572,17 @@ static int xmit_one(struct sk_buff *skb, +@@ -3580,8 +3580,17 @@ static int xmit_one(struct sk_buff *skb, unsigned int len; int rc; @@ -112,7 +111,7 @@ Signed-off-by: Xiaoping Fan len = skb->len; trace_net_dev_start_xmit(skb, dev); -@@ -5408,6 +5417,11 @@ void netdev_rx_handler_unregister(struct +@@ -5409,6 +5418,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -124,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5456,6 +5470,10 @@ static int __netif_receive_skb_core(stru +@@ -5457,6 +5471,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -135,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5494,6 +5512,16 @@ another_round: +@@ -5495,6 +5513,16 @@ another_round: goto out; } diff --git a/openwrt/patch/kernel-6.11/net/982-add-bcm-fullcone-support.patch b/openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch similarity index 100% rename from openwrt/patch/kernel-6.11/net/982-add-bcm-fullcone-support.patch rename to openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch diff --git a/openwrt/patch/kernel-6.11/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch similarity index 88% rename from openwrt/patch/kernel-6.11/net/983-add-bcm-fullcone-nft_masq-support.patch rename to openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch index 8ab8fba37..b8c16c605 100644 --- a/openwrt/patch/kernel-6.11/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -37,7 +37,7 @@ }; static int nft_masq_validate(const struct nft_ctx *ctx, -@@ -45,6 +49,7 @@ static int nft_masq_init(const struct nf +@@ -44,6 +48,7 @@ static int nft_masq_init(const struct nf const struct nlattr * const tb[]) { u32 plen = sizeof_field(struct nf_nat_range, min_proto.all); @@ -45,18 +45,18 @@ struct nft_masq *priv = nft_expr_priv(expr); int err; -@@ -68,6 +73,25 @@ static int nft_masq_init(const struct nf +@@ -67,6 +72,25 @@ static int nft_masq_init(const struct nf } } + if (tb[NFTA_MASQ_REG_ADDR_MIN]) { -+ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MIN], ++ err = nft_parse_register_load(ctx, tb[NFTA_MASQ_REG_ADDR_MIN], + &priv->sreg_addr_min, alen); + if (err < 0) + return err; + + if (tb[NFTA_MASQ_REG_ADDR_MAX]) { -+ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MAX], ++ err = nft_parse_register_load(ctx, tb[NFTA_MASQ_REG_ADDR_MAX], + &priv->sreg_addr_max, + alen); + if (err < 0) @@ -71,7 +71,7 @@ return nf_ct_netns_get(ctx->net, ctx->family); } -@@ -88,6 +112,14 @@ static int nft_masq_dump(struct sk_buff +@@ -87,6 +111,14 @@ static int nft_masq_dump(struct sk_buff goto nla_put_failure; } @@ -86,7 +86,7 @@ return 0; nla_put_failure: -@@ -112,6 +144,12 @@ static void nft_masq_eval(const struct n +@@ -111,6 +143,12 @@ static void nft_masq_eval(const struct n switch (nft_pf(pkt)) { case NFPROTO_IPV4: @@ -99,7 +99,7 @@ regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt), &range, -@@ -119,6 +157,12 @@ static void nft_masq_eval(const struct n +@@ -118,6 +156,12 @@ static void nft_masq_eval(const struct n break; #ifdef CONFIG_NF_TABLES_IPV6 case NFPROTO_IPV6: diff --git a/openwrt/patch/kernel-6.11/net/README.md b/openwrt/patch/kernel-6.12/net/README.md similarity index 100% rename from openwrt/patch/kernel-6.11/net/README.md rename to openwrt/patch/kernel-6.12/net/README.md diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index a7eea8623..d862d5f9e 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -10,7 +10,7 @@ HWMON_MENU:=Hardware Monitoring Support define KernelPackage/hwmon-core SUBMENU:=$(HWMON_MENU) TITLE:=Hardware monitoring support - DEPENDS:=+LINUX_6_11:kmod-i2c-core + DEPENDS:=+LINUX_6_12:kmod-i2c-core KCONFIG:= \ CONFIG_HWMON \ CONFIG_HWMON_DEBUG_CHIP=n @@ -422,7 +422,7 @@ define KernelPackage/hwmon-max6697 KCONFIG:=CONFIG_SENSORS_MAX6697 FILES:=$(LINUX_DIR)/drivers/hwmon/max6697.ko AUTOLOAD:=$(call AutoProbe,max6697) - $(call AddDepends/hwmon,+kmod-i2c-core) + $(call AddDepends/hwmon,+kmod-i2c-core +kmod-regmap-i2c) endef define KernelPackage/hwmon-max6697/description diff --git a/openwrt/patch/openwrt-6.x/modules/i2c.mk b/openwrt/patch/openwrt-6.x/modules/i2c.mk index d1bdfffcb..6145dc307 100644 --- a/openwrt/patch/openwrt-6.x/modules/i2c.mk +++ b/openwrt/patch/openwrt-6.x/modules/i2c.mk @@ -150,7 +150,7 @@ I2C_I801_MODULES:= \ define KernelPackage/i2c-i801 $(call i2c_defaults,$(I2C_I801_MODULES),59) TITLE:=Intel I801 and compatible I2C interfaces - DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus +LINUX_6_11:kmod-i2c-mux + DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus +LINUX_6_12:kmod-i2c-mux endef define KernelPackage/i2c-i801/description @@ -289,7 +289,7 @@ I2C_PIIX4_MODULES:= \ define KernelPackage/i2c-piix4 $(call i2c_defaults,$(I2C_PIIX4_MODULES),59) TITLE:=Intel PIIX4 and compatible I2C interfaces - DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +LINUX_6_11:kmod-i2c-smbus + DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +LINUX_6_12:kmod-i2c-smbus endef define KernelPackage/i2c-piix4/description diff --git a/openwrt/patch/openwrt-6.x/modules/iio.mk b/openwrt/patch/openwrt-6.x/modules/iio.mk index e46544b79..053f61c8b 100644 --- a/openwrt/patch/openwrt-6.x/modules/iio.mk +++ b/openwrt/patch/openwrt-6.x/modules/iio.mk @@ -220,7 +220,7 @@ $(eval $(call KernelPackage,iio-bme680-spi)) define KernelPackage/iio-bmp280 TITLE:=BMP180/BMP280/BME280 pressure/temperatur sensor - DEPENDS:=+kmod-regmap-core + DEPENDS:=+kmod-regmap-core +LINUX_6_12:kmod-industrialio-triggered-buffer KCONFIG:=CONFIG_BMP280 FILES:=$(LINUX_DIR)/drivers/iio/pressure/bmp280.ko $(call AddDepends/iio) diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index ab95b3774..e7ca46d44 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -111,7 +111,7 @@ $(eval $(call KernelPackage,libphy)) define KernelPackage/libie SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel Ethernet library - DEPENDS:=@LINUX_6_11 + DEPENDS:=@LINUX_6_12 KCONFIG:=CONFIG_LIBIE FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie.ko AUTOLOAD:=$(call AutoLoad,15,libie,1) @@ -127,7 +127,7 @@ $(eval $(call KernelPackage,libie)) define KernelPackage/libeth SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel Ethernet common library - DEPENDS:=@LINUX_6_11 + DEPENDS:=@LINUX_6_12 KCONFIG:=CONFIG_LIBETH FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libeth/libeth.ko AUTOLOAD:=$(call AutoLoad,15,libeth,1) @@ -426,7 +426,7 @@ $(eval $(call KernelPackage,phy-airoha-en8811h)) define KernelPackage/phy-aquantia SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Aquantia Ethernet PHYs - DEPENDS:=+kmod-libphy +kmod-hwmon-core +kmod-lib-crc-ccitt +LINUX_6_11:kmod-lib-crc-itu-t + DEPENDS:=+kmod-libphy +kmod-hwmon-core +kmod-lib-crc-ccitt +LINUX_6_12:kmod-lib-crc-itu-t KCONFIG:=CONFIG_AQUANTIA_PHY FILES:=$(LINUX_DIR)/drivers/net/phy/aquantia/aquantia.ko AUTOLOAD:=$(call AutoLoad,18,aquantia,1) @@ -970,7 +970,7 @@ $(eval $(call KernelPackage,ixgbevf)) define KernelPackage/i40e SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) Ethernet Controller XL710 Family support - DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +LINUX_6_11:kmod-libie + DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +LINUX_6_12:kmod-libie KCONFIG:=CONFIG_I40E \ CONFIG_I40E_VXLAN=n \ CONFIG_I40E_HWMON=y \ @@ -989,7 +989,7 @@ $(eval $(call KernelPackage,i40e)) define KernelPackage/iavf SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) Ethernet Adaptive Virtual Function support - DEPENDS:=@PCI_SUPPORT +LINUX_6_11:kmod-libie +LINUX_6_11:kmod-libeth + DEPENDS:=@PCI_SUPPORT +LINUX_6_12:kmod-libie +LINUX_6_12:kmod-libeth KCONFIG:= \ CONFIG_I40EVF \ CONFIG_IAVF diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index d3baa3726..cd1421f70 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -1358,7 +1358,7 @@ $(eval $(call KernelPackage,mpls)) define KernelPackage/9pnet SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Plan 9 Resource Sharing Support (9P2000) - DEPENDS:=+LINUX_6_11:kmod-fs-netfs + DEPENDS:=+LINUX_6_12:kmod-fs-netfs KCONFIG:= \ CONFIG_NET_9P \ CONFIG_NET_9P_DEBUG=n \ diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index 98bb8a01f..24db3420b 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -1060,6 +1060,7 @@ $(eval $(call KernelPackage,ikconfig)) define KernelPackage/zram SUBMENU:=$(OTHER_MENU) TITLE:=ZRAM + DEPENDS:=+LINUX_6_12:kmod-lib-lzo KCONFIG:= \ CONFIG_ZSMALLOC \ CONFIG_ZRAM \ diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.11 b/openwrt/patch/openwrt-6.x/x86/64/config-6.12 similarity index 100% rename from openwrt/patch/openwrt-6.x/x86/64/config-6.11 rename to openwrt/patch/openwrt-6.x/x86/64/config-6.12 diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.11 b/openwrt/patch/openwrt-6.x/x86/config-6.12 similarity index 99% rename from openwrt/patch/openwrt-6.x/x86/config-6.11 rename to openwrt/patch/openwrt-6.x/x86/config-6.12 index 342a3d614..3df65431e 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.11 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.12 @@ -277,7 +277,6 @@ CONFIG_MODULES_USE_ELF_REL=y # CONFIG_MPENTIUMIII is not set # CONFIG_MPENTIUMII is not set # CONFIG_MPENTIUMM is not set -# CONFIG_MTD is not set # CONFIG_MTRR_SANITIZER is not set CONFIG_MTRR=y # CONFIG_MVIAC3_2 is not set diff --git a/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch b/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch new file mode 100644 index 000000000..5e622e0d0 --- /dev/null +++ b/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch @@ -0,0 +1,16 @@ +--- a/net/batman-adv/soft-interface.c ++++ b/net/batman-adv/soft-interface.c +@@ -1020,8 +1020,13 @@ static void batadv_softif_init_early(str + dev->netdev_ops = &batadv_netdev_ops; + dev->needs_free_netdev = true; + dev->priv_destructor = batadv_softif_free; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | dev->netns_local; ++ dev->features |= dev->lltx; ++#else + dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL; + dev->features |= NETIF_F_LLTX; ++#endif + dev->priv_flags |= IFF_NO_QUEUE; + + /* can't call min_mtu, because the needed variables diff --git a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch similarity index 100% rename from openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch rename to openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch diff --git a/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch b/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch similarity index 100% rename from openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch rename to openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch diff --git a/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch b/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch new file mode 100644 index 000000000..78a60f4a5 --- /dev/null +++ b/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch @@ -0,0 +1,12 @@ +--- a/nat46/modules/nat46-netdev.c ++++ b/nat46/modules/nat46-netdev.c +@@ -110,7 +110,9 @@ static void nat46_netdev_setup(struct ne + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->mtu = 16384; /* iptables does reassembly. Rather than using ETH_DATA_LEN, let's try to get as much mileage as we can with the Linux stack */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0) + dev->features = NETIF_F_NETNS_LOCAL; ++#endif + dev->flags = IFF_NOARP | IFF_POINTOPOINT; + } + diff --git a/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch b/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch new file mode 100644 index 000000000..c47ea0ac9 --- /dev/null +++ b/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch @@ -0,0 +1,14 @@ +--- a/drivers/net/ovpn-dco/main.c ++++ b/drivers/net/ovpn-dco/main.c +@@ -125,7 +125,11 @@ static void ovpn_setup(struct net_device + const int overhead = sizeof(u32) + NONCE_WIRE_SIZE + 16 + sizeof(struct udphdr) + + max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++ netdev_features_t feat = NETIF_F_SG | dev->lltx | ++#else + netdev_features_t feat = NETIF_F_SG | NETIF_F_LLTX | ++#endif + NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_GSO | + NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA; + diff --git a/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch b/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch similarity index 100% rename from openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch rename to openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch diff --git a/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch b/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch similarity index 100% rename from openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch rename to openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch diff --git a/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch b/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch similarity index 100% rename from openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch rename to openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 105f7f35f..e951e7bab 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -12,15 +12,15 @@ curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.6 > target/linux/ mkdir -p target/linux/x86/patches-6.6 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.6/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.6/100-fix_cs5535_clockevt.patch curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.6/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.6/103-pcengines_apu6_platform.patch -# x86_64 - target 6.11 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.11 > target/linux/x86/64/config-6.11 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.11 > target/linux/x86/config-6.11 -mkdir -p target/linux/x86/patches-6.11 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.11/100-fix_cs5535_clockevt.patch -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.11/103-pcengines_apu6_platform.patch +# x86_64 - target 6.12 +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.12 > target/linux/x86/64/config-6.12 +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/config-6.12 +mkdir -p target/linux/x86/patches-6.12 +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.12/100-fix_cs5535_clockevt.patch +curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.12/103-pcengines_apu6_platform.patch # x86_64 - target sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.6/" target/linux/x86/Makefile -sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.11' target/linux/x86/Makefile +sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.12' target/linux/x86/Makefile curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network @@ -36,7 +36,7 @@ git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/arm # kernel - 6.x curl -s https://$mirror/tags/kernel-6.6 > include/kernel-6.6 -curl -s https://$mirror/tags/kernel-6.11 > include/kernel-6.11 +curl -s https://$mirror/tags/kernel-6.12 > include/kernel-6.12 # kenrel Vermagic sed -ie 's/^\(.\).*vermagic$/\1cp $(TOPDIR)\/.vermagic $(LINUX_DIR)\/.vermagic/' include/kernel-defaults.mk @@ -46,7 +46,7 @@ grep HASH include/kernel-$kernel_version | awk -F'HASH-' '{print $2}' | awk '{pr rm -rf target/linux/generic local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-$kernel_version) release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-$kernel_version | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') -if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ]; then +if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then git clone https://$github/sbwml/target_linux_generic -b main target/linux/generic --depth=1 else if [ "$(whoami)" = "runner" ]; then @@ -58,7 +58,7 @@ else fi # bcm53xx - fix build kernel with clang -[ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch target/linux/generic/hack-6.11/220-arm-gc_sections.patch +[ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch target/linux/generic/hack-6.12/220-arm-gc_sections.patch # kernel modules rm -rf package/kernel/linux @@ -93,7 +93,7 @@ pushd package/kernel/linux/modules curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/wpan.mk popd -# BBRv3 - linux-6.6/6.11 +# BBRv3 - linux-6.6/6.12 pushd target/linux/generic/backport-"$kernel_version" curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch @@ -116,7 +116,7 @@ pushd target/linux/generic/backport-"$kernel_version" [ "$TESTING_KERNEL" = "y" ] && curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch popd -# LRNG v54/56 - linux-6.6/6.11 +# LRNG v54/56 - linux-6.6/6.12 pushd target/linux/generic/hack-$kernel_version curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch @@ -150,7 +150,7 @@ rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware if [ "$TESTING_KERNEL" = "y" ]; then - # rtl8812au-ct - fix linux-6.11 + # rtl8812au-ct - fix linux-6.12 rm -rf package/kernel/rtl8812au-ct git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct -b v6.11 # add rtl8812au-ac diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index 587d20b3c..205e77404 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -# Fix build for linux-6.6 +# Fix build for linux-6.6/6.12 # cryptodev-linux mkdir -p package/kernel/cryptodev-linux/patches @@ -9,11 +9,11 @@ curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/002-fix-b # gpio-button-hotplug curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.11.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 # gpio-nct5104d curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.11.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch | patch -p1 # dmx_usb_module mkdir -p feeds/packages/libs/dmx_usb_module/patches @@ -31,6 +31,7 @@ mkdir -p feeds/packages/kernel/ovpn-dco/patches curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch > feeds/packages/kernel/ovpn-dco/patches/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch > feeds/packages/kernel/ovpn-dco/patches/900-fix-linux-6.6.patch curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch > feeds/packages/kernel/ovpn-dco/patches/901-fix-linux-6.11.patch +curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch > feeds/packages/kernel/ovpn-dco/patches/902-fix-linux-6.12.patch # siit rm -rf feeds/packages/net/siit @@ -49,19 +50,20 @@ popd # nat46 mkdir -p package/kernel/nat46/patches curl -s https://$mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch > package/kernel/nat46/patches/100-fix-build-with-kernel-6.9.patch +curl -s https://$mirror/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch > package/kernel/nat46/patches/101-fix-build-with-kernel-6.12.patch -# v4l2loopback - 6.11 +# v4l2loopback - 6.12 mkdir -p feeds/packages/kernel/v4l2loopback/patches -curl -s https://$mirror/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.11.patch > feeds/packages/kernel/v4l2loopback/patches/100-fix-build-with-linux-6.11.patch +curl -s https://$mirror/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch > feeds/packages/kernel/v4l2loopback/patches/100-fix-build-with-linux-6.12.patch # openvswitch if [ "$TESTING_KERNEL" = "y" ]; then sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile fi -# ubootenv-nvram - 6.11 (openwrt-23.05.5) +# ubootenv-nvram - 6.12 (openwrt-23.05.5) mkdir -p package/kernel/ubootenv-nvram/patches -curl -s https://$mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.11.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.11.patch +curl -s https://$mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.12.patch # packages pushd feeds/packages @@ -77,7 +79,7 @@ popd # xtables-addons rm -rf feeds/packages/net/xtables-addons cp -a ../master/packages/net/xtables-addons feeds/packages/net/xtables-addons -curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.11.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.11.patch +curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch # telephony pushd feeds/telephony @@ -89,6 +91,8 @@ popd # routing - batman-adv rm -rf feeds/routing/batman-adv cp -a ../master/routing/batman-adv feeds/routing/batman-adv +# fix build with linux-6.12 +curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch > feeds/routing/batman-adv/patches/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch # bcm53xx if [ "$platform" = "bcm53xx" ]; then diff --git a/tags/kernel-6.11 b/tags/kernel-6.11 deleted file mode 100644 index 7c1260757..000000000 --- a/tags/kernel-6.11 +++ /dev/null @@ -1,2 +0,0 @@ -LINUX_VERSION-6.11 = -LINUX_KERNEL_HASH-6.11 = 55d2c6c025ebc27810c748d66325dd5bc601e8d32f8581d9e77673529bdacb2e diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 new file mode 100644 index 000000000..85b7c5708 --- /dev/null +++ b/tags/kernel-6.12 @@ -0,0 +1,2 @@ +LINUX_VERSION-6.12 = -rc1 +LINUX_KERNEL_HASH-6.12-rc1 = 248f22796171a3d5809d76b019763cd4bb2a69f9a95d243ee614cea7eb3e578e diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index 9fc65c964..8257a30dd 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -10,13 +10,3 @@ TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` [ -z $TAG ] && TAG="" || TAG=.$TAG echo "LINUX_VERSION-6.6 = $TAG LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.6 - -# MAIN -KERNEL_VERSION=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | awk '{print $2}' | grep -E ^linux-6.11 | grep tar.xz | sed 's/linux-//g;s/.tar.xz//g' | tail -n 1` -KERNEL_HASH=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | grep linux-$KERNEL_VERSION | grep tar.xz | awk '{print $1}'` -TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` - -[ -z $TAG ] && TAG="" || TAG=.$TAG -echo "LINUX_VERSION-6.11 = $TAG -LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.11 - From f249d48c13c3c664d2587c0f6475c08f6b36c3b1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Oct 2024 01:20:32 +0800 Subject: [PATCH 044/425] nat46: correct conversion of NETIF_F_NETNS_LOCAL for linux 6.12 Signed-off-by: sbwml --- .../nat46/101-fix-build-with-kernel-6.12.patch | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch b/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch index 78a60f4a5..1c213ea90 100644 --- a/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch +++ b/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch @@ -1,11 +1,13 @@ --- a/nat46/modules/nat46-netdev.c +++ b/nat46/modules/nat46-netdev.c -@@ -110,7 +110,9 @@ static void nat46_netdev_setup(struct ne +@@ -110,7 +110,11 @@ static void nat46_netdev_setup(struct ne dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = 16384; /* iptables does reassembly. Rather than using ETH_DATA_LEN, let's try to get as much mileage as we can with the Linux stack */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0) dev->features = NETIF_F_NETNS_LOCAL; ++#else ++ dev->features = dev->netns_local; +#endif dev->flags = IFF_NOARP | IFF_POINTOPOINT; } From 86eb75f37a578b6b3dae8cdb6f239a63142d11b6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Oct 2024 03:08:42 +0800 Subject: [PATCH 045/425] x86: sync sbwml/r4s_init Signed-off-by: sbwml --- .../{patches-6.11 => patches-6.12}/100-fix_cs5535_clockevt.patch | 0 .../103-pcengines_apu6_platform.patch | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename openwrt/patch/openwrt-6.x/x86/{patches-6.11 => patches-6.12}/100-fix_cs5535_clockevt.patch (100%) rename openwrt/patch/openwrt-6.x/x86/{patches-6.11 => patches-6.12}/103-pcengines_apu6_platform.patch (100%) diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch similarity index 100% rename from openwrt/patch/openwrt-6.x/x86/patches-6.11/100-fix_cs5535_clockevt.patch rename to openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch similarity index 100% rename from openwrt/patch/openwrt-6.x/x86/patches-6.11/103-pcengines_apu6_platform.patch rename to openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch From 7f7c3be122410594ed715dd7182e433c7ac31322 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Oct 2024 23:06:45 +0800 Subject: [PATCH 046/425] linux-6.12: drop bcm-fullcone * incompatible with the kernel 6.12 netfilter. Signed-off-by: sbwml --- ...-luci-app-firewall-drop-bcm-fullcone.patch | 29 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 7 +++-- openwrt/scripts/01-prepare_base-mainline.sh | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch diff --git a/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch b/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch new file mode 100644 index 000000000..bf41475fd --- /dev/null +++ b/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch @@ -0,0 +1,29 @@ +From a98c7f7c38228f17813744c0c4b82b3e92ee4654 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Tue, 1 Oct 2024 22:54:31 +0800 +Subject: [PATCH] luci-app-firewall: drop bcm-fullcone + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/zones.js | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index 522d001..9e86b35 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -60,11 +60,6 @@ return view.extend({ + + if (L.hasSystemFeature('fullcone')) { + o = s.option(form.Flag, 'fullcone', _('Enable FullCone NAT')); +- +- o = s.option(form.Flag, 'brcmfullcone', _('BCM FullCone NAT scheme'), +- _('Use the Broadcom FullCone NAT scheme if enabled, and use the NFT FullCone scheme if the option is disabled.')); +- o.modalonly = true; +- o.depends('fullcone', '1'); + }; + + if (L.hasSystemFeature('ipv6')) { +-- +2.42.0 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index d30bb1867..c3a86de21 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -177,7 +177,7 @@ if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then # fullcone curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch # bcm fullcone - curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch + [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch # kernel version curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch > package/network/config/firewall4/patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch # fix flow offload @@ -189,14 +189,14 @@ if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then cp -a ../master/openwrt/package/libs/libnftnl package/libs/libnftnl mkdir -p package/libs/libnftnl/patches curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/001-libnftnl-add-fullcone-expression-support.patch - curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch + [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch sed -i '/PKG_INSTALL:=1/iPKG_FIXUP:=autoreconf' package/libs/libnftnl/Makefile # nftables rm -rf package/network/utils/nftables cp -a ../master/openwrt/package/network/utils/nftables package/network/utils/nftables mkdir -p package/network/utils/nftables/patches curl -s https://$mirror/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/002-nftables-add-fullcone-expression-support.patch - curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch + [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch # hide nftables warning message pushd feeds/luci curl -s https://$mirror/openwrt/patch/luci/luci-nftables.patch | patch -p1 @@ -219,6 +219,7 @@ pushd feeds/luci curl -s https://$mirror/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 + [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 popd # openssl - quictls diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index e951e7bab..b480635c7 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -167,7 +167,7 @@ fi rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile -curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +[ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch # iwinfo: add mt7922 device id mkdir -p package/network/utils/iwinfo/patches From 51124eb5139740125e6775d6506e2cf81a00af8f Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Oct 2024 23:12:45 +0800 Subject: [PATCH 047/425] archive 2024-10-01 Signed-off-by: sbwml --- openwrt/23-config-musl-x86 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 092bdaae3..435ec41db 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -56,7 +56,3 @@ CONFIG_PACKAGE_kmod-sound-hda-intel=y CONFIG_PACKAGE_kmod-video-pwc=y CONFIG_PACKAGE_kmod-video-uvc=y CONFIG_PACKAGE_kmod-video-videobuf2=y - -### Virtualization -CONFIG_PACKAGE_kmod-kvm-intel=y -CONFIG_PACKAGE_kmod-kvm-x86=y From e704b3087959fcf2c946e294ce45b1617efd57ad Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 3 Oct 2024 07:25:25 +0800 Subject: [PATCH 048/425] build: remove some obsolete packages Signed-off-by: sbwml --- openwrt/23-config-common | 16 ---------- openwrt/patch/mt76/Makefile | 3 +- openwrt/scripts/01-prepare_base-mainline.sh | 11 +++++-- openwrt/scripts/02-prepare_package.sh | 34 +++++---------------- 4 files changed, 17 insertions(+), 47 deletions(-) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 56b4f2015..7451bc281 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -88,7 +88,6 @@ CONFIG_PACKAGE_luci-app-aria2=y CONFIG_PACKAGE_luci-app-autoreboot=y CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y -# CONFIG_PACKAGE_luci-app-daed is not set CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y @@ -138,18 +137,6 @@ CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Xray_Plugin=y # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Trojan_Plus is not set # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_V2ray_Plugin is not set -### SSR Plus -# CONFIG_PACKAGE_luci-app-ssr-plus is not set -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_IPT2Socks=y -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_Kcptun=y -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_Redsocks2=y -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_Simple_Obfs=y -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_Xray=y -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_Shadowsocks_Xray_Plugin=y -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_ShadowsocksR_Libev_Client=y -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_Hysteria is not set -# CONFIG_PACKAGE_luci-app-ssr-plus_INCLUDE_Trojan is not set - ### DDNS Scripts CONFIG_PACKAGE_ddns-scripts=y CONFIG_PACKAGE_ddns-scripts-aliyun=y @@ -256,7 +243,6 @@ CONFIG_PACKAGE_rsync=y CONFIG_PACKAGE_screen=y CONFIG_PACKAGE_sed=y CONFIG_PACKAGE_sshpass=y -CONFIG_PACKAGE_sudo=y CONFIG_PACKAGE_tar=y CONFIG_PACKAGE_taskset=y CONFIG_PACKAGE_telnet-bsd=y @@ -276,8 +262,6 @@ CONFIG_PACKAGE_zip=y CONFIG_PACKAGE_zoneinfo-asia=y ### Shadow Utilities -CONFIG_PACKAGE_shadow-chgpasswd=y -CONFIG_PACKAGE_shadow-chpasswd=y CONFIG_PACKAGE_shadow-gpasswd=y CONFIG_PACKAGE_shadow-groupadd=y CONFIG_PACKAGE_shadow-groupdel=y diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index e35cd6114..9d91cf65f 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -659,6 +659,7 @@ define KernelPackage/mt7992-firmware/install cp \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_2i5i.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm.bin \ @@ -670,7 +671,7 @@ define KernelPackage/mt7992-23-firmware/install cp \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp_23.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23_2i5i.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch_23.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa_23.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm_23.bin \ diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index b480635c7..c5eca34ef 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -2,7 +2,10 @@ ################################################################# -# Rockchip - target - r4s/r5s only +# autocore +git clone https://$github/sbwml/autocore-arm -b openwrt-23.05 package/system/autocore + +# rockchip - target - r4s/r5s only rm -rf target/linux/rockchip git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b linux-6.6 @@ -198,8 +201,10 @@ curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/arm64/312-arm64-cpu # fullcone curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-$kernel_version/952-net-conntrack-events-support-multiple-registrant.patch # bcm-fullcone -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-$kernel_version/982-add-bcm-fullcone-support.patch -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-$kernel_version/983-add-bcm-fullcone-nft_masq-support.patch +[ "$TESTING_KERNEL" != "y" ] && { + curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-$kernel_version/982-add-bcm-fullcone-support.patch + curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-$kernel_version/983-add-bcm-fullcone-nft_masq-support.patch +} # shortcut-fe curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-$kernel_version/601-netfilter-export-udp_get_timeouts-function.patch curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-$kernel_version/953-net-patch-linux-kernel-to-support-shortcut-fe.patch diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index be5178bd1..1849c4089 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -11,13 +11,13 @@ git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages # Default settings git clone https://$github/sbwml/default-settings package/new/default-settings -# DDNS +# ddns - fix boot sed -i '/boot()/,+2d' feeds/packages/net/ddns-scripts/files/etc/init.d/ddns # nlbwmon - disable syslog sed -i 's/stderr 1/stderr 0/g' feeds/packages/net/nlbwmon/files/nlbwmon.init -# boost - 1.84.0 +# boost - bump version rm -rf feeds/packages/libs/boost cp -a ../master/packages/libs/boost feeds/packages/libs/boost @@ -34,7 +34,7 @@ if [ "$ENABLE_DPDK" = "y" ]; then sed -i '/-Dcapng=disabled/i\\t-Dnuma=disabled \\' feeds/packages/utils/irqbalance/Makefile fi -# FRPC +# frpc rm -rf feeds/packages/net/frp cp -a ../master/packages/net/frp feeds/packages/net/frp sed -i 's/procd_set_param stdout $stdout/procd_set_param stdout 0/g' feeds/packages/net/frp/files/frpc.init @@ -71,17 +71,14 @@ sed -i 's/0666/0644/g;s/0777/0755/g' feeds/packages/net/samba4/files/smb.conf.te # rk3568 bind cpus [ "$platform" = "rk3568" ] && sed -i 's#/usr/sbin/smbd -F#/usr/bin/taskset -c 1,0 /usr/sbin/smbd -F#' feeds/packages/net/samba4/files/samba.init -# autoCore -git clone https://$github/sbwml/autocore-arm -b openwrt-23.05 package/new/autocore - -# Aria2 & ariaNG +# aria2 & ariaNG rm -rf feeds/packages/net/ariang rm -rf feeds/luci/applications/luci-app-aria2 git clone https://$github/sbwml/ariang-nginx package/new/ariang-nginx rm -rf feeds/packages/net/aria2 git clone https://$github/sbwml/feeds_packages_net_aria2 -b 22.03 feeds/packages/net/aria2 -# AirConnect +# airconnect git clone https://$github/sbwml/luci-app-airconnect package/new/airconnect # netkit-ftp @@ -94,20 +91,14 @@ git clone https://github.com/sbwml/package_new_nethogs package/new/nethogs rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 -# DAED -git clone https://$github/sbwml/luci-app-daed package/new/daed - # alist git clone https://$github/sbwml/openwrt-alist package/new/alist -# Netdata +# netdata rm -rf feeds/packages/admin/netdata cp -a ../master/packages/admin/netdata feeds/packages/admin/netdata sed -i 's/syslog/none/g' feeds/packages/admin/netdata/files/netdata.conf -# OpenAI -git clone https://$github/sbwml/luci-app-openai package/new/openai - # qBittorrent git clone https://$github/sbwml/luci-app-qbittorrent package/new/qbittorrent @@ -115,9 +106,6 @@ git clone https://$github/sbwml/luci-app-qbittorrent package/new/qbittorrent git clone https://$github/UnblockNeteaseMusic/luci-app-unblockneteasemusic package/new/luci-app-unblockneteasemusic sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new/luci-app-unblockneteasemusic/root/usr/share/luci/menu.d/luci-app-unblockneteasemusic.json -# xunlei -git clone https://$github/sbwml/luci-app-xunlei package/new/xunlei - # Theme git clone --depth 1 https://$github/sbwml/luci-theme-argon.git package/new/luci-theme-argon @@ -155,7 +143,7 @@ fi sed -i 's/<%:Up%>/<%:Move up%>/g' feeds/luci/modules/luci-compat/luasrc/view/cbi/tblsection.htm sed -i 's/<%:Down%>/<%:Move down%>/g' feeds/luci/modules/luci-compat/luasrc/view/cbi/tblsection.htm -# FRPC Translation +# frpc translation sed -i 's,发送,Transmission,g' feeds/luci/applications/luci-app-transmission/po/zh_Hans/transmission.po sed -i 's,frp 服务器,FRP 服务器,g' feeds/luci/applications/luci-app-frps/po/zh_Hans/frps.po sed -i 's,frp 客户端,FRP 客户端,g' feeds/luci/applications/luci-app-frpc/po/zh_Hans/frpc.po @@ -164,14 +152,6 @@ sed -i 's,frp 客户端,FRP 客户端,g' feeds/luci/applications/luci-app-frpc/p mkdir -p feeds/packages/net/sqm-scripts/patches curl -s https://$mirror/openwrt/patch/sqm/001-help-translation.patch > feeds/packages/net/sqm-scripts/patches/001-help-translation.patch -# mjpg-streamer init -sed -i "s,option port '8080',option port '1024',g" feeds/packages/multimedia/mjpg-streamer/files/mjpg-streamer.config -sed -i "s,option fps '5',option fps '25',g" feeds/packages/multimedia/mjpg-streamer/files/mjpg-streamer.config - -# luci-app-mjpg-streamer -rm -rf feeds/luci/applications/luci-app-mjpg-streamer -git clone https://$github/sbwml/luci-app-mjpg-streamer feeds/luci/applications/luci-app-mjpg-streamer - # unzip rm -rf feeds/packages/utils/unzip git clone https://$github/sbwml/feeds_packages_utils_unzip feeds/packages/utils/unzip From 457886954f633a0d6ba551bcf8c6c123483c5b7c Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 8 Oct 2024 16:58:17 +0800 Subject: [PATCH 049/425] openwrt 24.10 preliminary work Signed-off-by: sbwml --- openwrt/23-config-common | 20 +- openwrt/23-config-musl-r8500 | 20 +- openwrt/23-config-musl-r8500-minimal | 20 +- openwrt/build.sh | 70 +- openwrt/files/sbin/emmc-install | 30 +- openwrt/nginx/luci.locations | 12 +- ...mplate => openwrt-23.05-uci.conf.template} | 6 +- openwrt/nginx/openwrt-24.10-uci.conf.template | 57 + ...ch => 200-use-ntfs3-instead-of-ntfs.patch} | 0 ...patch => 201-fstools-set-ntfs3-utf8.patch} | 0 ...for-non-MTD-rootfs_data-new-version.patch} | 0 ...ort-extroot-for-non-MTD-rootfs_data.patch} | 0 openwrt/patch/fstools/Makefile | 141 ++ .../block-mount-add-fstools-depends.patch | 11 - .../0001-tools-add-llvm-clang-toolchain.patch | 89 ++ .../0002-tools-add-upx-tools.patch | 63 + ...3-rootfs-add-upx-compression-support.patch | 38 + ...ermissions-for-UCI-configuration-fil.patch | 25 + ...rt-for-local-kmod-installation-sourc.patch | 50 + ...add-MODULE_ALLOW_BTF_MISMATCH-option.patch | 26 + ...-Add-support-for-llvm-clang-compiler.patch | 102 ++ ...ath-Add-libquadmath-to-the-toolchain.patch | 25 + ...kernel-add-out-of-tree-kernel-config.patch | 115 ++ ...ernel-add-miss-config-for-linux-6.11.patch | 25 + ...rm-variable-to-cross-compilation-fil.patch | 36 + ...toolchain-gcc-add-support-for-GCC-15.patch | 79 ++ .../203-tools-mold-update-to-2.34.1.patch | 33 + .../900-bpf-headers-6.12rc.patch | 19 + ...=> 0008-tools-mold-update-to-2.34.1.patch} | 6 +- ...i-app-frpc-hide-token-openwrt-23.05.patch} | 0 ...ci-app-frpc-hide-token-openwrt-24.10.patch | 11 + ...-frpc-add-enable-flag-openwrt-23.05.patch} | 0 ...p-frpc-add-enable-flag-openwrt-24.10.patch | 16 + openwrt/patch/luci/dhcp/README.md | 5 +- .../dhcp/{dhcp.js => openwrt-23.05-dhcp.js} | 0 openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js | 1138 +++++++++++++++++ openwrt/patch/mt76/Makefile | 8 +- .../patch/mt76/patches/100-api_update.patch | 11 + openwrt/patch/openwrt-6.x/modules/video.mk | 41 +- openwrt/patch/openwrt-6.x/x86/64/config-6.6 | 1 - .../patch/packages-patches/jool/Makefile.24 | 150 +++ .../900-fix-linux-6.12-11.5.1.18.patch | 13 + openwrt/patch/pcre/Config.in | 11 + openwrt/patch/pcre/Makefile | 129 ++ ...ntfs3.patch => 201-util-linux_ntfs3.patch} | 8 +- openwrt/scripts/00-prepare_base.sh | 161 ++- openwrt/scripts/01-prepare_base-mainline.sh | 37 +- openwrt/scripts/02-prepare_package.sh | 46 +- openwrt/scripts/04-fix_kmod.sh | 69 +- openwrt/scripts/05-fix-source.sh | 66 +- tags/kernel-6.6 | 4 +- 51 files changed, 2796 insertions(+), 247 deletions(-) rename openwrt/nginx/{uci.conf.template => openwrt-23.05-uci.conf.template} (96%) create mode 100644 openwrt/nginx/openwrt-24.10-uci.conf.template rename openwrt/patch/fstools/{ntfs3.patch => 200-use-ntfs3-instead-of-ntfs.patch} (100%) rename openwrt/patch/fstools/{fstools-set-ntfs3-utf8-new.patch => 201-fstools-set-ntfs3-utf8.patch} (100%) rename openwrt/patch/fstools/{22-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch => 202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch} (100%) rename openwrt/patch/fstools/{22-fstools-support-extroot-for-non-MTD-rootfs_data.patch => 202-fstools-support-extroot-for-non-MTD-rootfs_data.patch} (100%) create mode 100644 openwrt/patch/fstools/Makefile delete mode 100644 openwrt/patch/fstools/block-mount-add-fstools-depends.patch create mode 100644 openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch create mode 100644 openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch create mode 100644 openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch create mode 100644 openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch create mode 100644 openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch create mode 100644 openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch create mode 100644 openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch create mode 100644 openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch create mode 100644 openwrt/patch/generic-24.10/0009-build-kernel-add-out-of-tree-kernel-config.patch create mode 100644 openwrt/patch/generic-24.10/0010-include-kernel-add-miss-config-for-linux-6.11.patch create mode 100644 openwrt/patch/generic-24.10/0011-meson-add-platform-variable-to-cross-compilation-fil.patch create mode 100644 openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch create mode 100644 openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch create mode 100644 openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch rename openwrt/patch/generic/mold/{0008-tools-mold-update-to-2.34.0.patch => 0008-tools-mold-update-to-2.34.1.patch} (85%) rename openwrt/patch/luci/applications/{001-luci-app-frpc-hide-token.patch => luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-23.05.patch} (100%) create mode 100644 openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-24.10.patch rename openwrt/patch/luci/applications/{002-luci-app-frpc-add-enable-flag.patch => luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-23.05.patch} (100%) create mode 100644 openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch rename openwrt/patch/luci/dhcp/{dhcp.js => openwrt-23.05-dhcp.js} (100%) create mode 100644 openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js create mode 100644 openwrt/patch/mt76/patches/100-api_update.patch create mode 100644 openwrt/patch/packages-patches/jool/Makefile.24 create mode 100644 openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch create mode 100644 openwrt/patch/pcre/Config.in create mode 100644 openwrt/patch/pcre/Makefile rename openwrt/patch/util-linux/{util-linux_ntfs3.patch => 201-util-linux_ntfs3.patch} (66%) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 7451bc281..b6376642e 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -73,11 +73,29 @@ CONFIG_PACKAGE_luci-proto-wireguard=y CONFIG_PACKAGE_luci-theme-argon=y CONFIG_PACKAGE_luci-theme-material=y CONFIG_PACKAGE_luci-theme-openwrt-2020=y -CONFIG_PACKAGE_nginx-all-module=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set +### Nginx +# openwrt-23.05 +CONFIG_PACKAGE_nginx-all-module=y +# openwrt-24.10 +CONFIG_PACKAGE_nginx-ssl=y +CONFIG_PACKAGE_nginx-mod-brotli=y +CONFIG_PACKAGE_nginx-mod-luci=y +CONFIG_PACKAGE_nginx-mod-rtmp=y +CONFIG_PACKAGE_nginx-mod-stream=y +CONFIG_PACKAGE_nginx-mod-ubus=y +CONFIG_PACKAGE_nginx-mod-zstd=y +CONFIG_PACKAGE_nginx-ssl-util=y +CONFIG_NGINX_DAV=y +CONFIG_NGINX_HTTP_AUTH_BASIC=y +CONFIG_NGINX_HTTP_QUIC=y +CONFIG_NGINX_HTTP_REAL_IP=y +CONFIG_NGINX_HTTP_SUB=y +CONFIG_NGINX_STREAM_REAL_IP=y + ### APPS CONFIG_PACKAGE_luci-app-accesscontrol=y CONFIG_PACKAGE_luci-app-airconnect=y diff --git a/openwrt/23-config-musl-r8500 b/openwrt/23-config-musl-r8500 index 027a6dff4..909d55e2e 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/23-config-musl-r8500 @@ -74,11 +74,29 @@ CONFIG_PACKAGE_luci-lib-jsonc=y CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_luci-theme-argon=y -CONFIG_PACKAGE_nginx-all-module=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set +### Nginx +# openwrt-23.05 +CONFIG_PACKAGE_nginx-all-module=y +# openwrt-24.10 +CONFIG_PACKAGE_nginx-ssl=y +CONFIG_PACKAGE_nginx-mod-brotli=y +CONFIG_PACKAGE_nginx-mod-luci=y +CONFIG_PACKAGE_nginx-mod-rtmp=y +CONFIG_PACKAGE_nginx-mod-stream=y +CONFIG_PACKAGE_nginx-mod-ubus=y +CONFIG_PACKAGE_nginx-mod-zstd=y +CONFIG_PACKAGE_nginx-ssl-util=y +CONFIG_NGINX_DAV=y +CONFIG_NGINX_HTTP_AUTH_BASIC=y +CONFIG_NGINX_HTTP_QUIC=y +CONFIG_NGINX_HTTP_REAL_IP=y +CONFIG_NGINX_HTTP_SUB=y +CONFIG_NGINX_STREAM_REAL_IP=y + ### APPS CONFIG_PACKAGE_luci-app-accesscontrol=y CONFIG_PACKAGE_luci-app-airconnect=y diff --git a/openwrt/23-config-musl-r8500-minimal b/openwrt/23-config-musl-r8500-minimal index cfbbc0b5b..f3e460e6a 100644 --- a/openwrt/23-config-musl-r8500-minimal +++ b/openwrt/23-config-musl-r8500-minimal @@ -73,9 +73,27 @@ CONFIG_PACKAGE_luci-lib-ipkg=y CONFIG_PACKAGE_luci-lib-jsonc=y CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y -CONFIG_PACKAGE_nginx-all-module=y CONFIG_LUCI_LANG_zh_Hans=y +### Nginx +# openwrt-23.05 +CONFIG_PACKAGE_nginx-all-module=y +# openwrt-24.10 +CONFIG_PACKAGE_nginx-ssl=y +CONFIG_PACKAGE_nginx-mod-brotli=y +CONFIG_PACKAGE_nginx-mod-luci=y +CONFIG_PACKAGE_nginx-mod-rtmp=y +CONFIG_PACKAGE_nginx-mod-stream=y +CONFIG_PACKAGE_nginx-mod-ubus=y +CONFIG_PACKAGE_nginx-mod-zstd=y +CONFIG_PACKAGE_nginx-ssl-util=y +CONFIG_NGINX_DAV=y +CONFIG_NGINX_HTTP_AUTH_BASIC=y +CONFIG_NGINX_HTTP_QUIC=y +CONFIG_NGINX_HTTP_REAL_IP=y +CONFIG_NGINX_HTTP_SUB=y +CONFIG_NGINX_STREAM_REAL_IP=y + ### APPS CONFIG_PACKAGE_luci-app-autoreboot=y CONFIG_PACKAGE_luci-app-ddns=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 9504a6212..ddc17194f 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -26,7 +26,7 @@ endgroup() { # IP Location ip_info=`curl -sk https://ip.cooluc.com`; -export isCN=`echo $ip_info | grep -Po 'country_code\":"\K[^"]+'`; +[ -n "$ip_info" ] && export isCN=`echo $ip_info | grep -Po 'country_code\":"\K[^"]+'` || export isCN=US # script url if [ "$isCN" = "CN" ]; then @@ -40,9 +40,6 @@ if [ "$(whoami)" = "runner" ] && [ -n "$GITHUB_REPO" ]; then export mirror=raw.githubusercontent.com/$GITHUB_REPO/master fi -# apply for sbwml/builder -[ -n "$git_password" ] && export mirror=init2.cooluc.com - # private gitea export gitea=git.cooluc.com @@ -89,14 +86,14 @@ fi # Source branch if [ "$1" = "dev" ]; then - export branch=openwrt-23.05 - export version=snapshots-23.05 - export toolchain_version=openwrt-23.05 + export branch=master + export version=snapshots-24.10 + export openwrt_version=openwrt-24.10 elif [ "$1" = "rc2" ]; then latest_release="v$(curl -s https://$mirror/tags/v23)" export branch=$latest_release export version=rc2 - export toolchain_version=openwrt-23.05 + export openwrt_version=openwrt-23.05 fi # lan @@ -177,17 +174,19 @@ echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" [ "$KERNEL_CLANG_LTO" = "y" ] && echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO: true${RES}\r\n" || echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO:${RES} ${YELLOW_COLOR}false${RES}\r\n" # clean old files -rm -rf openwrt master && mkdir master +rm -rf openwrt master # openwrt - releases [ "$(whoami)" = "runner" ] && group "source code" git clone --depth=1 https://$github/openwrt/openwrt -b $branch # openwrt master -git clone https://$github/openwrt/openwrt master/openwrt --depth=1 -git clone https://$github/openwrt/packages master/packages --depth=1 -git clone https://$github/openwrt/luci master/luci --depth=1 -git clone https://$github/openwrt/routing master/routing --depth=1 +if [ "$1" = "rc2" ]; then + git clone https://$github/openwrt/openwrt master/openwrt --depth=1 + git clone https://$github/openwrt/packages master/packages --depth=1 + git clone https://$github/openwrt/luci master/luci --depth=1 + git clone https://$github/openwrt/routing master/routing --depth=1 +fi # openwrt-23.05 [ "$1" = "rc2" ] && git clone https://$github/openwrt/openwrt -b openwrt-23.05 master/openwrt-23.05 --depth=1 @@ -199,6 +198,7 @@ git clone https://$github/immortalwrt/packages master/immortalwrt_packages --dep if [ -d openwrt ]; then cd openwrt [ "$1" = "rc2" ] && echo "$CURRENT_DATE" > version.date + [ "$1" = "dev" ] && sed -i 's/$(VERSION_NUMBER),SNAPSHOT/$(VERSION_NUMBER),24.10-SNAPSHOT/g' include/version.mk curl -Os https://$mirror/openwrt/patch/key.tar.gz && tar zxf key.tar.gz && rm -f key.tar.gz else echo -e "${RED_COLOR}Failed to download source code${RES}" @@ -266,7 +266,7 @@ bash 04-fix_kmod.sh bash 05-fix-source.sh [ "$(whoami)" = "runner" ] && endgroup -if [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ]; then +if [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ] && [ "$version" = "rc2" ]; then rm -rf toolchain/binutils cp -a ../master/openwrt/toolchain/binutils toolchain/binutils fi @@ -352,29 +352,31 @@ fi # openwrt-23.05 gcc11/13/14/15 [ "$(whoami)" = "runner" ] && group "patching toolchain" -if [ "$USE_GCC13" = "y" ] || [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ]; then - [ "$USE_GCC13" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc13 >> .config - [ "$USE_GCC14" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc14 >> .config - [ "$USE_GCC15" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc15 >> .config - curl -s https://$mirror/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 - # gcc14/15 init - cp -a toolchain/gcc/patches-13.x toolchain/gcc/patches-14.x - curl -s https://$mirror/openwrt/patch/generic/gcc-14/910-mbsd_multi.patch > toolchain/gcc/patches-14.x/910-mbsd_multi.patch +if [ "$1" = "rc2" ]; then + if [ "$USE_GCC13" = "y" ] || [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ]; then + curl -s https://$mirror/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 + # gcc14/15 init + cp -a toolchain/gcc/patches-13.x toolchain/gcc/patches-14.x + curl -s https://$mirror/openwrt/patch/generic/gcc-14/910-mbsd_multi.patch > toolchain/gcc/patches-14.x/910-mbsd_multi.patch + cp -a toolchain/gcc/patches-14.x toolchain/gcc/patches-15.x + curl -s https://$mirror/openwrt/patch/generic/gcc-15/970-macos_arm64-building-fix.patch > toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch + elif [ ! "$ENABLE_GLIBC" = "y" ]; then + curl -s https://$mirror/openwrt/generic/config-gcc11 >> .config + fi +else cp -a toolchain/gcc/patches-14.x toolchain/gcc/patches-15.x - curl -s https://$mirror/openwrt/patch/generic/gcc-15/970-macos_arm64-building-fix.patch > toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch -elif [ ! "$ENABLE_GLIBC" = "y" ]; then - curl -s https://$mirror/openwrt/generic/config-gcc11 >> .config + curl -s https://$mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 fi +[ "$USE_GCC13" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc13 >> .config +[ "$USE_GCC14" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc14 >> .config +[ "$USE_GCC15" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc15 >> .config [ "$(whoami)" = "runner" ] && endgroup # uhttpd [ "$ENABLE_UHTTPD" = "y" ] && sed -i '/nginx/d' .config && echo 'CONFIG_PACKAGE_ariang=y' >> .config -# bcm53xx: upx_list.txt -# [ "$platform" = "bcm53xx" ] && curl -s https://$mirror/openwrt/generic/upx_list.txt > upx_list.txt - # test kernel [ "$TESTING_KERNEL" = "y" ] && [ "$platform" = "bcm53xx" ] && sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config [ "$TESTING_KERNEL" = "y" ] && sed -i '1i\# Test kernel\nCONFIG_TESTING_KERNEL=y\n' .config @@ -385,16 +387,16 @@ fi # Toolchain Cache if [ "$BUILD_FAST" = "y" ]; then [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl - [ "$isCN" = "CN" ] && github_proxy="http://gh.cooluc.com/" || github_proxy="" + [ "$isCN" = "CN" ] && github_proxy="ghp.ci/" || github_proxy="" echo -e "\n${GREEN_COLOR}Download Toolchain ...${RES}" PLATFORM_ID="" [ -f /etc/os-release ] && source /etc/os-release if [ "$PLATFORM_ID" = "platform:el9" ]; then TOOLCHAIN_URL="http://127.0.0.1:8080" else - TOOLCHAIN_URL="$github_proxy"https://github.com/sbwml/openwrt_caches/releases/latest/download + TOOLCHAIN_URL=https://"$github_proxy"github.com/sbwml/openwrt_caches/releases/download/${openwrt_version} fi - curl -L "$TOOLCHAIN_URL"/toolchain_"$LIBC"_"$toolchain_arch"_gcc-"$gcc_version".tar.zst -o toolchain.tar.zst $CURL_BAR + curl -L ${TOOLCHAIN_URL}/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}.tar.zst -o toolchain.tar.zst $CURL_BAR echo -e "\n${GREEN_COLOR}Process Toolchain ...${RES}" tar -I "zstd" -xf toolchain.tar.zst rm -f toolchain.tar.zst @@ -419,7 +421,7 @@ if [ "$BUILD_TOOLCHAIN" = "y" ]; then rm -f dl/clang-* mkdir -p toolchain-cache [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl - tar -I "zstd -19 -T$(nproc --all)" -cf toolchain-cache/toolchain_"$LIBC"_"$toolchain_arch"_gcc-"$gcc_version".tar.zst ./{build_dir,dl,staging_dir,tmp} + tar -I "zstd -19 -T$(nproc --all)" -cf toolchain-cache/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}.tar.zst ./{build_dir,dl,staging_dir,tmp} echo -e "\n${GREEN_COLOR} Build success! ${RES}" exit 0 else diff --git a/openwrt/files/sbin/emmc-install b/openwrt/files/sbin/emmc-install index a05648872..93ede7f0a 100755 --- a/openwrt/files/sbin/emmc-install +++ b/openwrt/files/sbin/emmc-install @@ -6,25 +6,16 @@ # check commands=("bash" "parted" "awk" "sed" "grep" "zcat" "dd" "fdisk") for cmd in "${commands[@]}"; do - if command -v "$cmd" >/dev/null 2>&1; then - rm -rf /var/emmc-install - mkdir -p /var/emmc-install/{bin,lib} - cp $(which fdisk) /var/emmc-install/bin - cp /lib/{libc.so,libgcc_s.so.1} /var/emmc-install/lib - ln -sf /var/emmc-install/lib/libc.so /var/emmc-install/lib/ld-musl-aarch64.so.1 - cp /usr/lib/{libfdisk.so.*,libsmartcols.so.*,libncursesw.so.*,libblkid.so.*,libuuid.so.*} /var/emmc-install/lib - export PATH="/var/emmc-install/bin:$PATH" - export LD_LIBRARY_PATH="/var/emmc-install/lib:$LD_LIBRARY_PATH" - else - echo "Command $cmd does not exist." - exit 1 - fi + if command -v "$cmd" >/dev/null 2>&1; then + echo "Command $cmd does not exist." + exit 1 + fi done if [ -z "$1" ]; then echo "Firmware file does not specified." echo "Usage: $0 " - exit 1 + exit 0 fi echo " " @@ -32,7 +23,7 @@ echo "Starting eMMC Flashing ..." # eMMC device echo " " -echo "eMMC:" +echo "eMMC info" emmc_device=$(parted -l 2>/dev/null | grep -A 1 -E 'Model: MMC .*sd/mmc' | tail -n1 | awk '{print $2}' | sed 's/://g') emmc_size=$(parted -l 2>/dev/null | grep -A 1 -E 'Model: MMC .*sd/mmc' | tail -n1 | awk '{print $3}') emmc_device_name=$(echo $emmc_device | awk -F/ '{print $3}') @@ -54,8 +45,7 @@ echo " " read -p "This script will erase your eMMC. Continue [y/n]? " -n 1 -r echo " " if [[ $REPLY =~ ^[Nn]$ ]]; then - rm -rf /var/emmc-install - echo "Exiting script" + echo "Exiting script." exit 1 fi @@ -65,8 +55,8 @@ if [ -e "$firmware_file" ]; then if [ "$extension" = "gz" ]; then echo " " echo "Gzip decompression $firmware_file ..." - zcat "$firmware_file" > /var/emmc-install/firmware.img - firmware_file_path="/var/emmc-install/firmware.img" + zcat "$firmware_file" > /var/firmware.img + firmware_file_path="/var/firmware.img" elif [ "$extension" = "img" ]; then firmware_file_path="$firmware_file" else @@ -94,5 +84,5 @@ EOM fi echo " " echo "Done!" -echo "Please remove the TF card and power off and restart device." +echo "Please remove the TF card and Power off and restart device." echo " " diff --git a/openwrt/nginx/luci.locations b/openwrt/nginx/luci.locations index eab593d53..df639bbfe 100644 --- a/openwrt/nginx/luci.locations +++ b/openwrt/nginx/luci.locations @@ -3,18 +3,18 @@ location /cgi-bin/luci { include uwsgi_params; uwsgi_param SERVER_ADDR $server_addr; uwsgi_modifier1 9; - uwsgi_send_timeout 600; - uwsgi_connect_timeout 600; - uwsgi_read_timeout 600; + uwsgi_send_timeout 300; + uwsgi_connect_timeout 300; + uwsgi_read_timeout 300; uwsgi_pass unix:////var/run/luci-webui.socket; } location ~ /cgi-bin/cgi-(backup|download|upload|exec) { include uwsgi_params; uwsgi_param SERVER_ADDR $server_addr; uwsgi_modifier1 9; - uwsgi_send_timeout 600; - uwsgi_connect_timeout 600; - uwsgi_read_timeout 600; + uwsgi_send_timeout 300; + uwsgi_connect_timeout 300; + uwsgi_read_timeout 300; uwsgi_pass unix:////var/run/luci-cgi_io.socket; } diff --git a/openwrt/nginx/uci.conf.template b/openwrt/nginx/openwrt-23.05-uci.conf.template similarity index 96% rename from openwrt/nginx/uci.conf.template rename to openwrt/nginx/openwrt-23.05-uci.conf.template index ef053d075..6e81164ee 100644 --- a/openwrt/nginx/uci.conf.template +++ b/openwrt/nginx/openwrt-23.05-uci.conf.template @@ -2,7 +2,7 @@ # Parsing UCI configuration is skipped if uci set nginx.global.uci_enable=false # For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx -worker_processes 2; +worker_processes 1; user root; @@ -14,7 +14,7 @@ http { access_log off; server_names_hash_bucket_size 128; server_tokens build; - keepalive_timeout 600s; + keepalive_timeout 300s; log_format openwrt '$request_method $scheme://$host$request_uri => $status' ' (${body_bytes_sent}B in ${request_time}s) <- $http_referer'; @@ -39,7 +39,7 @@ http { image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; zstd on; zstd_comp_level 7; - zstd_min_length 1k; + zstd_min_length 1k; zstd_static on; zstd_types application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype diff --git a/openwrt/nginx/openwrt-24.10-uci.conf.template b/openwrt/nginx/openwrt-24.10-uci.conf.template new file mode 100644 index 000000000..0adb618cd --- /dev/null +++ b/openwrt/nginx/openwrt-24.10-uci.conf.template @@ -0,0 +1,57 @@ +# Consider using UCI or creating files in /etc/nginx/conf.d/ for configuration. +# Parsing UCI configuration is skipped if uci set nginx.global.uci_enable=false +# For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx +# UCI_CONF_VERSION=1.2 + +worker_processes 1; + +user root; + +include module.d/*.module; + +events { + worker_connections 1024; +} + +http { + access_log off; + server_names_hash_bucket_size 128; + server_tokens build; + keepalive_timeout 300s; + log_format openwrt + '$request_method $scheme://$host$request_uri => $status' + ' (${body_bytes_sent}B in ${request_time}s) <- $http_referer'; + + include mime.types; + default_type application/octet-stream; + sendfile on; + + client_max_body_size 8192M; + large_client_header_buffers 4 32k; + + gzip on; + gzip_vary on; + gzip_proxied any; + brotli on; + brotli_comp_level 6; + brotli_static on; + brotli_types application/atom+xml application/javascript application/json application/rss+xml + application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype + application/x-font-ttf application/x-javascript application/xhtml+xml application/xml + font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon + image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; + zstd on; + zstd_comp_level 7; + zstd_min_length 1k; + zstd_static on; + zstd_types application/atom+xml application/javascript application/json application/rss+xml + application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype + application/x-font-ttf application/x-javascript application/xhtml+xml application/xml + font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon + image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; + + root /www; + + #UCI_HTTP_CONFIG + include conf.d/*.conf; +} diff --git a/openwrt/patch/fstools/ntfs3.patch b/openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch similarity index 100% rename from openwrt/patch/fstools/ntfs3.patch rename to openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch diff --git a/openwrt/patch/fstools/fstools-set-ntfs3-utf8-new.patch b/openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch similarity index 100% rename from openwrt/patch/fstools/fstools-set-ntfs3-utf8-new.patch rename to openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch diff --git a/openwrt/patch/fstools/22-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch b/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch similarity index 100% rename from openwrt/patch/fstools/22-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch rename to openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch diff --git a/openwrt/patch/fstools/22-fstools-support-extroot-for-non-MTD-rootfs_data.patch b/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch similarity index 100% rename from openwrt/patch/fstools/22-fstools-support-extroot-for-non-MTD-rootfs_data.patch rename to openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch diff --git a/openwrt/patch/fstools/Makefile b/openwrt/patch/fstools/Makefile new file mode 100644 index 000000000..3b76b5be1 --- /dev/null +++ b/openwrt/patch/fstools/Makefile @@ -0,0 +1,141 @@ +# +# Copyright (C) 2014-2015 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=fstools +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL=$(PROJECT_GIT)/project/fstools.git +PKG_MIRROR_HASH:=4ec370a1cdc9fa69131f1403b064d2e05d54ee865411917410d7540454265319 +PKG_SOURCE_DATE:=2023-02-28 +PKG_SOURCE_VERSION:=bfe882d5ff4eeebb8f57c8a0f9b9e767a57870d8 +CMAKE_INSTALL:=1 + +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:= + +PKG_BUILD_FLAGS:=no-mips16 +PKG_FLAGS:=nonshared + +PKG_BUILD_DEPENDS := util-linux +PKG_CONFIG_DEPENDS := CONFIG_NAND_SUPPORT CONFIG_FSTOOLS_UBIFS_EXTROOT + +PKG_MAINTAINER:=John Crispin + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_UBIFS_EXTROOT),-DCMAKE_UBIFS_EXTROOT=y) +CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_OVL_MOUNT_FULL_ACCESS_TIME),-DCMAKE_OVL_MOUNT_FULL_ACCESS_TIME=y) +CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_OVL_MOUNT_COMPRESS_ZLIB),-DCMAKE_OVL_MOUNT_COMPRESS_ZLIB=y) + +define Package/fstools + SECTION:=base + CATEGORY:=Base system + DEPENDS:=+ubox +NAND_SUPPORT:ubi-utils + TITLE:=OpenWrt filesystem tools + MENU:=1 +endef + +define Package/fstools/config + config FSTOOLS_UBIFS_EXTROOT + depends on PACKAGE_fstools + depends on NAND_SUPPORT + bool "Support extroot functionality with UBIFS" + default y + help + This option makes it possible to use extroot functionality if the root filesystem resides on an UBIFS partition + + config FSTOOLS_OVL_MOUNT_FULL_ACCESS_TIME + depends on PACKAGE_fstools + bool "Full access time accounting" + default n + help + This option enables the full access time accounting (warning: it will increase the flash writes). + + config FSTOOLS_OVL_MOUNT_COMPRESS_ZLIB + depends on PACKAGE_fstools + bool "Compress using zlib" + default n + help + This option enables the compression using zlib on the storage device. +endef + +define Package/snapshot-tool + SECTION:=base + CATEGORY:=Base system + TITLE:=rootfs snapshoting tool + DEPENDS:=+libubox +fstools +endef + +define Package/block-mount/conffiles +/etc/config/fstab +endef + +define Package/block-mount + SECTION:=base + CATEGORY:=Base system + TITLE:=Block device mounting and checking + DEPENDS:=+ubox +libubox +libuci +libblobmsg-json +libjson-c +fstools +endef + +define Package/blockd + SECTION:=base + CATEGORY:=Base system + TITLE:=Block device automounting + DEPENDS:=+block-mount +fstools +libubus +kmod-fs-autofs4 +libblobmsg-json +libjson-c +endef + +define Package/fstools/install + $(INSTALL_DIR) $(1)/sbin $(1)/lib + + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{mount_root,jffs2reset} $(1)/sbin/ + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libfstools.so $(1)/lib/ + $(LN) jffs2reset $(1)/sbin/jffs2mark +endef + +define Package/snapshot-tool/install + $(INSTALL_DIR) $(1)/sbin + + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/snapshot_tool $(1)/sbin/ + $(INSTALL_BIN) ./files/snapshot $(1)/sbin/ +endef + +define Package/block-mount/install + $(INSTALL_DIR) $(1)/sbin $(1)/lib $(1)/usr/sbin $(1)/etc/hotplug.d/block $(1)/etc/init.d/ $(1)/etc/uci-defaults/ + + $(INSTALL_BIN) ./files/fstab.init $(1)/etc/init.d/fstab + $(INSTALL_CONF) ./files/fstab.default $(1)/etc/uci-defaults/10-fstab + $(INSTALL_CONF) ./files/mount.hotplug $(1)/etc/hotplug.d/block/10-mount + $(INSTALL_CONF) ./files/media-change.hotplug $(1)/etc/hotplug.d/block/00-media-change + + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/block $(1)/sbin/ + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libblkid-tiny.so $(1)/lib/ + $(LN) ../../sbin/block $(1)/usr/sbin/swapon + $(LN) ../../sbin/block $(1)/usr/sbin/swapoff + +endef + +define Package/blockd/install + $(INSTALL_DIR) $(1)/sbin $(1)/etc/init.d/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/blockd $(1)/sbin/ + $(INSTALL_BIN) ./files/blockd.init $(1)/etc/init.d/blockd +endef + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include + $(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/ + $(INSTALL_DIR) $(1)/usr/lib/ + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libubi-utils.a $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,fstools)) +$(eval $(call BuildPackage,snapshot-tool)) +$(eval $(call BuildPackage,block-mount)) +$(eval $(call BuildPackage,blockd)) diff --git a/openwrt/patch/fstools/block-mount-add-fstools-depends.patch b/openwrt/patch/fstools/block-mount-add-fstools-depends.patch deleted file mode 100644 index 84c8fc909..000000000 --- a/openwrt/patch/fstools/block-mount-add-fstools-depends.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/package/system/fstools/Makefile -+++ b/package/system/fstools/Makefile -@@ -82,7 +82,7 @@ define Package/block-mount - SECTION:=base - CATEGORY:=Base system - TITLE:=Block device mounting and checking -- DEPENDS:=+ubox +libubox +libuci +libblobmsg-json +libjson-c -+ DEPENDS:=+ubox +libubox +libuci +libblobmsg-json +libjson-c +fstools - endef - - define Package/blockd diff --git a/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch new file mode 100644 index 000000000..bfc51feae --- /dev/null +++ b/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch @@ -0,0 +1,89 @@ +From 441062a754bb94cace5e2bf700dc0b36c6bf2da7 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:35:57 +0800 +Subject: [PATCH 01/11] tools: add llvm/clang toolchain + +Signed-off-by: sbwml +--- + tools/Makefile | 7 +++++++ + tools/clang/Makefile | 43 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+) + create mode 100644 tools/clang/Makefile + +diff --git a/tools/Makefile b/tools/Makefile +index b16c5d9..7937334 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -29,6 +29,12 @@ endif + ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),) + BUILD_LZO_TOOLS = y + endif ++ifeq ($(CONFIG_KERNEL_CC),clang) ++ BUILD_CLANG_HOST = y ++endif ++ifeq ($(CONFIG_BPF_TOOLCHAIN_HOST),y) ++ BUILD_CLANG_HOST = y ++endif + + tools-y += autoconf + tools-y += autoconf-archive +@@ -70,6 +76,7 @@ tools-y += util-linux + tools-y += xz + tools-y += zip + tools-y += zlib ++tools-$(if $(BUILD_CLANG_HOST),y) += clang + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS),y) += liblzo + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_B43_TOOLS),y) += b43-tools + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_BZIP2_TOOLS),y) += bzip2 +diff --git a/tools/clang/Makefile b/tools/clang/Makefile +new file mode 100644 +index 0000000..2557a1d +--- /dev/null ++++ b/tools/clang/Makefile +@@ -0,0 +1,43 @@ ++# ++# Copyright (C) 2006-2017 OpenWrt.org ++# ++# This is free software, licensed under the GNU General Public License v2. ++# See /LICENSE for more information. ++# ++ ++include $(TOPDIR)/rules.mk ++ ++PKG_NAME:=clang ++PKG_VERSION:=19.0.1 ++ ++PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz ++PKG_SOURCE_URL:=https://github.com/sbwml/openwrt-llvm-toolchain/releases/download/$(PKG_VERSION)/ ++PKG_HASH:=a73c5ec6d62e0f47fd3cf25e3904b5818b18695b7302a9b404e411f2085110a3 ++ ++PKG_MAINTAINER:=sbwml ++PKG_LICENSE:=Apache-2.0 ++PKG_LICENSE_FILES:=LICENSE ++ ++include $(INCLUDE_DIR)/host-build.mk ++ ++define Host/Prepare ++ $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz ++endef ++ ++define Host/Compile ++endef ++ ++define Host/Install ++ $(CP) -a $(HOST_BUILD_DIR)/{bin,include,lib} $(STAGING_DIR_HOST)/ ++ $(RM) -rf $(HOST_BUILD_DIR)/{bin,include,lib,libexec,share} ++endef ++ ++define Host/Uninstall ++ ( \ ++ rm -rf $(STAGING_DIR_HOST)/bin/{*clang*,dsymutil,find-all-symbols,*lld*,llc,lli,llvm*,merge-fdata,opt,perf2bolt,wasm-ld} ; \ ++ rm -rf $(STAGING_DIR_HOST)/include/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,c++,clang*,i386-unknown-linux-gnu,i686-unknown-linux-musl,lld,llvm*,mach-o,polly,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ ++ rm -rf $(STAGING_DIR_HOST)/lib/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,bfd-plugins,clang,cmake,i386-unknown-linux-gnu,i686-unknown-linux-musl,libbolt*,libfindAllSymbols.a,liblld*,*LLVM*,libPolly*,libRemarks.so,libxml2*,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ ++ ) ++endef ++ ++$(eval $(call HostBuild)) +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch b/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch new file mode 100644 index 000000000..77a15f70d --- /dev/null +++ b/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch @@ -0,0 +1,63 @@ +From 7b122fef7e663cdcca2a0f027a9abeddf28ac6fd Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:39:25 +0800 +Subject: [PATCH 02/11] tools: add upx tools + +Signed-off-by: sbwml +--- + tools/Makefile | 1 + + tools/upx/Makefile | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 31 insertions(+) + create mode 100644 tools/upx/Makefile + +diff --git a/tools/Makefile b/tools/Makefile +index 7937334..0ab5956 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -72,6 +72,7 @@ tools-y += pkgconf + tools-y += quilt + tools-y += squashfs4 + tools-y += sstrip ++tools-y += upx + tools-y += util-linux + tools-y += xz + tools-y += zip +diff --git a/tools/upx/Makefile b/tools/upx/Makefile +new file mode 100644 +index 0000000..9004514 +--- /dev/null ++++ b/tools/upx/Makefile +@@ -0,0 +1,30 @@ ++include $(TOPDIR)/rules.mk ++ ++PKG_NAME:=upx ++PKG_VERSION:=4.2.4 ++ ++PKG_SOURCE:=upx-$(PKG_VERSION)-src.tar.xz ++PKG_SOURCE_URL:=https://github.com/upx/upx/releases/download/v$(PKG_VERSION)/ ++PKG_HASH:=5ed6561607d27fb4ef346fc19f08a93696fa8fa127081e7a7114068306b8e1c4 ++ ++HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)-src ++HOST_BUILD_PARALLEL:=1 ++ ++include $(INCLUDE_DIR)/host-build.mk ++ ++define Host/Compile ++ $(MAKE) -C $(HOST_BUILD_DIR)/src \ ++ LDFLAGS="$(HOST_LDFLAGS)" \ ++ CXX="$(HOSTCXX)" ++endef ++ ++define Host/Install ++ $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin ++ $(INSTALL_BIN) $(HOST_BUILD_DIR)/build/release/upx $(STAGING_DIR_HOST)/bin/upx ++endef ++ ++define Host/Clean ++ rm -f $(STAGING_DIR_HOST)/bin/upx ++endef ++ ++$(eval $(call HostBuild)) +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch b/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch new file mode 100644 index 000000000..aedffdee2 --- /dev/null +++ b/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch @@ -0,0 +1,38 @@ +From cd93413b2c4d79fd0596f2029d79a0cbda687d56 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:46:49 +0800 +Subject: [PATCH 03/11] rootfs: add upx compression support + +* When the upx_list.txt file exists in the source code root directory, + it will be compressed by upx. + +* fill in the binary path with rootfs as the absolute path, like this: + +/usr/bin/xray +/usr/bin/xray-plugin +/usr/sbin/haproxy + +Signed-off-by: sbwml +--- + include/rootfs.mk | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/rootfs.mk b/include/rootfs.mk +index 554dd48..d16618f 100644 +--- a/include/rootfs.mk ++++ b/include/rootfs.mk +@@ -122,6 +122,11 @@ define prepare_rootfs + $(1)/usr/lib/opkg/info/*.postinst* \ + $(1)/usr/lib/opkg/lists/* \ + $(1)/var/lock/*.lock ++ @if [ -f "$(TOPDIR)/upx_list.txt" ]; then \ ++ while IFS= read -r file; do \ ++ $(STAGING_DIR_HOST)/bin/upx --lzma --best "$(1)$$file" || true; \ ++ done < "$(TOPDIR)/upx_list.txt"; \ ++ fi + $(call clean_ipkg,$(1)) + $(call mklibs,$(1)) + $(if $(SOURCE_DATE_EPOCH),find $(1)/ -mindepth 1 -execdir touch -hcd "@$(SOURCE_DATE_EPOCH)" "{}" +) +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch b/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch new file mode 100644 index 000000000..f4e81b2f5 --- /dev/null +++ b/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch @@ -0,0 +1,25 @@ +From 2841d7c43220a473600e17c49dd7a8bba22a3108 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:47:41 +0800 +Subject: [PATCH 04/11] rootfs: add r/w permissions for UCI configuration files + +Signed-off-by: sbwml +--- + include/rootfs.mk | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/rootfs.mk b/include/rootfs.mk +index d16618f..02426c4 100644 +--- a/include/rootfs.mk ++++ b/include/rootfs.mk +@@ -127,6 +127,7 @@ define prepare_rootfs + $(STAGING_DIR_HOST)/bin/upx --lzma --best "$(1)$$file" || true; \ + done < "$(TOPDIR)/upx_list.txt"; \ + fi ++ chmod 600 $(1)/etc/config/* + $(call clean_ipkg,$(1)) + $(call mklibs,$(1)) + $(if $(SOURCE_DATE_EPOCH),find $(1)/ -mindepth 1 -execdir touch -hcd "@$(SOURCE_DATE_EPOCH)" "{}" +) +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch b/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch new file mode 100644 index 000000000..4bdfa418e --- /dev/null +++ b/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch @@ -0,0 +1,50 @@ +From c05c4c4a8765fc2dff676d38ee14319c8aee808e Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:48:29 +0800 +Subject: [PATCH 05/11] rootfs: Add support for local kmod installation sources + +* CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES=y + +Signed-off-by: sbwml +--- + config/Config-images.in | 8 ++++++++ + include/rootfs.mk | 6 ++++++ + 2 files changed, 14 insertions(+) + +diff --git a/config/Config-images.in b/config/Config-images.in +index 47f3dfc..ed9ecb2 100644 +--- a/config/Config-images.in ++++ b/config/Config-images.in +@@ -322,4 +322,12 @@ menu "Target Images" + across reboots. When enabled, /var/run will still be linked + to /tmp/run. + ++ config TARGET_ROOTFS_LOCAL_PACKAGES ++ bool "Create a local target package opkg installation source" ++ select ALL_KMODS ++ default n ++ help ++ Copy target packages to rootfs and overwrite the original ++ openwrt_core installation source with local files. ++ + endmenu +diff --git a/include/rootfs.mk b/include/rootfs.mk +index 02426c4..db19192 100644 +--- a/include/rootfs.mk ++++ b/include/rootfs.mk +@@ -128,6 +128,12 @@ define prepare_rootfs + done < "$(TOPDIR)/upx_list.txt"; \ + fi + chmod 600 $(1)/etc/config/* ++ @( \ ++ if [ "$(call qstrip,$(CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES))" = y ]; then \ ++ $(CP) $(TOPDIR)/bin/targets/$(BOARD)/$(SUBTARGET)/packages $(1)/usr/share/openwrt_core; \ ++ $(SED) "/openwrt_core/c\src/gz openwrt_core file:///usr/share/openwrt_core" $(1)/etc/opkg/distfeeds.conf; \ ++ fi; \ ++ ) + $(call clean_ipkg,$(1)) + $(call mklibs,$(1)) + $(if $(SOURCE_DATE_EPOCH),find $(1)/ -mindepth 1 -execdir touch -hcd "@$(SOURCE_DATE_EPOCH)" "{}" +) +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch b/openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch new file mode 100644 index 000000000..8309b25a4 --- /dev/null +++ b/openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch @@ -0,0 +1,26 @@ +From b7123fe13e05b078c978923bff06dfaa9cf41639 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:50:08 +0800 +Subject: [PATCH 06/11] kernel: add MODULE_ALLOW_BTF_MISMATCH option + +Signed-off-by: sbwml +--- + config/Config-kernel.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/config/Config-kernel.in b/config/Config-kernel.in +index 4bd2cde..c83f2fb 100644 +--- a/config/Config-kernel.in ++++ b/config/Config-kernel.in +@@ -448,7 +448,7 @@ config KERNEL_MODULE_ALLOW_BTF_MISMATCH + BTF rather than refusing to load. The default behavior with + module BTF enabled is to reject modules with such mismatches; + this option will still load module BTF where possible but ignore +- it when a mismatch is found. ++ it when a mismatch is found. (skip patch) + + config KERNEL_DEBUG_INFO_REDUCED + bool "Reduce debugging information" +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch new file mode 100644 index 000000000..5c707ef35 --- /dev/null +++ b/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch @@ -0,0 +1,102 @@ +From ae3e66eb2cca2e1642d4a4816241bfffe488fff8 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:51:22 +0800 +Subject: [PATCH 07/11] kernel: Add support for llvm/clang compiler + +Signed-off-by: sbwml +--- + config/Config-devel.in | 7 +++++++ + include/kernel-defaults.mk | 11 +++++++++++ + include/kernel.mk | 13 ++++++++++++- + include/package.mk | 4 ++++ + 4 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/config/Config-devel.in b/config/Config-devel.in +index cbac91c..9079303 100644 +--- a/config/Config-devel.in ++++ b/config/Config-devel.in +@@ -95,6 +95,13 @@ menuconfig DEVEL + default "-falign-functions=32" if TARGET_bcm53xx + default "" + ++ config KERNEL_CC ++ string "Set kernel C compiler" if DEVEL ++ default "\$(TARGET_CC)" ++ help ++ Enter C compiler name or full pathname i.e.: clang ++ If not set, uses '$(TARGET_CC)' ++ + config EXTERNAL_KERNEL_TREE + string "Use external kernel tree" if DEVEL + default "" +diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk +index f94ed33..c4a042b 100644 +--- a/include/kernel-defaults.mk ++++ b/include/kernel-defaults.mk +@@ -9,6 +9,17 @@ endif + + INITRAMFS_EXTRA_FILES ?= $(GENERIC_PLATFORM_DIR)/image/initramfs-base-files.txt + ++ifneq (,$(findstring clang,$(KERNEL_CC))) ++ ifneq (,$(filter clang-%,$(KERNEL_CC))) ++ LLVM := $(subst clang-,,$(KERNEL_CC)) ++ LLVM_LLD := ld.lld-$(subst clang-,,$(KERNEL_CC)) ++ else ++ LLVM := 1 ++ LLVM_LLD := ld.lld ++ endif ++ KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)" LD="$(LLVM_LLD)" LD=ld.lld LLVM=$(LLVM) LLVM_IAS=1 ++endif ++ + export HOST_EXTRACFLAGS=-I$(STAGING_DIR_HOST)/include + + # defined in quilt.mk +diff --git a/include/kernel.mk b/include/kernel.mk +index 6ef7663..4f89d9f 100644 +--- a/include/kernel.mk ++++ b/include/kernel.mk +@@ -35,7 +35,7 @@ else + KERNEL_CC?=$(HOSTCC) + KERNEL_CROSS?= + else +- KERNEL_CC?=$(TARGET_CC) ++ KERNEL_CC?=$(call qstrip,$(CONFIG_KERNEL_CC)) + KERNEL_CROSS?=$(TARGET_CROSS) + endif + +@@ -125,6 +125,17 @@ ifneq (,$(KERNEL_CC)) + KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)" + endif + ++ifneq (,$(findstring clang,$(KERNEL_CC))) ++ ifneq (,$(filter clang-%,$(KERNEL_CC))) ++ LLVM := $(subst clang-,,$(KERNEL_CC)) ++ LLVM_LLD := ld.lld-$(subst clang-,,$(KERNEL_CC)) ++ else ++ LLVM := 1 ++ LLVM_LLD := ld.lld ++ endif ++ KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)" LD="$(LLVM_LLD)" LLVM=$(LLVM) LLVM_IAS=1 ++endif ++ + KERNEL_NOSTDINC_FLAGS = \ + -nostdinc $(if $(DUMP),, -isystem $(shell $(TARGET_CC) -print-file-name=include)) + +diff --git a/include/package.mk b/include/package.mk +index 7fbecf9..3e988ed 100644 +--- a/include/package.mk ++++ b/include/package.mk +@@ -23,6 +23,10 @@ else + PKG_JOBS?=$(if $(PKG_BUILD_PARALLEL),$(MAKE_J),-j1) + endif + ++ifneq (,$(findstring clang,$(KERNEL_CC))) ++ MAKE := $(KERNEL_MAKE) ++endif ++ + PKG_BUILD_FLAGS?= + __unknown_flags=$(filter-out no-iremap no-mips16 gc-sections no-gc-sections lto no-lto no-mold,$(PKG_BUILD_FLAGS)) + ifneq ($(__unknown_flags),) +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch b/openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch new file mode 100644 index 000000000..86b9d2be3 --- /dev/null +++ b/openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch @@ -0,0 +1,25 @@ +From 1754cecb299a3f83eb68dc777262c5f3d6e06dc3 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:52:57 +0800 +Subject: [PATCH 08/11] libquadmath: Add libquadmath to the toolchain + +Signed-off-by: sbwml +--- + package/libs/toolchain/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/package/libs/toolchain/Makefile b/package/libs/toolchain/Makefile +index 7c117b1..f342368 100644 +--- a/package/libs/toolchain/Makefile ++++ b/package/libs/toolchain/Makefile +@@ -4,6 +4,7 @@ + # This is free software, licensed under the GNU General Public License v2. + # See /LICENSE for more information. + # ++# skip patch + + include $(TOPDIR)/rules.mk + PKG_NAME:=toolchain +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0009-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic-24.10/0009-build-kernel-add-out-of-tree-kernel-config.patch new file mode 100644 index 000000000..7d1a7840a --- /dev/null +++ b/openwrt/patch/generic-24.10/0009-build-kernel-add-out-of-tree-kernel-config.patch @@ -0,0 +1,115 @@ +From 532fa843ebb023b49421720f62ffae1a792b60e9 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:56:57 +0800 +Subject: [PATCH 09/11] build: kernel: add out-of-tree kernel config + +Signed-off-by: sbwml +--- + config/Config-devel.in | 7 ++++ + include/kernel-defaults.mk | 72 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 79 insertions(+) + +diff --git a/config/Config-devel.in b/config/Config-devel.in +index 9079303..2cbefc2 100644 +--- a/config/Config-devel.in ++++ b/config/Config-devel.in +@@ -102,6 +102,13 @@ menuconfig DEVEL + Enter C compiler name or full pathname i.e.: clang + If not set, uses '$(TARGET_CC)' + ++ config KERNEL_LRNG ++ bool "Kernel LRNG" if DEVEL ++ help ++ If enabled, provides a different approach to /dev/random ++ which is called Linux Random Number Generator (LRNG) to collect ++ entropy within the Linux kernel. ++ + config EXTERNAL_KERNEL_TREE + string "Use external kernel tree" if DEVEL + default "" +diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk +index c4a042b..2d6b968 100644 +--- a/include/kernel-defaults.mk ++++ b/include/kernel-defaults.mk +@@ -119,6 +119,78 @@ define Kernel/SetNoInitramfs + echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set + echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set + echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config.set ++# CLANG ++ mv $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.old ++ grep -v CONFIG_LTO $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set ++ifneq (,$(findstring clang,$(KERNEL_CC))) ++ echo 'CONFIG_LTO=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LTO_CLANG=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LTO_CLANG_FULL=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_HAS_LTO_CLANG=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_RANDSTRUCT_NONE=y' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_CFI_CLANG is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LTO_CLANG_THIN is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LTO_NONE is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_RANDSTRUCT_FULL is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_RELR is not set' >> $(LINUX_DIR)/.config.set ++endif ++# BTF ++ifeq ($(call qstrip,$(CONFIG_KERNEL_BPF_EVENTS)),y) ++ echo 'CONFIG_DEBUG_INFO_BTF_MODULES=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_PROBE_EVENTS_BTF_ARGS=y' >> $(LINUX_DIR)/.config.set ++endif ++# LRNG ++ifeq ($(call qstrip,$(CONFIG_KERNEL_LRNG)),y) ++ echo 'CONFIG_LRNG=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_AUTO_SELECTED=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_COLLECTION_SIZE_1024=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_CONTINUOUS_COMPRESSION_ENABLED=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_CPU=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_CPU_ENTROPY_RATE=8' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_DEV_IF=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_DFLT_DRNG_CHACHA20=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_IRQ=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_IRQ_DFLT_TIMER_ES=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_IRQ_ENTROPY_RATE=256' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_JENT=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_JENT_ENTROPY_BLOCKS=128' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_128=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_JENT_ENTROPY_RATE=16' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_KCAPI_IF=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_RUNTIME_ES_CONFIG=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_SCHED=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_SCHED_ENTROPY_RATE=4294967295' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_SWITCH_DRNG=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_SWITCH_HASH=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION=y' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_AIS2031_NTG1_SEEDING_STRATEGY is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_COLLECTION_SIZE_2048 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_COLLECTION_SIZE_256 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_COLLECTION_SIZE_4096 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_COLLECTION_SIZE_512 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_COLLECTION_SIZE_8192 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_CONTINUOUS_COMPRESSION_DISABLED is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_DFLT_DRNG_DRBG is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_DFLT_DRNG_KCAPI is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_HASH_KCAPI is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_HEALTH_TESTS is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_HWRAND_IF is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_DISABLED is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_1024 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_256 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_32 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_512 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_64 is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_SCHED_DFLT_TIMER_ES is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_SELFTEST is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_SWITCH_DRBG is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_SWITCH_DRNG_KCAPI is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LRNG_TESTING_MENU is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_RANDOM_DEFAULT_IMPL is not set' >> $(LINUX_DIR)/.config.set ++else ++ echo '# CONFIG_LRNG is not set' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_RANDOM_DEFAULT_IMPL=y' >> $(LINUX_DIR)/.config.set ++endif + endef + + define Kernel/Configure/Default +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0010-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic-24.10/0010-include-kernel-add-miss-config-for-linux-6.11.patch new file mode 100644 index 000000000..9638fa53b --- /dev/null +++ b/openwrt/patch/generic-24.10/0010-include-kernel-add-miss-config-for-linux-6.11.patch @@ -0,0 +1,25 @@ +From 046d307da1b54936b69c701bb3a3aa587853c65f Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:58:29 +0800 +Subject: [PATCH 10/11] include: kernel: add miss config for linux-6.11 + +Signed-off-by: sbwml +--- + include/kernel-defaults.mk | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk +index 2d6b968..36a1b30 100644 +--- a/include/kernel-defaults.mk ++++ b/include/kernel-defaults.mk +@@ -119,6 +119,7 @@ define Kernel/SetNoInitramfs + echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set + echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set + echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_FSCACHE is not set' >> $(LINUX_DIR)/.config.set + # CLANG + mv $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.old + grep -v CONFIG_LTO $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0011-meson-add-platform-variable-to-cross-compilation-fil.patch b/openwrt/patch/generic-24.10/0011-meson-add-platform-variable-to-cross-compilation-fil.patch new file mode 100644 index 000000000..6d032d7dc --- /dev/null +++ b/openwrt/patch/generic-24.10/0011-meson-add-platform-variable-to-cross-compilation-fil.patch @@ -0,0 +1,36 @@ +From eb740ac64eeab24f9968d3013d2fa5752c7c2b0b Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 10:58:54 +0800 +Subject: [PATCH 11/11] meson: add platform variable to cross-compilation file + +Signed-off-by: sbwml +--- + include/meson.mk | 1 + + tools/meson/files/openwrt-cross.txt.in | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/include/meson.mk b/include/meson.mk +index 2a20c2b..f5333f7 100644 +--- a/include/meson.mk ++++ b/include/meson.mk +@@ -90,6 +90,7 @@ define Meson/CreateCrossFile + -e "s|@LDFLAGS@|$(foreach FLAG,$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS),'$(FLAG)',)|" \ + -e "s|@ARCH@|$(MESON_ARCH)|" \ + -e "s|@CPU@|$(MESON_CPU)|" \ ++ -e "s|@PLAT@|$(MESON_CPU)|" \ + -e "s|@ENDIAN@|$(if $(CONFIG_BIG_ENDIAN),big,little)|" \ + < $(MESON_DIR)/openwrt-cross.txt.in \ + > $(1) +diff --git a/tools/meson/files/openwrt-cross.txt.in b/tools/meson/files/openwrt-cross.txt.in +index 836a0e5..cc83bc8 100644 +--- a/tools/meson/files/openwrt-cross.txt.in ++++ b/tools/meson/files/openwrt-cross.txt.in +@@ -24,4 +24,5 @@ cpu = '@CPU@' + endian = '@ENDIAN@' + + [properties] ++platform = '@PLAT@' + needs_exe_wrapper = true +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch new file mode 100644 index 000000000..d76ba43d0 --- /dev/null +++ b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -0,0 +1,79 @@ +From b903fc6e637efd50ffba4269e019a44301e44bad Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 4 Oct 2024 11:07:07 +0800 +Subject: [PATCH] toolchain: gcc: add support for GCC 15 + +Signed-off-by: sbwml +--- + toolchain/gcc/Config.in | 3 +++ + toolchain/gcc/Config.version | 5 +++++ + toolchain/gcc/common.mk | 10 +++++++++- + 3 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in +index b306040..3ab16a8 100644 +--- a/toolchain/gcc/Config.in ++++ b/toolchain/gcc/Config.in +@@ -17,6 +17,9 @@ choice + + config GCC_USE_VERSION_14 + bool "gcc 14.x" ++ ++ config GCC_USE_VERSION_15 ++ bool "gcc 15.x" + endchoice + + config GCC_USE_GRAPHITE +diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version +index 49bb368..be06df2 100644 +--- a/toolchain/gcc/Config.version ++++ b/toolchain/gcc/Config.version +@@ -10,12 +10,17 @@ config GCC_VERSION_14 + default y if GCC_USE_VERSION_14 + bool + ++config GCC_VERSION_15 ++ default y if GCC_USE_VERSION_15 ++ bool ++ + config GCC_VERSION + string + default EXTERNAL_GCC_VERSION if EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN + default "11.3.0" if GCC_VERSION_11 + default "12.3.0" if GCC_VERSION_12 + default "14.2.0" if GCC_VERSION_14 ++ default "15.0.0" if GCC_VERSION_15 + default "13.3.0" + + config GCC_USE_DEFAULT_VERSION +diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk +index 0ccf55b..e1b760d 100644 +--- a/toolchain/gcc/common.mk ++++ b/toolchain/gcc/common.mk +@@ -26,7 +26,11 @@ PKG_VERSION:=$(firstword $(subst +, ,$(GCC_VERSION))) + GCC_MAJOR_VERSION:=$(word 1,$(subst ., ,$(PKG_VERSION))) + GCC_DIR:=$(PKG_NAME)-$(PKG_VERSION) + +-PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) ++ifeq ($(PKG_VERSION),15.0.0) ++ PKG_SOURCE_URL:=https://us.cooluc.com/gcc ++else ++ PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) ++endif + PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz + PKG_CPE_ID:=cpe:/a:gnu:gcc + +@@ -46,6 +50,10 @@ ifeq ($(PKG_VERSION),14.2.0) + PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 + endif + ++ifeq ($(PKG_VERSION),15.0.0) ++ PKG_HASH:=56d5e11d0c75077f8c556e57f2f317d9d324b28070a868fc85dc1108bd0508b3 ++endif ++ + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x + + BUGURL=http://bugs.openwrt.org/ +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch b/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch new file mode 100644 index 000000000..8ea6d85f6 --- /dev/null +++ b/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch @@ -0,0 +1,33 @@ +From 0b193c7b7c908758a703245071068182b08b7ef2 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 6 Oct 2024 06:20:50 +0800 +Subject: [PATCH] tools/mold: update to 2.34.1 + +Signed-off-by: sbwml +--- + tools/mold/Makefile | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/tools/mold/Makefile b/tools/mold/Makefile +index 28d760d..1a37b68 100644 +--- a/tools/mold/Makefile ++++ b/tools/mold/Makefile +@@ -3,12 +3,11 @@ + include $(TOPDIR)/rules.mk + + PKG_NAME:=mold +-PKG_VERSION:=2.33.0 ++PKG_VERSION:=2.34.1 + + PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +-PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz +-PKG_SOURCE_URL:=https://github.com/rui314/mold/archive/refs/tags +-PKG_HASH:=37b3aacbd9b6accf581b92ba1a98ca418672ae330b78fe56ae542c2dcb10a155 ++PKG_SOURCE_URL:=https://codeload.github.com/rui314/mold/tar.gz/v$(PKG_VERSION)? ++PKG_HASH:=a8cf638045b4a4b2697d0bcc77fd96eae93d54d57ad3021bf03b0333a727a59d + + include $(INCLUDE_DIR)/host-build.mk + include $(INCLUDE_DIR)/cmake.mk +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch b/openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch new file mode 100644 index 000000000..19c738e1f --- /dev/null +++ b/openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch @@ -0,0 +1,19 @@ +diff --git a/package/kernel/bpf-headers/Makefile b/package/kernel/bpf-headers/Makefile +index a644f47..216dd47 100644 +--- a/package/kernel/bpf-headers/Makefile ++++ b/package/kernel/bpf-headers/Makefile +@@ -13,12 +13,12 @@ include $(INCLUDE_DIR)/kernel.mk + + + PKG_NAME:=linux +-PKG_PATCHVER:=6.6 ++PKG_PATCHVER:=6.12 + # Manually include kernel version and hash from kernel details file + include $(INCLUDE_DIR)/kernel-$(PKG_PATCHVER) + + PKG_VERSION:=$(PKG_PATCHVER)$(strip $(LINUX_VERSION-$(PKG_PATCHVER))) +-PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz ++PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz + PKG_SOURCE_URL:=@KERNEL/linux/kernel/v$(word 1,$(subst ., ,$(PKG_PATCHVER))).x + PKG_HASH:=$(LINUX_KERNEL_HASH-$(strip $(PKG_VERSION))) + PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/bpf-headers/$(PKG_NAME)-$(PKG_VERSION) diff --git a/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch b/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch similarity index 85% rename from openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch rename to openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch index 3641d2af5..834ad6e5c 100644 --- a/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch +++ b/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch @@ -1,7 +1,7 @@ From 76471b08d9e1b5e9686b4444c5db53dd9c56bcfe Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 17 Jul 2024 08:51:39 +0800 -Subject: [PATCH 8/8] tools/mold: update to 2.34.0 +Subject: [PATCH 8/8] tools/mold: update to 2.34.1 Signed-off-by: sbwml --- @@ -17,14 +17,14 @@ index e8fcecb..d0b4443 100644 PKG_NAME:=mold -PKG_VERSION:=1.11.0 -+PKG_VERSION:=2.34.0 ++PKG_VERSION:=2.34.1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz -PKG_SOURCE_URL:=https://github.com/rui314/mold/archive/refs/tags -PKG_HASH:=99318eced81b09a77e4c657011076cc8ec3d4b6867bd324b8677974545bc4d6f +PKG_SOURCE_URL:=https://codeload.github.com/rui314/mold/tar.gz/v$(PKG_VERSION)? -+PKG_HASH:=6067f41f624c32cb0f4e959ae7fabee5dd71dd06771e2c069c2b3a6a8eca3c8c ++PKG_HASH:=a8cf638045b4a4b2697d0bcc77fd96eae93d54d57ad3021bf03b0333a727a59d include $(INCLUDE_DIR)/host-build.mk include $(INCLUDE_DIR)/cmake.mk diff --git a/openwrt/patch/luci/applications/001-luci-app-frpc-hide-token.patch b/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-23.05.patch similarity index 100% rename from openwrt/patch/luci/applications/001-luci-app-frpc-hide-token.patch rename to openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-23.05.patch diff --git a/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-24.10.patch b/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-24.10.patch new file mode 100644 index 000000000..1a0bbdef5 --- /dev/null +++ b/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-24.10.patch @@ -0,0 +1,11 @@ +--- a/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js ++++ b/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js +@@ -24,7 +24,7 @@ var commonConf = [ + [form.ListValue, 'log_level', _('Log level'), _('LogLevel specifies the minimum log level. Valid values are "trace", "debug", "info", "warn", and "error".
By default, this value is "info".'), {values: ['trace', 'debug', 'info', 'warn', 'error']}], + [form.Value, 'log_max_days', _('Log max days'), _('LogMaxDays specifies the maximum number of days to store log information before deletion. This is only used if LogWay == "file".
By default, this value is 0.'), {datatype: 'uinteger'}], + [form.Flag, 'disable_log_color', _('Disable log color'), _('DisableLogColor disables log colors when LogWay == "console" when set to true.'), {datatype: 'bool', default: 'false'}], +- [form.Value, 'token', _('Token'), _('Token specifies the authorization token used to create keys to be sent to the server. The server must have a matching token for authorization to succeed.
By default, this value is "".')], ++ [form.Value, 'token', _('Token'), _('Token specifies the authorization token used to create keys to be sent to the server. The server must have a matching token for authorization to succeed.
By default, this value is "".'), {password: true}], + [form.Value, 'admin_addr', _('Admin address'), _('AdminAddr specifies the address that the admin server binds to.
By default, this value is "0.0.0.0".'), {datatype: 'ipaddr'}], + [form.Value, 'admin_port', _('Admin port'), _('AdminPort specifies the port for the admin server to listen on. If this value is 0, the admin server will not be started.
By default, this value is 0.'), {datatype: 'port'}], + [form.Value, 'admin_user', _('Admin user'), _('AdminUser specifies the username that the admin server will use for login.
By default, this value is "admin".')], diff --git a/openwrt/patch/luci/applications/002-luci-app-frpc-add-enable-flag.patch b/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-23.05.patch similarity index 100% rename from openwrt/patch/luci/applications/002-luci-app-frpc-add-enable-flag.patch rename to openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-23.05.patch diff --git a/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch b/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch new file mode 100644 index 000000000..189d53666 --- /dev/null +++ b/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch @@ -0,0 +1,16 @@ +--- a/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js ++++ b/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js +@@ -7,11 +7,10 @@ + + // [Widget, Option, Title, Description, {Param: 'Value'}], + var startupConf = [ +- [form.Flag, 'stdout', _('Log stdout')], +- [form.Flag, 'stderr', _('Log stderr')], ++ [form.Flag, 'enable', _('Enable'), undefined, {datatype: 'bool', default: 'true', rmempty: false}], + [widgets.UserSelect, 'user', _('Run daemon as user')], + [widgets.GroupSelect, 'group', _('Run daemon as group')], +- [form.Flag, 'respawn', _('Respawn when crashed')], ++ [form.Flag, 'respawn', _('Respawn when crashed'), undefined, {datatype: 'bool', default: 'true', rmempty: false}], + [form.DynamicList, 'env', _('Environment variable'), _('OS environments pass to frp for config file template, see frp README'), {placeholder: 'ENV_NAME=value'}], + [form.DynamicList, 'conf_inc', _('Additional configs'), _('Config files include in temporary config file'), {placeholder: '/etc/frp/frpc.d/frpc_full.ini'}] + ]; diff --git a/openwrt/patch/luci/dhcp/README.md b/openwrt/patch/luci/dhcp/README.md index 107de0f44..90d8a5152 100644 --- a/openwrt/patch/luci/dhcp/README.md +++ b/openwrt/patch/luci/dhcp/README.md @@ -1 +1,4 @@ -### LuCI DHCP COMMIT: https://github.com/openwrt/luci/commit/1f36628bc60f6e1f33667b025917eebec19d3162 +### LuCI DHCP COMMIT: + +openwrt-23.05: https://github.com/openwrt/luci/commit/1f36628bc60f6e1f33667b025917eebec19d3162 +openwrt-24.10: https://github.com/openwrt/luci/commit/8c8073729fc0220444dce7bacca97f9c6f8a8305 diff --git a/openwrt/patch/luci/dhcp/dhcp.js b/openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js similarity index 100% rename from openwrt/patch/luci/dhcp/dhcp.js rename to openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js diff --git a/openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js b/openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js new file mode 100644 index 000000000..484c766f0 --- /dev/null +++ b/openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js @@ -0,0 +1,1138 @@ +'use strict'; +'require view'; +'require dom'; +'require poll'; +'require rpc'; +'require uci'; +'require form'; +'require network'; +'require validation'; +'require tools.widgets as widgets'; + +var callHostHints, callDUIDHints, callDHCPLeases, CBILeaseStatus, CBILease6Status; + +callHostHints = rpc.declare({ + object: 'luci-rpc', + method: 'getHostHints', + expect: { '': {} } +}); + +callDUIDHints = rpc.declare({ + object: 'luci-rpc', + method: 'getDUIDHints', + expect: { '': {} } +}); + +callDHCPLeases = rpc.declare({ + object: 'luci-rpc', + method: 'getDHCPLeases', + expect: { '': {} } +}); + +CBILeaseStatus = form.DummyValue.extend({ + renderWidget: function(section_id, option_id, cfgvalue) { + return E([ + E('h4', _('Active DHCP Leases')), + E('table', { 'id': 'lease_status_table', 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Hostname')), + E('th', { 'class': 'th' }, _('IPv4 address')), + E('th', { 'class': 'th' }, _('MAC address')), + E('th', { 'class': 'th' }, _('Lease time remaining')) + ]), + E('tr', { 'class': 'tr placeholder' }, [ + E('td', { 'class': 'td' }, E('em', _('Collecting data...'))) + ]) + ]) + ]); + } +}); + +CBILease6Status = form.DummyValue.extend({ + renderWidget: function(section_id, option_id, cfgvalue) { + return E([ + E('h4', _('Active DHCPv6 Leases')), + E('table', { 'id': 'lease6_status_table', 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Host')), + E('th', { 'class': 'th' }, _('IPv6 address')), + E('th', { 'class': 'th' }, _('DUID')), + E('th', { 'class': 'th' }, _('Lease time remaining')) + ]), + E('tr', { 'class': 'tr placeholder' }, [ + E('td', { 'class': 'td' }, E('em', _('Collecting data...'))) + ]) + ]) + ]); + } +}); + +function calculateNetwork(addr, mask) { + addr = validation.parseIPv4(String(addr)); + + if (!isNaN(mask)) + mask = validation.parseIPv4(network.prefixToMask(+mask)); + else + mask = validation.parseIPv4(String(mask)); + + if (addr == null || mask == null) + return null; + + return [ + [ + addr[0] & (mask[0] >>> 0 & 255), + addr[1] & (mask[1] >>> 0 & 255), + addr[2] & (mask[2] >>> 0 & 255), + addr[3] & (mask[3] >>> 0 & 255) + ].join('.'), + mask.join('.') + ]; +} + +function generateDnsmasqInstanceEntry(data) { + const nameValueMap = new Map(Object.entries(data)); + let formatString = nameValueMap.get('.index') + ' (' + _('Name') + (nameValueMap.get('.anonymous') ? ': dnsmasq[' + nameValueMap.get('.index') + ']': ': ' + nameValueMap.get('.name')); + + if (data.domain) { + formatString += ', ' + _('Domain') + ': ' + data.domain; + } + if (data.local) { + formatString += ', ' + _('Local') + ': ' + data.local; + } + formatString += ')'; + + return [nameValueMap.get('.name'), formatString]; +} + +function getDHCPPools() { + return uci.load('dhcp').then(function() { + let sections = uci.sections('dhcp', 'dhcp'), + tasks = [], pools = []; + + for (var i = 0; i < sections.length; i++) { + if (sections[i].ignore == '1' || !sections[i].interface) + continue; + + tasks.push(network.getNetwork(sections[i].interface).then(L.bind(function(section_id, net) { + var cidr = net ? (net.getIPAddrs()[0] || '').split('/') : null; + + if (cidr && cidr.length == 2) { + var net_mask = calculateNetwork(cidr[0], cidr[1]); + + pools.push({ + section_id: section_id, + network: net_mask[0], + netmask: net_mask[1] + }); + } + }, null, sections[i]['.name']))); + } + + return Promise.all(tasks).then(function() { + return pools; + }); + }); +} + +function validateHostname(sid, s) { + if (s == null || s == '') + return true; + + if (s.length > 256) + return _('Expecting: %s').format(_('valid hostname')); + + var labels = s.replace(/^\*?\.?|\.$/g, '').split(/\./); + + for (var i = 0; i < labels.length; i++) + if (!labels[i].match(/^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i)) + return _('Expecting: %s').format(_('valid hostname')); + + return true; +} + +function validateAddressList(sid, s) { + if (s == null || s == '') + return true; + + var m = s.match(/^\/(.+)\/$/), + names = m ? m[1].split(/\//) : [ s ]; + + for (var i = 0; i < names.length; i++) { + var res = validateHostname(sid, names[i]); + + if (res !== true) + return res; + } + + return true; +} + +function validateServerSpec(sid, s) { + if (s == null || s == '') + return true; + + var m = s.match(/^(\/.*\/)?(.*)$/); + if (!m) + return _('Expecting: %s').format(_('valid hostname')); + + if (m[1] != '//' && m[1] != '/#/') { + var res = validateAddressList(sid, m[1]); + if (res !== true) + return res; + } + + if (m[2] == '' || m[2] == '#') + return true; + + // ipaddr%scopeid#srvport@source@interface#srcport + + m = m[2].match(/^([0-9a-f:.]+)(?:%[^#@]+)?(?:#(\d+))?(?:@([0-9a-f:.]+)(?:@[^#]+)?(?:#(\d+))?)?$/); + + if (!m) + return _('Expecting: %s').format(_('valid IP address')); + + if (validation.parseIPv4(m[1])) { + if (m[3] != null && !validation.parseIPv4(m[3])) + return _('Expecting: %s').format(_('valid IPv4 address')); + } + else if (validation.parseIPv6(m[1])) { + if (m[3] != null && !validation.parseIPv6(m[3])) + return _('Expecting: %s').format(_('valid IPv6 address')); + } + else { + return _('Expecting: %s').format(_('valid IP address')); + } + + if ((m[2] != null && +m[2] > 65535) || (m[4] != null && +m[4] > 65535)) + return _('Expecting: %s').format(_('valid port value')); + + return true; +} + +function expandAndFormatMAC(macs) { + let result = []; + + macs.forEach(mac => { + if (isValidMAC(mac)) { + const expandedMac = mac.split(':').map(part => { + return (part.length === 1 && part !== '*') ? '0' + part : part; + }).join(':').toUpperCase(); + result.push(expandedMac); + } + }); + + return result.length ? result : null; +} + +function isValidMAC(sid, s) { + if (!s) + return true; + + let macaddrs = L.toArray(s); + + for (var i = 0; i < macaddrs.length; i++) + if (!macaddrs[i].match(/^(([0-9a-f]{1,2}|\*)[:-]){5}([0-9a-f]{1,2}|\*)$/i)) + return _('Expecting a valid MAC address, optionally including wildcards') + _('; invalid MAC: ') + macaddrs[i]; + + return true; +} + +function validateMACAddr(pools, sid, s) { + if (s == null || s == '') + return true; + + var leases = uci.sections('dhcp', 'host'), + this_macs = L.toArray(s).map(function(m) { return m.toUpperCase() }); + + for (var i = 0; i < pools.length; i++) { + var this_net_mask = calculateNetwork(this.section.formvalue(sid, 'ip'), pools[i].netmask); + + if (!this_net_mask) + continue; + + for (var j = 0; j < leases.length; j++) { + if (leases[j]['.name'] == sid || !leases[j].ip) + continue; + + var lease_net_mask = calculateNetwork(leases[j].ip, pools[i].netmask); + + if (!lease_net_mask || this_net_mask[0] != lease_net_mask[0]) + continue; + + var lease_macs = L.toArray(leases[j].mac).map(function(m) { return m.toUpperCase() }); + + for (var k = 0; k < lease_macs.length; k++) + for (var l = 0; l < this_macs.length; l++) + if (lease_macs[k] == this_macs[l]) + return _('The MAC address %h is already used by another static lease in the same DHCP pool').format(this_macs[l]); + } + } + + return isValidMAC(sid, s); +} + +return view.extend({ + load: function() { + return Promise.all([ + callHostHints(), + callDUIDHints(), + getDHCPPools(), + network.getNetworks() + ]); + }, + + render: function(hosts_duids_pools) { + var has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'), + hosts = hosts_duids_pools[0], + duids = hosts_duids_pools[1], + pools = hosts_duids_pools[2], + networks = hosts_duids_pools[3], + m, s, o, ss, so; + + let noi18nstrings = { + etc_hosts: '/etc/hosts', + etc_ethers: '/etc/ethers', + localhost_v6: '::1', + loopback_slash_8_v4: '127.0.0.0/8', + not_found: 'Not found', + nxdomain: 'NXDOMAIN', + rfc_1918_link: 'RFC1918', + rfc_4193_link: 'RFC4193', + rfc_4291_link: 'RFC4291', + rfc_6303_link: 'RFC6303', + reverse_arpa: '*.IN-ADDR.ARPA,*.IP6.ARPA', + servers_file_entry01: 'server=1.2.3.4', + servers_file_entry02: 'server=/domain/1.2.3.4', + + }; + + function customi18n(template, values) { + if (!values) + values = noi18nstrings; + return template.replace(/\{(\w+)\}/g, (match, key) => values[key] || match); + }; + + m = new form.Map('dhcp', _('DHCP and DNS'), + _('Dnsmasq is a lightweight DHCP server and DNS forwarder.')); + + s = m.section(form.TypedSection, 'dnsmasq'); + s.anonymous = true; + s.addremove = false; + + s.tab('general', _('General Settings')); + s.tab('advanced', _('Advanced Settings')); + s.tab('leases', _('Static Leases')); + s.tab('files', _('Resolv and Hosts Files')); + s.tab('hosts', _('Hostnames')); + s.tab('ipsets', _('IP Sets')); + s.tab('relay', _('Relay')); + s.tab('srvhosts', _('SRV')); + s.tab('mxhosts', _('MX')); + s.tab('cnamehosts', _('CNAME')); + s.tab('pxe_tftp', _('PXE/TFTP Settings')); + + s.taboption('general', form.Flag, 'domainneeded', + _('Domain required'), + _('Never forward DNS queries which lack dots or domain parts.') + '
' + + customi18n(_('Names not in {etc_hosts} are answered {not_found}.') ) + ); + s.taboption('general', form.Flag, 'authoritative', + _('Authoritative'), + _('This is the only DHCP server in the local network.')); + + o = s.taboption('general', form.Value, 'local', + _('Resolve these locally'), + _('Never forward these matching domains or subdomains; resolve from DHCP or hosts files only.')); + o.placeholder = '/internal.example.com/private.example.com/example.org'; + + s.taboption('general', form.Value, 'domain', + _('Local domain'), + _('Local domain suffix appended to DHCP names and hosts file entries.')); + + o = s.taboption('general', form.Flag, 'logqueries', + _('Log queries'), + _('Write received DNS queries to syslog.') + ' ' + _('Dump cache on SIGUSR1, include requesting IP.')); + o.optional = true; + + o = s.taboption('general', form.DynamicList, 'server', + _('DNS forwardings'), + _('Forward specific domain queries to specific upstream servers.')); + o.optional = true; + o.placeholder = '/*.example.org/10.1.2.3'; + o.validate = validateServerSpec; + + o = s.taboption('general', form.DynamicList, 'address', + _('Addresses'), + _('Resolve specified FQDNs to an IP.') + '
' + + customi18n(_('Syntax: {code_syntax}.'), + {code_syntax: '/fqdn[/fqdn…]/[ipaddr]'}) + '
' + + customi18n(_('{example_nx} returns {nxdomain}.', + 'hint: /example.com/ returns NXDOMAIN.'), + {example_nx: '/example.com/', nxdomain: 'NXDOMAIN'}) + '
' + + customi18n(_('{any_domain} matches any domain (and returns {nxdomain}).', + 'hint: /#/ matches any domain (and returns NXDOMAIN).'), + {any_domain:'/#/', nxdomain: 'NXDOMAIN'}) + '
' + + customi18n( + _('{example_null} returns {null_addr} addresses ({null_ipv4}, {null_ipv6}) for {example_com} and its subdomains.', + 'hint: /example.com/# returns NULL addresses (0.0.0.0, ::) for example.com and its subdomains.'), + { example_null: '/example.com/#', + null_addr: 'NULL', + null_ipv4: '0.0.0.0', + null_ipv6: '::', + example_com: 'example.com', + } + ) + ); + o.optional = true; + o.placeholder = '/router.local/router.lan/192.168.0.1'; + + o = s.taboption('general', form.DynamicList, 'ipset', + _('IP sets'), + _('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.')); + o.optional = true; + o.placeholder = '/example.org/ipset,ipset6'; + + o = s.taboption('general', form.Flag, 'rebind_protection', + _('Rebind protection'), + customi18n(_('Discard upstream responses containing {rfc_1918_link} addresses.') ) + '
' + + customi18n(_('Discard also upstream responses containing {rfc_4193_link}, Link-Local and private IPv4-Mapped {rfc_4291_link} IPv6 Addresses.') ) + ); + o.rmempty = false; + + o = s.taboption('general', form.Flag, 'rebind_localhost', + _('Allow localhost'), + customi18n( + _('Exempt {loopback_slash_8_v4} and {localhost_v6} from rebinding checks, e.g. for RBL services.') + ) + ); + o.depends('rebind_protection', '1'); + + o = s.taboption('general', form.DynamicList, 'rebind_domain', + _('Domain whitelist'), + customi18n(_('List of domains to allow {rfc_1918_link} responses for.') ) + ); + o.depends('rebind_protection', '1'); + o.optional = true; + o.placeholder = 'ihost.netflix.com'; + o.validate = validateAddressList; + + o = s.taboption('general', form.Flag, 'localservice', + _('Local service only'), + _('Accept DNS queries only from hosts whose address is on a local subnet.')); + o.optional = false; + o.rmempty = false; + + o = s.taboption('general', form.Flag, 'nonwildcard', + _('Non-wildcard'), + _('Bind only to configured interface addresses, instead of the wildcard address.')); + o.default = o.enabled; + o.optional = false; + o.rmempty = true; + + o = s.taboption('general', widgets.NetworkSelect, 'interface', + _('Listen interfaces'), + _('Listen only on the specified interfaces, and loopback if not excluded explicitly.')); + o.multiple = true; + o.nocreate = true; + + o = s.taboption('general', widgets.NetworkSelect, 'notinterface', + _('Exclude interfaces'), + _('Do not listen on the specified interfaces.')); + o.loopback = true; + o.multiple = true; + o.nocreate = true; + + o = s.taboption('relay', form.SectionValue, '__relays__', form.TableSection, 'relay', null, + _('Relay DHCP requests elsewhere. OK: v4↔v4, v6↔v6. Not OK: v4↔v6, v6↔v4.') + + '
' + _('Note: you may also need a DHCP Proxy (currently unavailable) when specifying a non-standard Relay To port(addr#port).') + + '
' + _('You may add multiple unique Relay To on the same Listen addr.')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + ss.rowcolors = true; + ss.nodescriptions = true; + + so = ss.option(form.Value, 'local_addr', _('Relay from')); + so.rmempty = false; + so.datatype = 'ipaddr'; + + for (var family = 4; family <= 6; family += 2) { + for (var i = 0; i < networks.length; i++) { + if (networks[i].getName() != 'loopback') { + var addrs = (family == 6) ? networks[i].getIP6Addrs() : networks[i].getIPAddrs(); + for (var j = 0; j < addrs.length; j++) { + var addr = addrs[j].split('/')[0]; + so.value(addr, E([], [ + addr, ' (', + widgets.NetworkSelect.prototype.renderIfaceBadge(networks[i]), + ')' + ])); + } + } + } + } + + so = ss.option(form.Value, 'server_addr', _('Relay to address')); + so.rmempty = false; + so.optional = false; + so.placeholder = '192.168.10.1#535'; + + so.validate = function(section, value) { + var m = this.section.formvalue(section, 'local_addr'), + n = this.section.formvalue(section, 'server_addr'), + p; + + if (!m || !n) { + return _('Both "Relay from" and "Relay to address" must be specified.'); + } + else { + p = n.split('#'); + if (p.length > 1 && !/^[0-9]+$/.test(p[1])) + return _('Expected port number.'); + else + n = p[0]; + + if ((validation.parseIPv6(m) && validation.parseIPv6(n)) || + validation.parseIPv4(m) && validation.parseIPv4(n)) + return true; + else + return _('Address families of "Relay from" and "Relay to address" must match.') + } + return true; + }; + + + so = ss.option(widgets.NetworkSelect, 'interface', _('Only accept replies via')); + so.optional = true; + so.rmempty = false; + so.placeholder = 'lan'; + + s.taboption('files', form.Flag, 'readethers', + customi18n(_('Use {etc_ethers}') ), + customi18n(_('Read {etc_ethers} to configure the DHCP server.') ) + ); + + s.taboption('files', form.Value, 'leasefile', + _('Lease file'), + _('File to store DHCP lease information.')); + + o = s.taboption('files', form.Flag, 'noresolv', + _('Ignore resolv file')); + o.optional = true; + + o = s.taboption('files', form.Value, 'resolvfile', + _('Resolv file'), + _('File with upstream resolvers.')); + o.depends('noresolv', '0'); + o.placeholder = '/tmp/resolv.conf.d/resolv.conf.auto'; + o.optional = true; + + o = s.taboption('files', form.Flag, 'nohosts', + customi18n(_('Ignore {etc_hosts}') ) + ); + o.optional = true; + + o = s.taboption('files', form.DynamicList, 'addnhosts', + _('Additional hosts files')); + o.optional = true; + o.placeholder = '/etc/dnsmasq.hosts'; + + o = s.taboption('advanced', form.Flag, 'quietdhcp', + _('Suppress logging'), + _('Suppress logging of the routine operation for the DHCP protocol.')); + o.optional = true; + + o = s.taboption('advanced', form.Flag, 'sequential_ip', + _('Allocate IPs sequentially'), + _('Allocate IP addresses sequentially, starting from the lowest available address.')); + o.optional = true; + + o = s.taboption('advanced', form.Flag, 'boguspriv', + _('Filter private'), + customi18n( + _('Reject reverse lookups to {rfc_6303_link} IP ranges ({reverse_arpa}) not in {etc_hosts}.') ) + ); + o.default = o.enabled; + + s.taboption('advanced', form.Flag, 'filterwin2k', + _('Filter SRV/SOA service discovery'), + _('Filters SRV/SOA service discovery, to avoid triggering dial-on-demand links.') + '
' + + _('May prevent VoIP or other services from working.')); + + o = s.taboption('advanced', form.Flag, 'filter_aaaa', + _('Filter IPv6 AAAA records'), + _('Remove IPv6 addresses from the results and only return IPv4 addresses.') + '
' + + _('Can be useful if ISP has IPv6 nameservers but does not provide IPv6 routing.')); + o.optional = true; + + o = s.taboption('advanced', form.Flag, 'filter_a', + _('Filter IPv4 A records'), + _('Remove IPv4 addresses from the results and only return IPv6 addresses.')); + o.optional = true; + + s.taboption('advanced', form.Flag, 'localise_queries', + _('Localise queries'), + customi18n(_('Limit response records (from {etc_hosts}) to those that fall within the subnet of the querying interface.') ) + '
' + + _('This prevents unreachable IPs in subnets not accessible to you.') + '
' + + _('Note: IPv4 only.')); + + if (L.hasSystemFeature('dnsmasq', 'dnssec')) { + o = s.taboption('advanced', form.Flag, 'dnssec', + _('DNSSEC'), + _('Validate DNS replies and cache DNSSEC data, requires upstream to support DNSSEC.')); + o.optional = true; + + o = s.taboption('advanced', form.Flag, 'dnsseccheckunsigned', + _('DNSSEC check unsigned'), + _('Verify unsigned domain responses really come from unsigned domains.')); + o.default = o.enabled; + o.optional = true; + } + + s.taboption('advanced', form.Flag, 'expandhosts', + _('Expand hosts'), + _('Add local domain suffix to names served from hosts files.')); + + s.taboption('advanced', form.Flag, 'nonegcache', + _('No negative cache'), + _('Do not cache negative replies, e.g. for non-existent domains.')); + + o = s.taboption('advanced', form.Value, 'serversfile', + _('Additional servers file'), + customi18n(_('File listing upstream resolvers, optionally domain-specific, e.g. {servers_file_entry01}, {servers_file_entry02}.') ) + ); + o.placeholder = '/etc/dnsmasq.servers'; + + o = s.taboption('advanced', form.Flag, 'strictorder', + _('Strict order'), + _('Upstream resolvers will be queried in the order of the resolv file.')); + o.optional = true; + + o = s.taboption('advanced', form.Flag, 'allservers', + _('All servers'), + _('Query all available upstream resolvers.')); + o.optional = true; + + o = s.taboption('advanced', form.DynamicList, 'bogusnxdomain', + customi18n(_('IPs to override with {nxdomain}') ), + customi18n(_('Transform replies which contain the specified addresses or subnets into {nxdomain} responses.') ) + ); + o.optional = true; + o.placeholder = '64.94.110.11'; + + o = s.taboption('advanced', form.Value, 'port', + _('DNS server port'), + _('Listening port for inbound DNS queries.')); + o.optional = true; + o.datatype = 'port'; + o.placeholder = 53; + + o = s.taboption('advanced', form.Value, 'queryport', + _('DNS query port'), + _('Fixed source port for outbound DNS queries.')); + o.optional = true; + o.datatype = 'port'; + o.placeholder = _('any'); + + o = s.taboption('advanced', form.Value, 'dhcpleasemax', + _('Max. DHCP leases'), + _('Maximum allowed number of active DHCP leases.')); + o.optional = true; + o.datatype = 'uinteger'; + o.placeholder = _('unlimited'); + + o = s.taboption('advanced', form.Value, 'ednspacket_max', + _('Max. EDNS0 packet size'), + _('Maximum allowed size of EDNS0 UDP packets.')); + o.optional = true; + o.datatype = 'uinteger'; + o.placeholder = 1280; + + o = s.taboption('advanced', form.Value, 'dnsforwardmax', + _('Max. concurrent queries'), + _('Maximum allowed number of concurrent DNS queries.')); + o.optional = true; + o.datatype = 'uinteger'; + o.placeholder = 150; + + o = s.taboption('advanced', form.Value, 'cachesize', + _('Size of DNS query cache'), + _('Number of cached DNS entries, 10000 is maximum, 0 is no caching.')); + o.optional = true; + o.datatype = 'range(0,10000)'; + o.placeholder = 1000; + + o = s.taboption('advanced', form.Value, 'addmac', + _('Add requestor MAC'), + _('Add the MAC address of the requestor to DNS queries which are forwarded upstream.') + ' ' + '
' + + _('%s uses the default MAC address format encoding').format('enabled') + ' ' + '
' + + _('%s uses an alternative encoding of the MAC as base64').format('base64') + ' ' + '
' + + _('%s uses a human-readable encoding of hex-and-colons').format('text')); + o.optional = true; + o.value('', _('off')); + o.value('1', _('enabled (default)')); + o.value('base64'); + o.value('text'); + s.taboption('advanced', form.Flag, 'stripmac', + _('Remove MAC address before forwarding query'), + _('Remove any MAC address information already in downstream queries before forwarding upstream.')); + o = s.taboption('advanced', form.Value, 'addsubnet', + _('Add subnet address to forwards'), + _('Add a subnet address to the DNS queries which are forwarded upstream, leaving this value empty disables the feature.') + ' ' + + _('If an address is specified in the flag, it will be used, otherwise, the address of the requestor will be used.') + ' ' + + _('The amount of the address forwarded depends on the prefix length parameter: 32 (128 for IPv6) forwards the whole address, zero forwards none of it but still marks the request so that no upstream nameserver will add client address information either.') + ' ' + '
' + + _('The default (%s) is zero for both IPv4 and IPv6.').format('0,0') + ' ' + '
' + + _('%s adds the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.').format('24,96') + ' ' + '
' + + _('%s adds 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.').format('1.2.3.4/24') + ' ' + '
' + + _('%s adds 1.2.3.0/24 for both IPv4 and IPv6 requestors.').format('1.2.3.4/24,1.2.3.4/24')); + o.optional = true; + s.taboption('advanced', form.Flag, 'stripsubnet', + _('Remove subnet address before forwarding query'), + _('Remove any subnet address already present in a downstream query before forwarding it upstream.')); + + o = s.taboption('pxe_tftp', form.Flag, 'enable_tftp', + _('Enable TFTP server'), + _('Enable the built-in single-instance TFTP server.')); + o.optional = true; + + o = s.taboption('pxe_tftp', form.Value, 'tftp_root', + _('TFTP server root'), + _('Root directory for files served via TFTP. Enable TFTP server and TFTP server root turn on the TFTP server and serve files from TFTP server root.')); + o.depends('enable_tftp', '1'); + o.optional = true; + o.placeholder = '/'; + + o = s.taboption('pxe_tftp', form.Value, 'dhcp_boot', + _('Network boot image'), + _('Filename of the boot image advertised to clients.')); + o.depends('enable_tftp', '1'); + o.optional = true; + o.placeholder = 'pxelinux.0'; + + /* PXE - https://openwrt.org/docs/guide-user/base-system/dhcp#booting_options */ + o = s.taboption('pxe_tftp', form.SectionValue, '__pxe__', form.GridSection, 'boot', null, + _('Special PXE boot options for Dnsmasq.')); + ss = o.subsection; + ss.addremove = true; + ss.anonymous = true; + ss.nodescriptions = true; + + so = ss.option(form.Value, 'filename', + _('Filename'), + _('Host requests this filename from the boot server.')); + so.optional = false; + so.placeholder = 'pxelinux.0'; + + so = ss.option(form.Value, 'servername', + _('Server name'), + _('The hostname of the boot server')); + so.optional = false; + so.placeholder = 'myNAS'; + + so = ss.option(form.Value, 'serveraddress', + _('Server address'), + _('The IP address of the boot server')); + so.optional = false; + so.placeholder = '192.168.1.2'; + + so = ss.option(form.DynamicList, 'dhcp_option', + _('DHCP Options'), + _('Options for the Network-ID. (Note: needs also Network-ID.) E.g. "42,192.168.1.4" for NTP server, "3,192.168.4.4" for default route. 0.0.0.0 means "the address of the system running dnsmasq".')); + so.optional = true; + so.placeholder = '42,192.168.1.4'; + + so = ss.option(widgets.DeviceSelect, 'networkid', + _('Network-ID'), + _('Apply DHCP Options to this net. (Empty = all clients).')); + so.optional = true; + so.noaliases = true; + + so = ss.option(form.Flag, 'force', + _('Force'), + _('Always send DHCP Options. Sometimes needed, with e.g. PXELinux.')); + so.optional = true; + + so = ss.option(form.Value, 'instance', + _('Instance'), + _('Dnsmasq instance to which this boot section is bound. If unspecified, the section is valid for all dnsmasq instances.')); + so.optional = true; + + Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { + var [name, display_str] = generateDnsmasqInstanceEntry(val); + so.value(name, display_str); + }); + + o = s.taboption('srvhosts', form.SectionValue, '__srvhosts__', form.TableSection, 'srvhost', null, + _('Bind service records to a domain name: specify the location of services. See RFC2782.').format('https://datatracker.ietf.org/doc/html/rfc2782') + + '
' + _('_service: _sip, _ldap, _imap, _stun, _xmpp-client, … . (Note: while _http is possible, no browsers support SRV records.)') + + '
' + _('_proto: _tcp, _udp, _sctp, _quic, … .') + + '
' + _('You may add multiple records for the same Target.') + + '
' + _('Larger weights (of the same prio) are given a proportionately higher probability of being selected.')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + ss.rowcolors = true; + + so = ss.option(form.Value, 'srv', _('SRV'), _('Syntax:') + ' ' + '_service._proto.example.com.'); + so.rmempty = false; + so.datatype = 'hostname'; + so.placeholder = '_sip._tcp.example.com.'; + + so = ss.option(form.Value, 'target', _('Target'), _('CNAME or fqdn')); + so.rmempty = false; + so.datatype = 'hostname'; + so.placeholder = 'sip.example.com.'; + + so = ss.option(form.Value, 'port', _('Port')); + so.rmempty = false; + so.datatype = 'port'; + so.placeholder = '5060'; + + so = ss.option(form.Value, 'class', _('Priority'), _('Ordinal: lower comes first.')); + so.rmempty = true; + so.datatype = 'range(0,65535)'; + so.placeholder = '10'; + + so = ss.option(form.Value, 'weight', _('Weight')); + so.rmempty = true; + so.datatype = 'range(0,65535)'; + so.placeholder = '50'; + + o = s.taboption('mxhosts', form.SectionValue, '__mxhosts__', form.TableSection, 'mxhost', null, + _('Bind service records to a domain name: specify the location of services.') + + '
' + _('You may add multiple records for the same domain.')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + ss.rowcolors = true; + ss.nodescriptions = true; + + so = ss.option(form.Value, 'domain', _('Domain')); + so.rmempty = false; + so.datatype = 'hostname'; + so.placeholder = 'example.com.'; + + so = ss.option(form.Value, 'relay', _('Relay')); + so.rmempty = false; + so.datatype = 'hostname'; + so.placeholder = 'relay.example.com.'; + + so = ss.option(form.Value, 'pref', _('Priority'), _('Ordinal: lower comes first.')); + so.rmempty = true; + so.datatype = 'range(0,65535)'; + so.placeholder = '0'; + + o = s.taboption('cnamehosts', form.SectionValue, '__cname__', form.TableSection, 'cname', null, + _('Set an alias for a hostname.')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + ss.rowcolors = true; + ss.nodescriptions = true; + + so = ss.option(form.Value, 'cname', _('Domain')); + so.rmempty = false; + so.validate = validateHostname; + so.placeholder = 'www.example.com.'; + + so = ss.option(form.Value, 'target', _('Target')); + so.rmempty = false; + so.datatype = 'hostname'; + so.placeholder = 'example.com.'; + + o = s.taboption('hosts', form.SectionValue, '__hosts__', form.GridSection, 'domain', null, + _('Hostnames are used to bind a domain name to an IP address. This setting is redundant for hostnames already configured with static leases, but it can be useful to rebind an FQDN.')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + + so = ss.option(form.Value, 'name', _('Hostname')); + so.rmempty = false; + so.datatype = 'hostname'; + + so = ss.option(form.Value, 'ip', _('IP address')); + so.rmempty = false; + so.datatype = 'ipaddr'; + + var ipaddrs = {}; + + Object.keys(hosts).forEach(function(mac) { + var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4); + + for (var i = 0; i < addrs.length; i++) + ipaddrs[addrs[i]] = hosts[mac].name || mac; + }); + + L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { + so.value(ipv4, '%s (%s)'.format(ipv4, ipaddrs[ipv4])); + }); + + o = s.taboption('ipsets', form.SectionValue, '__ipsets__', form.GridSection, 'ipset', null, + _('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.') + '
' + + _('The netfilter components below are only regarded when running fw4.')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + ss.rowcolors = true; + ss.nodescriptions = true; + ss.modaltitle = _('Edit IP set'); + + so = ss.option(form.DynamicList, 'name', _('Name of the set')); + so.rmempty = false; + so.editable = true; + so.datatype = 'string'; + + so = ss.option(form.DynamicList, 'domain', _('FQDN')); + so.rmempty = false; + so.editable = true; + so.datatype = 'hostname'; + + so = ss.option(form.Value, 'table', _('Netfilter table name'), _('Defaults to fw4.')); + so.editable = true; + so.placeholder = 'fw4'; + so.rmempty = true; + + so = ss.option(form.ListValue, 'table_family', _('Table IP family'), _('Defaults to IPv4+6.') + ' ' + _('Can be hinted by adding 4 or 6 to the name.') + '
' + + _('Adding an IPv6 to an IPv4 set and vice-versa silently fails.')); + so.editable = true; + so.rmempty = true; + so.value('inet', _('IPv4+6')); + so.value('ip', _('IPv4')); + so.value('ip6', _('IPv6')); + + o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null, + _('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '

' + + _('Use the Add Button to add a new lease entry. The MAC address identifies the host, the IPv4 address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.') + '

' + + _('The tag construct filters which host directives are used; more than one tag can be provided, in this case the request must match all of them. Tagged directives are used in preference to untagged ones. Note that one of mac, duid or hostname still needs to be specified (can be a wildcard).')); + + ss = o.subsection; + + ss.addremove = true; + ss.anonymous = true; + ss.sortable = true; + ss.nodescriptions = true; + ss.max_cols = 8; + ss.modaltitle = _('Edit static lease'); + + so = ss.option(form.Value, 'name', + _('Hostname'), + _('Optional hostname to assign')); + so.validate = validateHostname; + so.rmempty = true; + so.write = function(section, value) { + uci.set('dhcp', section, 'name', value); + uci.set('dhcp', section, 'dns', '1'); + }; + so.remove = function(section) { + uci.unset('dhcp', section, 'name'); + uci.unset('dhcp', section, 'dns'); + }; + + //this can be a .DynamicList or a .Value with a widget and dnsmasq handles multimac OK. + so = ss.option(form.DynamicList, 'mac', + _('MAC address(es)'), + _('The hardware address(es) of this entry/host.') + '

' + + _('In DHCPv4, it is possible to include more than one mac address. This allows an IP address to be associated with multiple macaddrs, and dnsmasq abandons a DHCP lease to one of the macaddrs when another asks for a lease. It only works reliably if only one of the macaddrs is active at any time.')); + //As a special case, in DHCPv4, it is possible to include more than one hardware address. eg: --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2 This allows an IP address to be associated with multiple hardware addresses, and gives dnsmasq permission to abandon a DHCP lease to one of the hardware addresses when another one asks for a lease + so.rmempty = true; + so.cfgvalue = function(section) { + var macs = uci.get('dhcp', section, 'mac'); + if(!Array.isArray(macs)){ + return expandAndFormatMAC(L.toArray(macs)); + } else { + return expandAndFormatMAC(macs); + } + }; + //removed jows renderwidget function which hindered multi-mac entry + so.validate = validateMACAddr.bind(so, pools); + Object.keys(hosts).forEach(function(mac) { + var hint = hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0]; + so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); + }); + + so = ss.option(form.Value, 'ip', _('IPv4 address'), _('The IP address to be used for this host, or ignore to ignore any DHCP request from this host.')); + so.value('ignore', _('Ignore')); + so.datatype = 'or(ip4addr,"ignore")'; + so.validate = function(section, value) { + var m = this.section.formvalue(section, 'mac'), + n = this.section.formvalue(section, 'name'); + + if ((m && !m.length > 0) && !n) + return _('One of hostname or MAC address must be specified!'); + + if (!value || value == 'ignore') + return true; + + var leases = uci.sections('dhcp', 'host'); + + for (var i = 0; i < leases.length; i++) + if (leases[i]['.name'] != section && leases[i].ip == value) + return _('The IP address %h is already used by another static lease').format(value); + + for (var i = 0; i < pools.length; i++) { + var net_mask = calculateNetwork(value, pools[i].netmask); + + if (net_mask && net_mask[0] == pools[i].network) + return true; + } + + return _('The IP address is outside of any DHCP pool address range'); + }; + + L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { + so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4); + }); + + so = ss.option(form.Value, 'leasetime', + _('Lease time'), + _('Host-specific lease time, e.g. 5m, 3h, 7d.')); + so.rmempty = true; + so.value('5m', _('5m (5 minutes)')); + so.value('3h', _('3h (3 hours)')); + so.value('12h', _('12h (12 hours - default)')); + so.value('7d', _('7d (7 days)')); + so.value('infinite', _('infinite (lease does not expire)')); + + so = ss.option(form.Value, 'duid', + _('DUID'), + _('The DHCPv6-DUID (DHCP unique identifier) of this host.')); + so.datatype = 'and(rangelength(20,36),hexstring)'; + Object.keys(duids).forEach(function(duid) { + so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?')); + }); + + so = ss.option(form.Value, 'hostid', + _('IPv6-Suffix (hex)'), + _('The IPv6 interface identifier (address suffix) as hexadecimal number (max. 16 chars).')); + so.datatype = 'and(rangelength(0,16),hexstring)'; + + so = ss.option(form.DynamicList, 'tag', + _('Tag'), + _('Assign new, freeform tags to this entry.')); + + so = ss.option(form.DynamicList, 'match_tag', + _('Match Tag'), + _('When a host matches an entry then the special tag %s is set. Use %s to match all known hosts.').format('known', 'known') + '

' + + _('Ignore requests from unknown machines using %s.').format('!known') + '

' + + _('If a host matches an entry which cannot be used because it specifies an address on a different subnet, the tag %s is set.').format('known-othernet')); + so.value('known', _('known')); + so.value('!known', _('!known (not known)')); + so.value('known-othernet', _('known-othernet (on different subnet)')); + so.optional = true; + + so = ss.option(form.Value, 'instance', + _('Instance'), + _('Dnsmasq instance to which this DHCP host section is bound. If unspecified, the section is valid for all dnsmasq instances.')); + so.optional = true; + + Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { + var [name, display_str] = generateDnsmasqInstanceEntry(val); + so.value(name, display_str); + }); + + + so = ss.option(form.Flag, 'broadcast', + _('Broadcast'), + _('Force broadcast DHCP response.')); + + so = ss.option(form.Flag, 'dns', + _('Forward/reverse DNS'), + _('Add static forward and reverse DNS entries for this host.')); + + o = s.taboption('leases', CBILeaseStatus, '__status__'); + + if (has_dhcpv6) + o = s.taboption('leases', CBILease6Status, '__status6__'); + + return m.render().then(function(mapEl) { + poll.add(function() { + return callDHCPLeases().then(function(leaseinfo) { + var leases = Array.isArray(leaseinfo.dhcp_leases) ? leaseinfo.dhcp_leases : [], + leases6 = Array.isArray(leaseinfo.dhcp6_leases) ? leaseinfo.dhcp6_leases : []; + + cbi_update_table(mapEl.querySelector('#lease_status_table'), + leases.map(function(lease) { + var exp; + + if (lease.expires === false) + exp = E('em', _('unlimited')); + else if (lease.expires <= 0) + exp = E('em', _('expired')); + else + exp = '%t'.format(lease.expires); + + var hint = lease.macaddr ? hosts[lease.macaddr] : null, + name = hint ? hint.name : null, + host = null; + + if (name && lease.hostname && lease.hostname != name) + host = '%s (%s)'.format(lease.hostname, name); + else if (lease.hostname) + host = lease.hostname; + + return [ + host || '-', + lease.ipaddr, + lease.macaddr, + exp + ]; + }), + E('em', _('There are no active leases'))); + + if (has_dhcpv6) { + cbi_update_table(mapEl.querySelector('#lease6_status_table'), + leases6.map(function(lease) { + var exp; + + if (lease.expires === false) + exp = E('em', _('unlimited')); + else if (lease.expires <= 0) + exp = E('em', _('expired')); + else + exp = '%t'.format(lease.expires); + + var hint = lease.macaddr ? hosts[lease.macaddr] : null, + name = hint ? (hint.name || L.toArray(hint.ipaddrs || hint.ipv4)[0] || L.toArray(hint.ip6addrs || hint.ipv6)[0]) : null, + host = null; + + if (name && lease.hostname && lease.hostname != name && lease.ip6addr != name) + host = '%s (%s)'.format(lease.hostname, name); + else if (lease.hostname) + host = lease.hostname; + else if (name) + host = name; + + return [ + host || '-', + lease.ip6addrs ? lease.ip6addrs.join('
') : lease.ip6addr, + lease.duid, + exp + ]; + }), + E('em', _('There are no active leases'))); + } + }); + }); + + return mapEl; + }); + } +}); diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 9d91cf65f..070d0f3c2 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -10,7 +10,7 @@ PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git PKG_SOURCE_DATE:=2024-09-29 PKG_SOURCE_VERSION:=680bc70f161fde0f167e2ae50c771be4775eb50a -PKG_MIRROR_HASH:=dff0656a68f05779f9563baee8abb55faeeda79dbc24b99c1f4904af5a69821a +PKG_MIRROR_HASH:=bcdb95e40cfceba56a565ad6b6d9f92a122e7230d0f7f950b3d39e4280723cca PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 @@ -318,7 +318,8 @@ endef define KernelPackage/mt7996e $(KernelPackage/mt76-default) TITLE:=MediaTek MT7996E wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core +@DRIVER_11AX_SUPPORT +@KERNEL_RELAY + DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core +@DRIVER_11AX_SUPPORT \ + +@KERNEL_RELAY +@DRIVER_11BE_SUPPORT FILES:= $(PKG_BUILD_DIR)/mt7996/mt7996e.ko AUTOLOAD:=$(call AutoProbe,mt7996e) endef @@ -363,7 +364,7 @@ define KernelPackage/mt7925-common $(KernelPackage/mt76-default) TITLE:=MediaTek MT7925 wireless driver common code HIDDEN:=1 - DEPENDS+=+kmod-mt792x-common +@DRIVER_11AX_SUPPORT +kmod-hwmon-core + DEPENDS+=+kmod-mt792x-common +@DRIVER_11AX_SUPPORT +kmod-hwmon-core +@DRIVER_11BE_SUPPORT FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925-common.ko endef @@ -660,6 +661,7 @@ define KernelPackage/mt7992-firmware/install $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_2i5i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_2i5e.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa.bin \ $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm.bin \ diff --git a/openwrt/patch/mt76/patches/100-api_update.patch b/openwrt/patch/mt76/patches/100-api_update.patch new file mode 100644 index 000000000..8b528f05f --- /dev/null +++ b/openwrt/patch/mt76/patches/100-api_update.patch @@ -0,0 +1,11 @@ +--- a/tx.c ++++ b/tx.c +@@ -350,7 +350,7 @@ mt76_tx(struct mt76_phy *phy, struct iee + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); + + if ((info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || +- (info->control.flags & IEEE80211_TX_CTRL_SCAN_TX)) ++ (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) + head = &wcid->tx_offchannel; + else + head = &wcid->tx_pending; diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index a29c19fd9..4f2fb23b8 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -1257,28 +1257,45 @@ endef $(eval $(call KernelPackage,video-mem2mem)) -define KernelPackage/video-dma + +define KernelPackage/video-dma-contig SUBMENU:=$(VIDEO_MENU) TITLE:=Video DMA support HIDDEN:=1 DEPENDS:=+kmod-video-videobuf2 - KCONFIG:= \ - CONFIG_VIDEOBUF2_DMA_CONTIG \ - CONFIG_VIDEOBUF2_DMA_SG - FILES:= $(LINUX_DIR)/drivers/media/common/videobuf2/videobuf2-dma-*.ko - AUTOLOAD:=$(call AutoLoad,66,videobuf2-dma-contig videobuf2-dma-sg) + KCONFIG:=CONFIG_VIDEOBUF2_DMA_CONTIG + FILES:=$(LINUX_DIR)/drivers/media/common/videobuf2/videobuf2-dma-contig.ko + AUTOLOAD:=$(call AutoLoad,66,videobuf2-dma-contig) + $(call AddDepends/video) +endef + +define KernelPackage/video-dma-contig/description + Video DMA support Contig +endef + + +$(eval $(call KernelPackage,video-dma-contig)) + +define KernelPackage/video-dma-sg + SUBMENU:=$(VIDEO_MENU) + TITLE:=Video DMA support + HIDDEN:=1 + DEPENDS:=+kmod-video-videobuf2 + KCONFIG:=CONFIG_VIDEOBUF2_DMA_SG + FILES:=$(LINUX_DIR)/drivers/media/common/videobuf2/videobuf2-dma-sg.ko + AUTOLOAD:=$(call AutoLoad,66,videobuf2-dma-sg) $(call AddDepends/video) endef -define KernelPackage/video-dma/description - Video DMA support +define KernelPackage/video-dma-sg/description + Video DMA support SG endef -$(eval $(call KernelPackage,video-dma)) +$(eval $(call KernelPackage,video-dma-sg)) define KernelPackage/video-coda TITLE:=i.MX VPU support - DEPENDS:=@(TARGET_imx&&!TARGET_imx_cortexa7) +kmod-video-mem2mem +kmod-video-dma + DEPENDS:=@(TARGET_imx&&!TARGET_imx_cortexa7) +kmod-video-mem2mem +kmod-video-dma-contig KCONFIG:= \ CONFIG_VIDEO_CODA \ CONFIG_VIDEO_IMX_VDOA @@ -1300,7 +1317,7 @@ $(eval $(call KernelPackage,video-coda)) define KernelPackage/video-pxp TITLE:=i.MX PXP support - DEPENDS:=@TARGET_imx +kmod-video-mem2mem +kmod-video-dma + DEPENDS:=@TARGET_imx +kmod-video-mem2mem +kmod-video-dma-contig KCONFIG:= CONFIG_VIDEO_IMX_PXP FILES:= $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/imx-pxp.ko@lt6.1 \ $(LINUX_DIR)/drivers/media/platform/nxp/imx-pxp.ko@ge6.1 @@ -1318,7 +1335,7 @@ $(eval $(call KernelPackage,video-pxp)) define KernelPackage/video-tw686x TITLE:=TW686x support - DEPENDS:=@PCIE_SUPPORT +kmod-video-dma +kmod-sound-core + DEPENDS:=@PCIE_SUPPORT +kmod-video-dma-contig +kmod-video-dma-sg +kmod-sound-core KCONFIG:= CONFIG_VIDEO_TW686X FILES:= $(LINUX_DIR)/drivers/media/pci/tw686x/tw686x.ko AUTOLOAD:=$(call AutoProbe,tw686x) diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.6 b/openwrt/patch/openwrt-6.x/x86/64/config-6.6 index 93e8b77e1..689689ee9 100644 --- a/openwrt/patch/openwrt-6.x/x86/64/config-6.6 +++ b/openwrt/patch/openwrt-6.x/x86/64/config-6.6 @@ -224,7 +224,6 @@ CONFIG_FB_TILEBLITTING=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y CONFIG_FONT_SUPPORT=y -# CONFIG_FORTIFY_SOURCE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set diff --git a/openwrt/patch/packages-patches/jool/Makefile.24 b/openwrt/patch/packages-patches/jool/Makefile.24 new file mode 100644 index 000000000..685239a44 --- /dev/null +++ b/openwrt/patch/packages-patches/jool/Makefile.24 @@ -0,0 +1,150 @@ +# +# Copyright (C) 2016-2017 Dan Luedtke +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=jool +PKG_VERSION:=4.1.13 +PKG_RELEASE:=1 + +PKG_LICENSE:=GPL-2.0-only +PKG_LICENSE_FILES:=COPYING + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/NICMx/Jool.git +PKG_SOURCE_VERSION:=39ca69f8717a83733548bea3b7bfad2a4799572a +PKG_MIRROR_HASH:=f00592d639f34bc6c38e9d012d59a694b159a57ada1b86985cd4df38e4f85d5f + +PKG_BUILD_DIR=$(KERNEL_BUILD_DIR)/$(PKG_SOURCE_SUBDIR) +PKG_BUILD_PARALLEL:=1 +PKG_BUILD_DEPENDS:=!USE_GLIBC:argp-standalone + +PKG_FIXUP:=autoreconf + +MAKE_PATH:=src/usr +CONFIGURE_PATH:=src/usr + +include $(INCLUDE_DIR)/package.mk + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + KERNEL_DIR="$(LINUX_DIR)" \ + ARCH="$(LINUX_KARCH)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + M="$(PKG_BUILD_DIR)/src/mod/common" \ + V="$(V)" \ + CFLAGS_MODULE=$(NOXTABLES) \ + modules + $(MAKE) -C "$(LINUX_DIR)" \ + KBUILD_MODPOST_WARN=1 \ + KERNEL_DIR="$(LINUX_DIR)" \ + ARCH="$(LINUX_KARCH)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + M="$(PKG_BUILD_DIR)/src/mod/nat64" \ + CFLAGS_MODULE=$(NOXTABLES) \ + V="$(V)" \ + modules + $(MAKE) -C "$(LINUX_DIR)" \ + KBUILD_MODPOST_WARN=1 \ + KERNEL_DIR="$(LINUX_DIR)" \ + ARCH="$(LINUX_KARCH)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + M="$(PKG_BUILD_DIR)/src/mod/siit" \ + CFLAGS_MODULE=$(NOXTABLES) \ + V="$(V)" \ + modules + $(call Build/Compile/Default) +endef + +define Build/Configure + (cd $(PKG_BUILD_DIR); ./autogen.sh ); + $(call Build/Configure/Default, --with-xtables=no) +endef + + +define Package/jool/Default + SECTION:=net + CATEGORY:=Network + URL:=https://nicmx.github.io/Jool/ +endef + +define Package/jool/Default/description + Jool is an Open Source SIIT and NAT64 for Linux. +endef + + +define KernelPackage/jool-netfilter + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Support + TITLE:=Jool kernel module + DEPENDS:= \ + @IPV6 \ + +kmod-crypto-md5 \ + +kmod-nf-conntrack \ + +kmod-nf-conntrack6 + FILES:= \ + $(PKG_BUILD_DIR)/src/mod/common/jool_common.$(LINUX_KMOD_SUFFIX) \ + $(PKG_BUILD_DIR)/src/mod/nat64/jool.$(LINUX_KMOD_SUFFIX) \ + $(PKG_BUILD_DIR)/src/mod/siit/jool_siit.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,48,$(JOOL_AUTOLOAD)) +endef + +define KernelPackage/jool-netfilter/description + $(call Package/jool/Default/description) + + This package provides the kernel module for Jool with netfilter API Only. +endef + + +define Package/jool-tools-netfilter + $(call Package/jool/Default) + TITLE:=Jool userspace control programs + DEPENDS:=+libnl +libnl-genl +kmod-jool-netfilter +ethtool +endef + +define Package/jool-tools-netfilter/description + $(call Package/jool/Default/description) + + This package provides the userspace control programs for Jool. +endef + +JOOL_AUTOLOAD:= \ + jool \ + jool_siit + +NOXTABLES:=-DXTABLES_DISABLED + +define Package/jool-tools-netfilter/conffiles +/etc/config/jool +/etc/jool/jool-nat64.conf.json +/etc/jool/jool-siit.conf.json +endef + +define Package/jool-tools-netfilter/install + $(INSTALL_DIR) $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/usr/nat64/jool $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/usr/joold/joold $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/usr/siit/jool_siit $(1)/usr/bin/ + + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/jool.config $(1)/etc/config/jool + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/jool.init $(1)/etc/init.d/jool + + $(INSTALL_DIR) $(1)/etc/hotplug.d/net + $(INSTALL_BIN) ./files/jool-disable-fraglist-gro.sh $(1)/etc/hotplug.d/net/90-jool-disable-fraglist-gro.sh + + $(INSTALL_DIR) $(1)/etc/jool + $(INSTALL_CONF) ./files/jool-nat64.conf.json $(1)/etc/jool/jool-nat64.conf.json + $(INSTALL_CONF) ./files/jool-siit.conf.json $(1)/etc/jool/jool-siit.conf.json + $(INSTALL_DATA) ./files/readme.md $(1)/etc/jool/readme.md +endef + +$(eval $(call KernelPackage,jool-netfilter)) +$(eval $(call BuildPackage,jool-tools-netfilter)) diff --git a/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch b/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch new file mode 100644 index 000000000..bc94690fe --- /dev/null +++ b/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch @@ -0,0 +1,13 @@ +diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c +index 2e5278a..7a3cb09 100644 +--- a/kernel-module/xt_RTPENGINE.c ++++ b/kernel-module/xt_RTPENGINE.c +@@ -4017,7 +4017,7 @@ static int send_proxy_packet4(struct sk_buff *skb, struct re_address *src, struc + if (!net) + goto drop; + +- rt = ip_route_output(net, dst->u.ipv4, src->u.ipv4, tos, 0); ++ rt = ip_route_output(net, dst->u.ipv4, src->u.ipv4, tos, 0, 0); + if (IS_ERR(rt)) + goto drop; + skb_dst_drop(skb); diff --git a/openwrt/patch/pcre/Config.in b/openwrt/patch/pcre/Config.in new file mode 100644 index 000000000..15e75fc75 --- /dev/null +++ b/openwrt/patch/pcre/Config.in @@ -0,0 +1,11 @@ +config PCRE_JIT_ENABLED + bool + depends on PACKAGE_libpcre && (arm || i386 || i686 || x86_64 || mips || mipsel || powerpc || sparc) + default y if (arm || i686 || x86_64) + prompt "Enable JIT compiler support" + help + Enable JIT (Just-In-Time) compiler support. + + Enabling this option can give an about 10x performance increase on JIT operations. It can be desireable for e.g. high performance Apache mod_rewrite or HA-Proxy reqrep operations. + + However, JIT should _only_ be enabled on architectures that are supported. Enabling JIT on unsupported platforms will result in a compilation failure. A list of supported architectures can be found here: https://pcre.org/original/doc/html/pcrejit.html#SEC3 . diff --git a/openwrt/patch/pcre/Makefile b/openwrt/patch/pcre/Makefile new file mode 100644 index 000000000..5309f81d7 --- /dev/null +++ b/openwrt/patch/pcre/Makefile @@ -0,0 +1,129 @@ +# +# Copyright (C) 2006-2015 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=pcre +PKG_VERSION:=8.45 +PKG_RELEASE:=5 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 +PKG_SOURCE_URL:=@SF/$(PKG_NAME) +PKG_HASH:=4dae6fdcd2bb0bb6c37b5f97c33c2be954da743985369cddac3546e3218bffb8 + +PKG_MAINTAINER:=Thomas Heil +PKG_LICENSE:=BSD-3-Clause +PKG_LICENSE_FILES:=LICENCE +PKG_CPE_ID:=cpe:/a:pcre:pcre + +PKG_INSTALL:=1 +PKG_BUILD_PARALLEL:=1 + +PKG_CONFIG_DEPENDS:=\ + CONFIG_PACKAGE_libpcrecpp \ + CONFIG_PCRE_JIT_ENABLED + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/host-build.mk + +define Package/libpcre/default + SECTION:=libs + CATEGORY:=Libraries + URL:=https://www.pcre.org/ +endef + +define Package/libpcre/config + source "$(SOURCE)/Config.in" +endef + +define Package/libpcre + $(call Package/libpcre/default) + TITLE:=A Perl Compatible Regular Expression library +endef + +define Package/libpcre16 + $(call Package/libpcre/default) + TITLE:=A Perl Compatible Regular Expression library (16bit support) +endef + +define Package/libpcre32 + $(call Package/libpcre/default) + TITLE:=A Perl Compatible Regular Expression library (32bit support) +endef + +define Package/libpcrecpp + $(call Package/libpcre/default) + TITLE:=C++ wrapper for Perl Compatible Regular Expression library + DEPENDS:=+libpcre +libstdcpp +endef + +HOST_CONFIGURE_ARGS += \ + --disable-shared \ + --enable-utf8 \ + --enable-unicode-properties \ + --enable-pcre16 \ + --with-match-limit-recursion=16000 \ + --enable-cpp \ + --with-pic + +CONFIGURE_ARGS += \ + --enable-utf8 \ + --enable-unicode-properties \ + --enable-pcre16 \ + --enable-pcre32 \ + $(if $(CONFIG_PCRE_JIT_ENABLED),--enable-jit,--disable-jit) \ + --with-match-limit-recursion=16000 \ + --$(if $(CONFIG_PACKAGE_libpcrecpp),en,dis)able-cpp \ + --with-pic + +MAKE_FLAGS += \ + CFLAGS="$(TARGET_CFLAGS)" + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/pcre-config $(1)/usr/bin/ + $(SED) 's,^\(prefix\|exec_prefix\)=.*,\1=$(STAGING_DIR)/usr,g' $(1)/usr/bin/pcre-config + + $(INSTALL_DIR) $(2)/bin + $(LN) $(STAGING_DIR)/usr/bin/pcre-config $(2)/bin + + $(INSTALL_DIR) $(1)/usr/include + $(CP) $(PKG_INSTALL_DIR)/usr/include/pcre*.h $(1)/usr/include/ + + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcre*.{a,so*} $(1)/usr/lib/ + + $(INSTALL_DIR) $(1)/usr/lib/pkgconfig + $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libpcre*.pc $(1)/usr/lib/pkgconfig/ +endef + +define Package/libpcre/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcre{,posix}.so.* $(1)/usr/lib/ + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcre.so $(1)/usr/lib/ +endef + +define Package/libpcre16/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcre16.so* $(1)/usr/lib/ +endef + +define Package/libpcre32/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcre32.so* $(1)/usr/lib/ +endef + +define Package/libpcrecpp/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcrecpp.so.* $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,libpcre)) +$(eval $(call BuildPackage,libpcre16)) +$(eval $(call BuildPackage,libpcre32)) +$(eval $(call BuildPackage,libpcrecpp)) +$(eval $(call HostBuild)) diff --git a/openwrt/patch/util-linux/util-linux_ntfs3.patch b/openwrt/patch/util-linux/201-util-linux_ntfs3.patch similarity index 66% rename from openwrt/patch/util-linux/util-linux_ntfs3.patch rename to openwrt/patch/util-linux/201-util-linux_ntfs3.patch index 2bfc4be90..04c4ebf81 100644 --- a/openwrt/patch/util-linux/util-linux_ntfs3.patch +++ b/openwrt/patch/util-linux/201-util-linux_ntfs3.patch @@ -1,8 +1,6 @@ -diff --git a/libblkid/src/superblocks/ntfs.c b/libblkid/src/superblocks/ntfs.c -index be2e3d8..3019b10 100644 --- a/libblkid/src/superblocks/ntfs.c +++ b/libblkid/src/superblocks/ntfs.c -@@ -238,7 +238,7 @@ int blkid_probe_is_ntfs(blkid_probe pr) +@@ -248,7 +248,7 @@ int blkid_probe_is_ntfs(blkid_probe pr) const struct blkid_idinfo ntfs_idinfo = { @@ -11,11 +9,9 @@ index be2e3d8..3019b10 100644 .usage = BLKID_USAGE_FILESYSTEM, .probefunc = probe_ntfs, .magics = -diff --git a/libmount/src/utils.c b/libmount/src/utils.c -index 7481505..587e657 100644 --- a/libmount/src/utils.c +++ b/libmount/src/utils.c -@@ -390,7 +390,7 @@ const char *mnt_statfs_get_fstype(struct statfs *vfs) +@@ -436,7 +436,7 @@ const char *mnt_statfs_get_fstype(struct statfs *vfs) case STATFS_NCP_MAGIC: return "ncp"; case STATFS_NFS_MAGIC: return "nfs"; case STATFS_NILFS_MAGIC: return "nilfs2"; diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index c3a86de21..d7295a090 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -1,7 +1,7 @@ #!/bin/bash -e # Rockchip - rkbin & u-boot -rm -rf package/boot/uboot-rockchip package/boot/arm-trusted-firmware-rockchip +rm -rf package/boot/rkbin package/boot/uboot-rockchip package/boot/arm-trusted-firmware-rockchip if [ "$platform" = "rk3568" ]; then git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip @@ -12,44 +12,49 @@ fi ######## OpenWrt Patches ######## +[ "$version" = "rc2" ] && generic=generic || generic=generic-24.10 + # tools: add llvm/clang toolchain -curl -s https://$mirror/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0001-tools-add-llvm-clang-toolchain.patch | patch -p1 # tools: add upx tools -curl -s https://$mirror/openwrt/patch/generic/0002-tools-add-upx-tools.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0002-tools-add-upx-tools.patch | patch -p1 # rootfs: upx compression # include/rootfs.mk -curl -s https://$mirror/openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0003-rootfs-add-upx-compression-support.patch | patch -p1 # rootfs: add r/w (0600) permissions for UCI configuration files # include/rootfs.mk -curl -s https://$mirror/openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 # rootfs: Add support for local kmod installation sources -curl -s https://$mirror/openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 # BTF: fix failed to validate module # config/Config-kernel.in patch -curl -s https://$mirror/openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch | patch -p1 # kernel: Add support for llvm/clang compiler -curl -s https://$mirror/openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 # toolchain: Add libquadmath to the toolchain -curl -s https://$mirror/openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch | patch -p1 # build: kernel: add out-of-tree kernel config -curl -s https://$mirror/openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0009-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 # kernel: linux-6.11 config -curl -s https://$mirror/openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 # meson: add platform variable to cross-compilation file -curl -s https://$mirror/openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/$generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 + +# bpf-headers-6.12 +#[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/$generic/900-bpf-headers-6.12rc.patch | patch -p1 # mold -if [ "$ENABLE_MOLD" = "y" ]; then +if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then curl -s https://$mirror/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 curl -s https://$mirror/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch | patch -p1 curl -s https://$mirror/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch | patch -p1 @@ -57,16 +62,26 @@ if [ "$ENABLE_MOLD" = "y" ]; then curl -s https://$mirror/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch | patch -p1 curl -s https://$mirror/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch | patch -p1 curl -s https://$mirror/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.0.patch | patch -p1 - # no-mold - sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile + curl -s https://$mirror/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch | patch -p1 fi +[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch | patch -p1 + +# attr no-mold +[ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile ######## OpenWrt Patches End ######## # dwarves: Fix a dwarf type DW_ATE_unsigned_1024 to btf encoding issue -mkdir -p tools/dwarves/patches -curl -s https://$mirror/openwrt/patch/openwrt-6.x/dwarves/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch > tools/dwarves/patches/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch +if [ "$version" = "rc2" ]; then + mkdir -p tools/dwarves/patches + curl -s https://$mirror/openwrt/patch/openwrt-6.x/dwarves/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch > tools/dwarves/patches/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch +fi + +# dwarves 1.25 +if [ "$version" = "snapshots-24.10" ]; then + rm -rf tools/dwarves + git clone https://$github/sbwml/tools_dwarves tools/dwarves +fi # x86 - disable intel_pstate & mitigations sed -i 's/noinitrd/noinitrd intel_pstate=disable mitigations=off/g' target/linux/x86/image/grub-efi.cfg @@ -81,7 +96,7 @@ if [ "$ENABLE_UHTTPD" != "y" ]; then sed -i 's/+uhttpd /+luci-nginx /g' feeds/luci/collections/luci-light/Makefile sed -i "s/+luci /+luci-nginx /g" feeds/luci/collections/luci-ssl-openssl/Makefile sed -i "s/+luci /+luci-nginx /g" feeds/luci/collections/luci-ssl/Makefile - if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then + if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then sed -i 's/+uhttpd +uhttpd-mod-ubus /+luci-nginx /g' feeds/packages/net/wg-installer/Makefile sed -i '/uhttpd-mod-ubus/d' feeds/luci/collections/luci-light/Makefile sed -i 's/+luci-nginx \\$/+luci-nginx/' feeds/luci/collections/luci-light/Makefile @@ -120,8 +135,8 @@ if [ "$ENABLE_GLIBC" = "y" ]; then # musl-libc git clone https://$gitea/sbwml/package_libs_musl-libc package/libs/musl-libc # bump fstools version - rm -rf package/system/fstools - cp -a ../master/openwrt/package/system/fstools package/system/fstools + [ "$version" = "rc2" ] && rm -rf package/system/fstools + [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/system/fstools package/system/fstools # glibc-common curl -s https://$mirror/openwrt/patch/glibc/glibc-common.patch | patch -p1 # glibc-common - locale data @@ -136,40 +151,45 @@ if [ "$ENABLE_GLIBC" = "y" ]; then fi # Mbedtls AES & GCM Crypto Extensions -if [ ! "$platform" = "x86_64" ]; then +if [ ! "$platform" = "x86_64" ] && [ "$version" = "rc2" ]; then curl -s https://$mirror/openwrt/patch/mbedtls-23.05/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch > package/libs/mbedtls/patches/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch curl -s https://$mirror/openwrt/patch/mbedtls-23.05/mbedtls.patch | patch -p1 fi -# NTFS3 -mkdir -p package/system/fstools/patches -curl -s https://$mirror/openwrt/patch/fstools/ntfs3.patch > package/system/fstools/patches/ntfs3.patch -curl -s https://$mirror/openwrt/patch/util-linux/util-linux_ntfs3.patch > package/utils/util-linux/patches/util-linux_ntfs3.patch - -# fstools - enable any device with non-MTD rootfs_data volume -sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/system/fstools/Makefile -curl -s https://$mirror/openwrt/patch/fstools/block-mount-add-fstools-depends.patch | patch -p1 -if [ "$ENABLE_GLIBC" = "y" ]; then - curl -s https://$mirror/openwrt/patch/fstools/fstools-set-ntfs3-utf8-new.patch > package/system/fstools/patches/ntfs3-utf8.patch - curl -s https://$mirror/openwrt/patch/fstools/glibc/0001-libblkid-tiny-add-support-for-XFS-superblock.patch > package/system/fstools/patches/0001-libblkid-tiny-add-support-for-XFS-superblock.patch - curl -s https://$mirror/openwrt/patch/fstools/glibc/0003-block-add-xfsck-support.patch > package/system/fstools/patches/0003-block-add-xfsck-support.patch -else - curl -s https://$mirror/openwrt/patch/fstools/fstools-set-ntfs3-utf8-new.patch > package/system/fstools/patches/ntfs3-utf8.patch -fi -if [ "$ENABLE_GLIBC" = "y" ]; then - curl -s https://$mirror/openwrt/patch/fstools/22-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch > package/system/fstools/patches/22-fstools-support-extroot-for-non-MTD-rootfs_data.patch +if [ "$version" = "rc2" ]; then + # util-linux - ntfs3 + mkdir -p package/utils/util-linux/patches + curl -s https://$mirror/openwrt/patch/util-linux/201-util-linux_ntfs3.patch > package/utils/util-linux/patches/201-util-linux_ntfs3.patch + # fstools - enable any device with non-MTD rootfs_data volume + curl -s https://$mirror/openwrt/patch/fstools/Makefile > package/system/fstools/Makefile + sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/system/fstools/Makefile + mkdir -p package/system/fstools/patches + curl -s https://$mirror/openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch > package/system/fstools/patches/200-use-ntfs3-instead-of-ntfs.patch + curl -s https://$mirror/openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch > package/system/fstools/patches/201-fstools-set-ntfs3-utf8.patch + if [ "$ENABLE_GLIBC" = "y" ]; then + curl -s https://$mirror/openwrt/patch/fstools/glibc/0001-libblkid-tiny-add-support-for-XFS-superblock.patch > package/system/fstools/patches/0001-libblkid-tiny-add-support-for-XFS-superblock.patch + curl -s https://$mirror/openwrt/patch/fstools/glibc/0003-block-add-xfsck-support.patch > package/system/fstools/patches/0003-block-add-xfsck-support.patch + curl -s https://$mirror/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch > package/system/fstools/patches/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch + else + curl -s https://$mirror/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch > package/system/fstools/patches/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch + fi else - curl -s https://$mirror/openwrt/patch/fstools/22-fstools-support-extroot-for-non-MTD-rootfs_data.patch > package/system/fstools/patches/22-fstools-support-extroot-for-non-MTD-rootfs_data.patch + # fstools + rm -rf package/system/fstools + git clone https://$github/sbwml/package_system_fstools -b openwrt-24.10 package/system/fstools + # util-linux + rm -rf package/utils/util-linux + git clone https://$github/sbwml/package_utils_util-linux -b openwrt-24.10 package/utils/util-linux fi # Shortcut Forwarding Engine git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe # Patch FireWall 4 -if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then +if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then # firewall4 - master - rm -rf package/network/config/firewall4 - cp -a ../master/openwrt/package/network/config/firewall4 package/network/config/firewall4 + [ "$version" = "rc2" ] && rm -rf package/network/config/firewall4 + [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/network/config/firewall4 package/network/config/firewall4 sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/network/config/firewall4/Makefile mkdir -p package/network/config/firewall4/patches # fix ct status dnat @@ -185,15 +205,15 @@ if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then # add custom nft command support curl -s https://$mirror/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch | patch -p1 # libnftnl - rm -rf package/libs/libnftnl - cp -a ../master/openwrt/package/libs/libnftnl package/libs/libnftnl + [ "$version" = "rc2" ] && rm -rf package/libs/libnftnl + [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/libs/libnftnl package/libs/libnftnl mkdir -p package/libs/libnftnl/patches curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/001-libnftnl-add-fullcone-expression-support.patch [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch sed -i '/PKG_INSTALL:=1/iPKG_FIXUP:=autoreconf' package/libs/libnftnl/Makefile # nftables - rm -rf package/network/utils/nftables - cp -a ../master/openwrt/package/network/utils/nftables package/network/utils/nftables + [ "$version" = "rc2" ] && rm -rf package/network/utils/nftables + [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/network/utils/nftables package/network/utils/nftables mkdir -p package/network/utils/nftables/patches curl -s https://$mirror/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/002-nftables-add-fullcone-expression-support.patch [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch @@ -304,13 +324,16 @@ git clone https://$github/sbwml/feeds_packages_net_curl feeds/packages/net/curl # Docker rm -rf feeds/luci/applications/luci-app-dockerman git clone https://$gitea/sbwml/luci-app-dockerman -b openwrt-23.05 feeds/luci/applications/luci-app-dockerman -if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then - rm -rf feeds/packages/utils/{docker,dockerd,docker-compose,containerd,runc} +if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then + rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} git clone https://$github/sbwml/packages_utils_docker feeds/packages/utils/docker git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd git clone https://$github/sbwml/packages_utils_containerd feeds/packages/utils/containerd git clone https://$github/sbwml/packages_utils_runc feeds/packages/utils/runc - cp -a ../master/packages/utils/docker-compose feeds/packages/utils/docker-compose + [ "$version" = "rc2" ] && { + rm -rf feeds/packages/utils/docker-compose + cp -a ../master/packages/utils/docker-compose feeds/packages/utils/docker-compose + } fi sed -i '/sysctl.d/d' feeds/packages/utils/dockerd/Makefile pushd feeds/packages @@ -355,34 +378,38 @@ popd sed -i 's/services/network/g' feeds/luci/applications/luci-app-upnp/root/usr/share/luci/menu.d/luci-app-upnp.json # nginx-util - fix gcc13 -pushd feeds/packages - curl -s https://$mirror/openwrt/nginx/nginx-util/0001-nginx-util-fix-compilation-with-GCC13.patch | patch -p1 - curl -s https://$mirror/openwrt/nginx/nginx-util/0002-nginx-util-move-to-pcre2.patch | patch -p1 -popd +if [ "$version" = "rc2" ]; then + pushd feeds/packages + curl -s https://$mirror/openwrt/nginx/nginx-util/0001-nginx-util-fix-compilation-with-GCC13.patch | patch -p1 + curl -s https://$mirror/openwrt/nginx/nginx-util/0002-nginx-util-move-to-pcre2.patch | patch -p1 + popd +fi # nginx - latest version rm -rf feeds/packages/net/nginx -git clone https://$github/sbwml/feeds_packages_net_nginx feeds/packages/net/nginx -b quic+zstd +git clone https://$github/sbwml/feeds_packages_net_nginx feeds/packages/net/nginx -b "$openwrt_version" sed -i 's/procd_set_param stdout 1/procd_set_param stdout 0/g;s/procd_set_param stderr 1/procd_set_param stderr 0/g' feeds/packages/net/nginx/files/nginx.init # nginx - ubus sed -i 's/ubus_parallel_req 2/ubus_parallel_req 6/g' feeds/packages/net/nginx/files-luci-support/60_nginx-luci-support -sed -i '/ubus_parallel_req/a\ ubus_script_timeout 600;' feeds/packages/net/nginx/files-luci-support/60_nginx-luci-support +sed -i '/ubus_parallel_req/a\ ubus_script_timeout 300;' feeds/packages/net/nginx/files-luci-support/60_nginx-luci-support # nginx - uwsgi timeout & enable brotli curl -s https://$mirror/openwrt/nginx/luci.locations > feeds/packages/net/nginx/files-luci-support/luci.locations -curl -s https://$mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template +curl -s https://$mirror/openwrt/nginx/${openwrt_version}-uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template # zstd - bump version -rm -rf feeds/packages/utils/zstd -cp -a ../master/packages/utils/zstd feeds/packages/utils/zstd +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/utils/zstd + cp -a ../master/packages/utils/zstd feeds/packages/utils/zstd +fi # opkg mkdir -p package/system/opkg/patches curl -s https://$mirror/openwrt/patch/opkg/900-opkg-download-disable-hsts.patch > package/system/opkg/patches/900-opkg-download-disable-hsts.patch # uwsgi - bump version -if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then +if [ "$version" = "rc2" ]; then rm -rf feeds/packages/net/uwsgi cp -a ../master/packages/net/uwsgi feeds/packages/net/uwsgi fi @@ -418,7 +445,7 @@ sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/l rm -f feeds/luci/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/29_ports.js # luci - rollback dhcp.js -curl -s https://$mirror/openwrt/patch/luci/dhcp/dhcp.js > feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js +curl -s https://$mirror/openwrt/patch/luci/dhcp/${openwrt_version}-dhcp.js > feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js # luci - disable wireless WPA3 [ "$platform" = "bcm53xx" ] && sed -i -e '/if (has_ap_sae || has_sta_sae) {/{N;N;N;N;d;}' feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js @@ -428,11 +455,13 @@ rm -rf package/network/services/ppp git clone https://$github/sbwml/package_network_services_ppp package/network/services/ppp # odhcpd RFC-9096 -mkdir -p package/network/services/odhcpd/patches -curl -s https://$mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch -pushd feeds/luci - curl -s https://$mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 -popd +if [ "$version" = "rc2" ]; then + mkdir -p package/network/services/odhcpd/patches + curl -s https://$mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch + pushd feeds/luci + curl -s https://$mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 + popd +fi # urngd - 2020-01-21 rm -rf package/system/urngd diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index c5eca34ef..828476757 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -3,7 +3,11 @@ ################################################################# # autocore -git clone https://$github/sbwml/autocore-arm -b openwrt-23.05 package/system/autocore +if [ "$version" = "rc2" ]; then + git clone https://$github/sbwml/autocore-arm -b openwrt-23.05 package/system/autocore +else + git clone https://$github/sbwml/autocore-arm -b openwrt-24.10 package/system/autocore +fi # rockchip - target - r4s/r5s only rm -rf target/linux/rockchip @@ -171,23 +175,32 @@ rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/mt76/patches/100-api_update.patch > package/kernel/mt76/patches/100-api_update.patch # iwinfo: add mt7922 device id -mkdir -p package/network/utils/iwinfo/patches -curl -s https://$mirror/openwrt/patch/openwrt-6.x/iwinfo/0001-devices-add-MediaTek-MT7922-device-id.patch > package/network/utils/iwinfo/patches/0001-devices-add-MediaTek-MT7922-device-id.patch +if [ "$version" = "rc2" ]; then + mkdir -p package/network/utils/iwinfo/patches + curl -s https://$mirror/openwrt/patch/openwrt-6.x/iwinfo/0001-devices-add-MediaTek-MT7922-device-id.patch > package/network/utils/iwinfo/patches/0001-devices-add-MediaTek-MT7922-device-id.patch +fi # iwinfo: add rtl8812/14/21au devices -curl -s https://$mirror/openwrt/patch/openwrt-6.x/iwinfo/0004-add-rtl8812au-devices.patch > package/network/utils/iwinfo/patches/0004-add-rtl8812au-devices.patch +[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/iwinfo/0004-add-rtl8812au-devices.patch > package/network/utils/iwinfo/patches/0004-add-rtl8812au-devices.patch # wireless-regdb -rm -rf package/firmware/wireless-regdb -cp -a ../master/openwrt/package/firmware/wireless-regdb package/firmware/wireless-regdb +if [ "$version" = "rc2" ]; then + rm -rf package/firmware/wireless-regdb + cp -a ../master/openwrt/package/firmware/wireless-regdb package/firmware/wireless-regdb +fi curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch # mac80211 - fix linux 6.6 & add rtw89 rm -rf package/kernel/mac80211 -git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 -[ "$TESTING_KERNEL" = "y" ] && rm -f package/kernel/mac80211/patches/build/140-trace_backport.patch +if [ "$version" = "rc2" ]; then + git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 + [ "$TESTING_KERNEL" = "y" ] && rm -f package/kernel/mac80211/patches/build/140-trace_backport.patch +else + git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 +fi # ath10k-ct rm -rf package/kernel/ath10k-ct @@ -209,7 +222,7 @@ curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/952-net-conntra curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-$kernel_version/601-netfilter-export-udp_get_timeouts-function.patch curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-$kernel_version/953-net-patch-linux-kernel-to-support-shortcut-fe.patch # backport - 6.8 fast-path-variables -if [ "$platform" != "bcm53xx" ] && [ "$TESTING_KERNEL" != "y" ]; then +if [ "$version" = "rc2" ] && [ "$platform" != "bcm53xx" ] && [ "$TESTING_KERNEL" != "y" ]; then curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch > target/linux/generic/backport-6.6/901-v6.8-cache-enforce-cache-groups.patch curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch > target/linux/generic/backport-6.6/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch > target/linux/generic/backport-6.6/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch @@ -218,8 +231,10 @@ if [ "$platform" != "bcm53xx" ] && [ "$TESTING_KERNEL" != "y" ]; then fi # ubnt-ledbar - fix linux-6.x -rm -rf package/kernel/ubnt-ledbar -cp -a ../master/openwrt/package/kernel/ubnt-ledbar package/kernel/ubnt-ledbar +if [ "$version" = "rc2" ]; then + rm -rf package/kernel/ubnt-ledbar + cp -a ../master/openwrt/package/kernel/ubnt-ledbar package/kernel/ubnt-ledbar +fi # RTC if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ]; then diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 1849c4089..36701dce4 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -8,7 +8,7 @@ git clone https://$github/sbwml/packages_lang_golang -b 23.x feeds/packages/lang rm -rf feeds/packages/lang/node git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages/lang/node -# Default settings +# default settings git clone https://$github/sbwml/default-settings package/new/default-settings # ddns - fix boot @@ -18,16 +18,27 @@ sed -i '/boot()/,+2d' feeds/packages/net/ddns-scripts/files/etc/init.d/ddns sed -i 's/stderr 1/stderr 0/g' feeds/packages/net/nlbwmon/files/nlbwmon.init # boost - bump version -rm -rf feeds/packages/libs/boost -cp -a ../master/packages/libs/boost feeds/packages/libs/boost +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/libs/boost + cp -a ../master/packages/libs/boost feeds/packages/libs/boost +fi + +# pcre - 8.45 +if [ "$version" = "snapshots-24.10" ]; then + mkdir -p package/libs/pcre + curl -s https://$mirror/openwrt/patch/pcre/Makefile > package/libs/pcre/Makefile + curl -s https://$mirror/openwrt/patch/pcre/Config.in > package/libs/pcre/Config.in +fi # lrzsz - 0.12.20 rm -rf feeds/packages/utils/lrzsz git clone https://$github/sbwml/packages_utils_lrzsz package/new/lrzsz # irqbalance - openwrt master -rm -rf feeds/packages/utils/irqbalance -cp -a ../master/packages/utils/irqbalance feeds/packages/utils/irqbalance +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/utils/irqbalance + cp -a ../master/packages/utils/irqbalance feeds/packages/utils/irqbalance +fi # irqbalance: disable build with numa if [ "$ENABLE_DPDK" = "y" ]; then curl -s https://$mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch @@ -35,8 +46,10 @@ if [ "$ENABLE_DPDK" = "y" ]; then fi # frpc -rm -rf feeds/packages/net/frp -cp -a ../master/packages/net/frp feeds/packages/net/frp +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/net/frp + cp -a ../master/packages/net/frp feeds/packages/net/frp +fi sed -i 's/procd_set_param stdout $stdout/procd_set_param stdout 0/g' feeds/packages/net/frp/files/frpc.init sed -i 's/procd_set_param stderr $stderr/procd_set_param stderr 0/g' feeds/packages/net/frp/files/frpc.init sed -i 's/stdout stderr //g' feeds/packages/net/frp/files/frpc.init @@ -46,8 +59,8 @@ sed -i 's/env conf_inc/env conf_inc enable/g' feeds/packages/net/frp/files/frpc. sed -i "s/'conf_inc:list(string)'/& \\\\/" feeds/packages/net/frp/files/frpc.init sed -i "/conf_inc:list/a\\\t\t\'enable:bool:0\'" feeds/packages/net/frp/files/frpc.init sed -i '/procd_open_instance/i\\t\[ "$enable" -ne 1 \] \&\& return 1\n' feeds/packages/net/frp/files/frpc.init -curl -s https://$mirror/openwrt/patch/luci/applications/001-luci-app-frpc-hide-token.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/luci/applications/002-luci-app-frpc-add-enable-flag.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-${openwrt_version}.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-${openwrt_version}.patch | patch -p1 # samba4 - bump version rm -rf feeds/packages/net/samba4 @@ -92,11 +105,14 @@ rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 # alist +rm -rf feeds/packages/net/alist feeds/luci/applications/luci-app-alist git clone https://$github/sbwml/openwrt-alist package/new/alist # netdata -rm -rf feeds/packages/admin/netdata -cp -a ../master/packages/admin/netdata feeds/packages/admin/netdata +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/admin/netdata + cp -a ../master/packages/admin/netdata feeds/packages/admin/netdata +fi sed -i 's/syslog/none/g' feeds/packages/admin/netdata/files/netdata.conf # qBittorrent @@ -116,8 +132,10 @@ git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns git clone https://$github/sbwml/OpenAppFilter --depth=1 package/new/OpenAppFilter # iperf3 -rm -rf feeds/packages/net/iperf3 -cp -a ../master/packages/net/iperf3 feeds/packages/net/iperf3 +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/net/iperf3 + cp -a ../master/packages/net/iperf3 feeds/packages/net/iperf3 +fi sed -i "s/D_GNU_SOURCE/D_GNU_SOURCE -funroll-loops/g" feeds/packages/net/iperf3/Makefile # nlbwmon @@ -128,7 +146,7 @@ sed -i 's/services/network/g' feeds/luci/applications/luci-app-nlbwmon/htdocs/lu git clone https://github.com/sbwml/luci-app-mentohust package/new/mentohust # custom packages -rm -rf feeds/packages/utils/coremark +rm -rf feeds/packages/utils/coremark feeds/luci/applications/luci-app-filebrowser git clone https://$github/sbwml/openwrt_pkgs package/new/custom --depth=1 # coremark - prebuilt with gcc15 if [ "$platform" = "rk3568" ]; then diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index 205e77404..e1c73e8a4 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -3,12 +3,14 @@ # Fix build for linux-6.6/6.12 # cryptodev-linux -mkdir -p package/kernel/cryptodev-linux/patches -curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/001-Fix-build-for-Linux-6.3-rc1.patch > package/kernel/cryptodev-linux/patches/001-Fix-build-for-Linux-6.3-rc1.patch -curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch > package/kernel/cryptodev-linux/patches/002-fix-build-for-linux-6.7-rc1.patch +if [ "$version" = "rc2" ]; then + mkdir -p package/kernel/cryptodev-linux/patches + curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/001-Fix-build-for-Linux-6.3-rc1.patch > package/kernel/cryptodev-linux/patches/001-Fix-build-for-Linux-6.3-rc1.patch + curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch > package/kernel/cryptodev-linux/patches/002-fix-build-for-linux-6.7-rc1.patch +fi # gpio-button-hotplug -curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch | patch -p1 +[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch | patch -p1 curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 # gpio-nct5104d @@ -16,26 +18,36 @@ curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-f curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch | patch -p1 # dmx_usb_module -mkdir -p feeds/packages/libs/dmx_usb_module/patches -curl -s https://$mirror/openwrt/patch/packages-patches/dmx_usb_module/900-fix-linux-6.6.patch > feeds/packages/libs/dmx_usb_module/patches/900-fix-linux-6.6.patch +if [ "$version" = "rc2" ]; then + mkdir -p feeds/packages/libs/dmx_usb_module/patches + curl -s https://$mirror/openwrt/patch/packages-patches/dmx_usb_module/900-fix-linux-6.6.patch > feeds/packages/libs/dmx_usb_module/patches/900-fix-linux-6.6.patch +fi # jool -curl -s https://$mirror/openwrt/patch/packages-patches/jool/Makefile > feeds/packages/net/jool/Makefile +[ "$version" = "rc2" ] && \ + curl -s https://$mirror/openwrt/patch/packages-patches/jool/Makefile > feeds/packages/net/jool/Makefile || \ + curl -s https://$mirror/openwrt/patch/packages-patches/jool/Makefile.24 > feeds/packages/net/jool/Makefile # mdio-netlink -mkdir -p feeds/packages/kernel/mdio-netlink/patches -curl -s https://$mirror/openwrt/patch/packages-patches/mdio-netlink/001-mdio-netlink-rework-C45-to-work-with-net-next.patch > feeds/packages/kernel/mdio-netlink/patches/001-mdio-netlink-rework-C45-to-work-with-net-next.patch +if [ "$version" = "rc2" ]; then + mkdir -p feeds/packages/kernel/mdio-netlink/patches + curl -s https://$mirror/openwrt/patch/packages-patches/mdio-netlink/001-mdio-netlink-rework-C45-to-work-with-net-next.patch > feeds/packages/kernel/mdio-netlink/patches/001-mdio-netlink-rework-C45-to-work-with-net-next.patch +fi # ovpn-dco mkdir -p feeds/packages/kernel/ovpn-dco/patches -curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch > feeds/packages/kernel/ovpn-dco/patches/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch -curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch > feeds/packages/kernel/ovpn-dco/patches/900-fix-linux-6.6.patch +if [ "$version" = "rc2" ]; then + curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch > feeds/packages/kernel/ovpn-dco/patches/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch + curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch > feeds/packages/kernel/ovpn-dco/patches/900-fix-linux-6.6.patch +fi curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch > feeds/packages/kernel/ovpn-dco/patches/901-fix-linux-6.11.patch curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch > feeds/packages/kernel/ovpn-dco/patches/902-fix-linux-6.12.patch # siit -rm -rf feeds/packages/net/siit -cp -a ../master/packages/net/siit feeds/packages/net/siit +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/net/siit + cp -a ../master/packages/net/siit feeds/packages/net/siit +fi # libpfring rm -rf feeds/packages/libs/libpfring @@ -53,14 +65,21 @@ curl -s https://$mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with- curl -s https://$mirror/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch > package/kernel/nat46/patches/101-fix-build-with-kernel-6.12.patch # v4l2loopback - 6.12 -mkdir -p feeds/packages/kernel/v4l2loopback/patches -curl -s https://$mirror/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch > feeds/packages/kernel/v4l2loopback/patches/100-fix-build-with-linux-6.12.patch +if [ "$version" = "rc2" ]; then + mkdir -p feeds/packages/kernel/v4l2loopback/patches + curl -s https://$mirror/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch > feeds/packages/kernel/v4l2loopback/patches/100-fix-build-with-linux-6.12.patch +fi # openvswitch if [ "$TESTING_KERNEL" = "y" ]; then sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile fi +# rtpengine +if [ "$TESTING_KERNEL" = "y" ] && [ "$version" = "snapshots-24.10" ]; then + curl -s https://$mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch +fi + # ubootenv-nvram - 6.12 (openwrt-23.05.5) mkdir -p package/kernel/ubootenv-nvram/patches curl -s https://$mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.12.patch @@ -68,17 +87,19 @@ curl -s https://$mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-u # packages pushd feeds/packages # xr_usb_serial_common - curl -s https://github.com/openwrt/packages/commit/23a3ea2d6b3779cd48d318b95a3c72cad9433d50.patch | patch -p1 + [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/23a3ea2d6b3779cd48d318b95a3c72cad9433d50.patch | patch -p1 # fix linux-6.6 - curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch > libs/xr_usb_serial_common/patches/900-fix-linux-6.6.patch + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch > libs/xr_usb_serial_common/patches/900-fix-linux-6.6.patch # coova-chilli - curl -s https://github.com/openwrt/packages/commit/9975e855adcfc24939080a5e0279e0a90553347b.patch | patch -p1 - curl -s https://github.com/openwrt/packages/commit/c0683d3f012096fc7b2fbe8b8dc81ea424945e9b.patch | patch -p1 + [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/9975e855adcfc24939080a5e0279e0a90553347b.patch | patch -p1 + [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/c0683d3f012096fc7b2fbe8b8dc81ea424945e9b.patch | patch -p1 popd # xtables-addons -rm -rf feeds/packages/net/xtables-addons -cp -a ../master/packages/net/xtables-addons feeds/packages/net/xtables-addons +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/net/xtables-addons + cp -a ../master/packages/net/xtables-addons feeds/packages/net/xtables-addons +fi curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch # telephony @@ -89,8 +110,10 @@ pushd feeds/telephony popd # routing - batman-adv -rm -rf feeds/routing/batman-adv -cp -a ../master/routing/batman-adv feeds/routing/batman-adv +if [ "$version" = "rc2" ]; then + rm -rf feeds/routing/batman-adv + cp -a ../master/routing/batman-adv feeds/routing/batman-adv +fi # fix build with linux-6.12 curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch > feeds/routing/batman-adv/patches/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 52c083534..a32de4eef 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -6,15 +6,27 @@ sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/l # grub2 - disable `gc-sections` flag sed -i '/PKG_BUILD_FLAGS/ s/$/ no-gc-sections/' package/boot/grub2/Makefile +# mbedtls +[ "$version" = "snapshots-24.10" ] && sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile + +# haproxy - fix build with quictls +[ "$version" = "snapshots-24.10" ] && sed -i '/USE_QUIC_OPENSSL_COMPAT/d' feeds/packages/net/haproxy/Makefile + +# xdp-tools +rm -rf package/network/utils/xdp-tools +git clone https://$github/sbwml/package_network_utils_xdp-tools package/network/utils/xdp-tools -b openwrt-23.05 + # fix gcc13 if [ "$USE_GCC13" = "y" ] || [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then - # libwebsockets - mkdir feeds/packages/libs/libwebsockets/patches - pushd feeds/packages/libs/libwebsockets/patches - curl -sLO https://raw.githubusercontent.com/openwrt/packages/bcd970fb4ff6029fbf612dccf6d8c2902a65e20e/libs/libwebsockets/patches/010-fix-enum-int-mismatch-openssl.patch - curl -sLO https://raw.githubusercontent.com/openwrt/packages/bcd970fb4ff6029fbf612dccf6d8c2902a65e20e/libs/libwebsockets/patches/011-fix-enum-int-mismatch-mbedtls.patch - curl -sLO https://raw.githubusercontent.com/openwrt/packages/94bd1ca8bad053a772a3ea8cb06ce59241fb9a57/libs/libwebsockets/patches/100-fix-uninitialized-variable-usage.patch - popd + if [ "$version" = "rc2" ]; then + # libwebsockets + mkdir -p feeds/packages/libs/libwebsockets/patches + pushd feeds/packages/libs/libwebsockets/patches + curl -sLO https://raw.githubusercontent.com/openwrt/packages/bcd970fb4ff6029fbf612dccf6d8c2902a65e20e/libs/libwebsockets/patches/010-fix-enum-int-mismatch-openssl.patch + curl -sLO https://raw.githubusercontent.com/openwrt/packages/bcd970fb4ff6029fbf612dccf6d8c2902a65e20e/libs/libwebsockets/patches/011-fix-enum-int-mismatch-mbedtls.patch + curl -sLO https://raw.githubusercontent.com/openwrt/packages/94bd1ca8bad053a772a3ea8cb06ce59241fb9a57/libs/libwebsockets/patches/100-fix-uninitialized-variable-usage.patch + popd + fi fi # fix gcc14 @@ -24,32 +36,32 @@ if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then git clone https://$github/sbwml/package_network_utils_iproute2 package/network/utils/iproute2 # wsdd2 if [ "$ENABLE_GLIBC" != "y" ]; then - mkdir -p feeds/packages/net/wsdd2/patches - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/wsdd2/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch > feeds/packages/net/wsdd2/patches/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch + [ "$version" = "rc2" ] && mkdir -p feeds/packages/net/wsdd2/patches + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/wsdd2/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch > feeds/packages/net/wsdd2/patches/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch fi # libunwind rm -rf package/libs/libunwind git clone https://$github/sbwml/package_libs_libunwind package/libs/libunwind # mbedtls - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch > package/libs/mbedtls/patches/900-tests-fix-calloc-argument-list-gcc-14-fix.patch + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch > package/libs/mbedtls/patches/900-tests-fix-calloc-argument-list-gcc-14-fix.patch # linux-atm rm -rf package/network/utils/linux-atm git clone https://$github/sbwml/package_network_utils_linux-atm package/network/utils/linux-atm # lsof - rm -rf feeds/packages/utils/lsof - cp -a ../master/packages/utils/lsof feeds/packages/utils/lsof + if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/utils/lsof + cp -a ../master/packages/utils/lsof feeds/packages/utils/lsof + fi # screen SCREEN_VERSION=4.9.1 SCREEN_HASH=26cef3e3c42571c0d484ad6faf110c5c15091fbf872b06fa7aa4766c7405ac69 sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$SCREEN_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$SCREEN_HASH/" feeds/packages/utils/screen/Makefile rm -rf feeds/packages/utils/screen/patches && mkdir -p feeds/packages/utils/screen/patches curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/screen/900-fix-implicit-function-declaration.patch > feeds/packages/utils/screen/patches/900-fix-implicit-function-declaration.patch - # xdp-tools - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/xdp-tools/900-Fix-transposed-calloc-arguments.patch > package/network/utils/xdp-tools/patches/900-Fix-transposed-calloc-arguments.patch # perl - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/perl/1000-fix-implicit-declaration-error.patch > feeds/packages/lang/perl/patches/1000-fix-implicit-declaration-error.patch + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/perl/1000-fix-implicit-declaration-error.patch > feeds/packages/lang/perl/patches/1000-fix-implicit-declaration-error.patch # grub2 - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/grub2/900-fix-incompatible-pointer-type.patch > package/boot/grub2/patches/900-fix-incompatible-pointer-type.patch + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/grub2/900-fix-incompatible-pointer-type.patch > package/boot/grub2/patches/900-fix-incompatible-pointer-type.patch # glibc # Added the compiler flag -Wno-implicit-function-declaration to suppress # warnings about implicit function declarations during the build process. @@ -74,7 +86,7 @@ if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then sed -i 's/libxcrypt/openssl/g' feeds/packages/utils/shadow/Makefile fi # openssh - 9.8p1 - if [ "$version" = "snapshots-23.05" ] || [ "$version" = "rc2" ]; then + if [ "$version" = "rc2" ]; then rm -rf feeds/packages/net/openssh cp -a ../master/packages/net/openssh feeds/packages/net/openssh fi @@ -87,24 +99,25 @@ if [ "$USE_GCC15" = y ]; then # elfutils curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch # libwebsockets + mkdir -p feeds/packages/libs/libwebsockets/patches curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libwebsockets/patches/901-fix-string-initialization-error-on-gcc15.patch # libxcrypt mkdir -p feeds/packages/libs/libxcrypt/patches curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libxcrypt/patches/901-fix-string-initialization-error-on-gcc15.patch fi -# xdp-tools -[ "$platform" != "x86_64" ] && sed -i '/TARGET_LDFLAGS +=/iTARGET_CFLAGS += -Wno-error=maybe-uninitialized -ffat-lto-objects\n' package/network/utils/xdp-tools/Makefile -[ "$platform" = "x86_64" ] && sed -i '/TARGET_LDFLAGS +=/iTARGET_CFLAGS += -ffat-lto-objects\n' package/network/utils/xdp-tools/Makefile - # ksmbd luci -rm -rf feeds/luci/applications/luci-app-ksmbd -cp -a ../master/luci/applications/luci-app-ksmbd feeds/luci/applications/luci-app-ksmbd +if [ "$version" = "rc2" ]; then + rm -rf feeds/luci/applications/luci-app-ksmbd + cp -a ../master/luci/applications/luci-app-ksmbd feeds/luci/applications/luci-app-ksmbd +fi sed -i 's/0666/0644/g;s/0777/0755/g' feeds/luci/applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js # ksmbd tools -rm -rf feeds/packages/net/ksmbd-tools -cp -a ../master/packages/net/ksmbd-tools feeds/packages/net/ksmbd-tools +if [ "$version" = "rc2" ]; then + rm -rf feeds/packages/net/ksmbd-tools + cp -a ../master/packages/net/ksmbd-tools feeds/packages/net/ksmbd-tools +fi sed -i 's/0666/0644/g;s/0777/0755/g' feeds/packages/net/ksmbd-tools/files/ksmbd.config.example sed -i 's/bind interfaces only = yes/bind interfaces only = no/g' feeds/packages/net/ksmbd-tools/files/ksmbd.conf.template @@ -113,9 +126,6 @@ pushd feeds/packages curl -s https://$mirror/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch | patch -p1 popd -# bpf - add host clang-15/17 support -sed -i 's/command -v clang/command -v clang clang-17 clang-15/g' include/bpf.mk - # perf curl -s https://$mirror/openwrt/patch/openwrt-6.x/musl/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch > toolchain/musl/patches/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch if [ "$KERNEL_CLANG_LTO" = "y" ]; then diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index d096bfabd..ee524ccdd 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .53 -LINUX_KERNEL_HASH-6.6.53 = 285d181d1b252b0bf905f040d094215cf183ac98c31a17f9cce9f3537ef4d779 +LINUX_VERSION-6.6 = .54 +LINUX_KERNEL_HASH-6.6.54 = 5fae869d6a24055c16ffc2d92669e3fb2b258e34d36c850bb8cf9def417ecfa0 From 5fa2867bb1b84b9e93838391ecc2116286d46e3b Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 8 Oct 2024 23:13:01 +0800 Subject: [PATCH 050/425] linux-6.12: bump to 6.12rc2 Signed-off-by: sbwml --- openwrt/23-config-common | 1 - openwrt/23-config-musl-r8500 | 1 - .../900-bpf-headers-6.12rc.patch | 19 --------- .../101-fix-build-with-linux-6.12rc2.patch | 42 +++++++++++++++++++ .../901-fix-linux-6.12rc2-builds.patch | 16 +++++++ .../0002-fix-kernel-6.12-builds.patch | 24 +++++++++++ .../302-fix-build-for-linux-6.12rc2.patch | 14 +++++++ openwrt/scripts/00-prepare_base.sh | 5 +-- openwrt/scripts/01-prepare_base-mainline.sh | 5 ++- openwrt/scripts/04-fix_kmod.sh | 4 ++ openwrt/scripts/05-fix-source.sh | 2 +- tags/kernel-6.12 | 4 +- 12 files changed, 108 insertions(+), 29 deletions(-) delete mode 100644 openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch create mode 100644 openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch create mode 100644 openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch create mode 100644 openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch create mode 100644 openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch diff --git a/openwrt/23-config-common b/openwrt/23-config-common index b6376642e..2cd413be8 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -129,7 +129,6 @@ CONFIG_PACKAGE_luci-app-upnp=y CONFIG_PACKAGE_luci-app-usb-printer=y CONFIG_PACKAGE_luci-app-vlmcsd=y CONFIG_PACKAGE_luci-app-watchcat=y -CONFIG_PACKAGE_luci-app-wireguard=y CONFIG_PACKAGE_luci-app-wolplus=y CONFIG_PACKAGE_luci-app-zerotier=y CONFIG_PACKAGE_ariang-nginx=y diff --git a/openwrt/23-config-musl-r8500 b/openwrt/23-config-musl-r8500 index 909d55e2e..db7670690 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/23-config-musl-r8500 @@ -121,7 +121,6 @@ CONFIG_PACKAGE_luci-app-upnp=y CONFIG_PACKAGE_luci-app-usb-printer=y CONFIG_PACKAGE_luci-app-vlmcsd=y CONFIG_PACKAGE_luci-app-watchcat=y -CONFIG_PACKAGE_luci-app-wireguard=y CONFIG_PACKAGE_luci-app-wolplus=y CONFIG_PACKAGE_luci-app-zerotier=y diff --git a/openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch b/openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch deleted file mode 100644 index 19c738e1f..000000000 --- a/openwrt/patch/generic-24.10/900-bpf-headers-6.12rc.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/package/kernel/bpf-headers/Makefile b/package/kernel/bpf-headers/Makefile -index a644f47..216dd47 100644 ---- a/package/kernel/bpf-headers/Makefile -+++ b/package/kernel/bpf-headers/Makefile -@@ -13,12 +13,12 @@ include $(INCLUDE_DIR)/kernel.mk - - - PKG_NAME:=linux --PKG_PATCHVER:=6.6 -+PKG_PATCHVER:=6.12 - # Manually include kernel version and hash from kernel details file - include $(INCLUDE_DIR)/kernel-$(PKG_PATCHVER) - - PKG_VERSION:=$(PKG_PATCHVER)$(strip $(LINUX_VERSION-$(PKG_PATCHVER))) --PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz -+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz - PKG_SOURCE_URL:=@KERNEL/linux/kernel/v$(word 1,$(subst ., ,$(PKG_PATCHVER))).x - PKG_HASH:=$(LINUX_KERNEL_HASH-$(strip $(PKG_VERSION))) - PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/bpf-headers/$(PKG_NAME)-$(PKG_VERSION) diff --git a/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch b/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch new file mode 100644 index 000000000..7cc31573c --- /dev/null +++ b/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch @@ -0,0 +1,42 @@ +--- a/mt76x0/eeprom.c ++++ b/mt76x0/eeprom.c +@@ -10,7 +10,11 @@ + #include + #include + #include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++#include ++#else + #include ++#endif + #include "mt76x0.h" + #include "eeprom.h" + #include "../mt76x02_phy.h" +--- a/mt76x02_eeprom.c ++++ b/mt76x02_eeprom.c +@@ -4,7 +4,11 @@ + * Copyright (C) 2018 Lorenzo Bianconi + */ + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++#include ++#else + #include ++#endif + + #include "mt76x02_eeprom.h" + +--- a/mt76x2/eeprom.c ++++ b/mt76x2/eeprom.c +@@ -5,7 +5,11 @@ + + #include + #include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++#include ++#else + #include ++#endif + #include "mt76x2.h" + #include "eeprom.h" + diff --git a/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch b/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch new file mode 100644 index 000000000..a8b04ce0d --- /dev/null +++ b/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch @@ -0,0 +1,16 @@ +--- a/net/batman-adv/distributed-arp-table.c ++++ b/net/batman-adv/distributed-arp-table.c +@@ -7,7 +7,13 @@ + #include "distributed-arp-table.h" + #include "main.h" + ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++#include ++#else + #include ++#endif + #include + #include + #include diff --git a/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch b/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch new file mode 100644 index 000000000..20553406e --- /dev/null +++ b/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch @@ -0,0 +1,24 @@ +diff --git a/xr_usb_serial_common-1a/xr_usb_serial_common.c b/xr_usb_serial_common-1a/xr_usb_serial_common.c +index 74bfa93..a948305 100644 +--- a/xr_usb_serial_common-1a/xr_usb_serial_common.c ++++ b/xr_usb_serial_common-1a/xr_usb_serial_common.c +@@ -35,6 +35,7 @@ + #undef VERBOSE_DEBUG + + #include ++#include + #include + #include + #include +@@ -48,7 +49,11 @@ + #include + #include + #include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++#include ++#else + #include ++#endif + #include + #include "linux/version.h" + diff --git a/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch b/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch new file mode 100644 index 000000000..aa66aa00b --- /dev/null +++ b/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch @@ -0,0 +1,14 @@ +--- a/extensions/xt_ipp2p.c ++++ b/extensions/xt_ipp2p.c +@@ -3,7 +3,11 @@ + #include + #include + #include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) ++#include ++#else + #include ++#endif + #include "xt_ipp2p.h" + #include "compat_xtables.h" + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index d7295a090..8cfdae519 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -50,9 +50,6 @@ curl -s https://$mirror/openwrt/patch/$generic/0010-include-kernel-add-miss-conf # meson: add platform variable to cross-compilation file curl -s https://$mirror/openwrt/patch/$generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 -# bpf-headers-6.12 -#[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/$generic/900-bpf-headers-6.12rc.patch | patch -p1 - # mold if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then curl -s https://$mirror/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 @@ -442,7 +439,7 @@ popd sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/diagnostics.js # luci - drop ethernet port status -rm -f feeds/luci/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/29_ports.js +[ "$version" = "rc2" ] && rm -f feeds/luci/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/29_ports.js # luci - rollback dhcp.js curl -s https://$mirror/openwrt/patch/luci/dhcp/${openwrt_version}-dhcp.js > feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 828476757..1bca41af0 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -174,7 +174,10 @@ fi rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile -[ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +[ "$TESTING_KERNEL" = "y" ] && { + curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch + curl -s https://$mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch +} [ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/mt76/patches/100-api_update.patch > package/kernel/mt76/patches/100-api_update.patch # iwinfo: add mt7922 device id diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index e1c73e8a4..b775b95d3 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -90,6 +90,8 @@ pushd feeds/packages [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/23a3ea2d6b3779cd48d318b95a3c72cad9433d50.patch | patch -p1 # fix linux-6.6 [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch > libs/xr_usb_serial_common/patches/900-fix-linux-6.6.patch + # fix linux-6.12 + [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch # coova-chilli [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/9975e855adcfc24939080a5e0279e0a90553347b.patch | patch -p1 [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/c0683d3f012096fc7b2fbe8b8dc81ea424945e9b.patch | patch -p1 @@ -101,6 +103,7 @@ if [ "$version" = "rc2" ]; then cp -a ../master/packages/net/xtables-addons feeds/packages/net/xtables-addons fi curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch +curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch > feeds/packages/net/xtables-addons/patches/302-fix-build-for-linux-6.12rc2.patch # telephony pushd feeds/telephony @@ -116,6 +119,7 @@ if [ "$version" = "rc2" ]; then fi # fix build with linux-6.12 curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch > feeds/routing/batman-adv/patches/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch +curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch > feeds/routing/batman-adv/patches/901-fix-linux-6.12rc2-builds.patch # bcm53xx if [ "$platform" = "bcm53xx" ]; then diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index a32de4eef..94451396b 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -14,7 +14,7 @@ sed -i '/PKG_BUILD_FLAGS/ s/$/ no-gc-sections/' package/boot/grub2/Makefile # xdp-tools rm -rf package/network/utils/xdp-tools -git clone https://$github/sbwml/package_network_utils_xdp-tools package/network/utils/xdp-tools -b openwrt-23.05 +git clone https://$github/sbwml/package_network_utils_xdp-tools package/network/utils/xdp-tools -b $openwrt_version # fix gcc13 if [ "$USE_GCC13" = "y" ] || [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 85b7c5708..340fa590f 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -rc1 -LINUX_KERNEL_HASH-6.12-rc1 = 248f22796171a3d5809d76b019763cd4bb2a69f9a95d243ee614cea7eb3e578e +LINUX_VERSION-6.12 = -rc2 +LINUX_KERNEL_HASH-6.12-rc2 = 36efbb865ead39771f63ecad7a26adf3dc7de93e27932e59dda81a0bda556b91 From daf23b4f47fd3bc7f49e0929ec3ad90def769b68 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 09:23:30 +0800 Subject: [PATCH 051/425] fix emmc-install script Signed-off-by: sbwml --- openwrt/files/sbin/emmc-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/files/sbin/emmc-install b/openwrt/files/sbin/emmc-install index 93ede7f0a..457cab016 100755 --- a/openwrt/files/sbin/emmc-install +++ b/openwrt/files/sbin/emmc-install @@ -6,7 +6,7 @@ # check commands=("bash" "parted" "awk" "sed" "grep" "zcat" "dd" "fdisk") for cmd in "${commands[@]}"; do - if command -v "$cmd" >/dev/null 2>&1; then + if ! which "$cmd" >/dev/null 2>&1; then echo "Command $cmd does not exist." exit 1 fi From 702c760c9fde0937b99e77667536cf3c0e181872 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 09:23:43 +0800 Subject: [PATCH 052/425] nginx: restore the last updated configuration Signed-off-by: sbwml --- openwrt/nginx/openwrt-23.05-uci.conf.template | 2 +- openwrt/nginx/openwrt-24.10-uci.conf.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/nginx/openwrt-23.05-uci.conf.template b/openwrt/nginx/openwrt-23.05-uci.conf.template index 6e81164ee..7888c3dea 100644 --- a/openwrt/nginx/openwrt-23.05-uci.conf.template +++ b/openwrt/nginx/openwrt-23.05-uci.conf.template @@ -2,7 +2,7 @@ # Parsing UCI configuration is skipped if uci set nginx.global.uci_enable=false # For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx -worker_processes 1; +worker_processes 2; user root; diff --git a/openwrt/nginx/openwrt-24.10-uci.conf.template b/openwrt/nginx/openwrt-24.10-uci.conf.template index 0adb618cd..94d57c3ed 100644 --- a/openwrt/nginx/openwrt-24.10-uci.conf.template +++ b/openwrt/nginx/openwrt-24.10-uci.conf.template @@ -3,7 +3,7 @@ # For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx # UCI_CONF_VERSION=1.2 -worker_processes 1; +worker_processes 2; user root; From 688dd1fa6ebd126b6b13075ddad5dbc1816b2032 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 09:25:29 +0800 Subject: [PATCH 053/425] update theme for dev builds Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 36701dce4..3c4b67972 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -123,7 +123,7 @@ git clone https://$github/UnblockNeteaseMusic/luci-app-unblockneteasemusic packa sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new/luci-app-unblockneteasemusic/root/usr/share/luci/menu.d/luci-app-unblockneteasemusic.json # Theme -git clone --depth 1 https://$github/sbwml/luci-theme-argon.git package/new/luci-theme-argon +git clone --depth 1 https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon -b $openwrt_version # Mosdns git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns From 0269b30b5da336589df897fe4e2b7ed7e8ed1909 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 09:29:31 +0800 Subject: [PATCH 054/425] openssl: using non-blocking random numbers * In FIPS testing, non-blocking random numbers with LRNG are hundreds of times faster than hardware random numbers Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 8cfdae519..53ad5999e 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -291,14 +291,8 @@ pushd package/libs/openssl/patches curl -sO https://$mirror/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch popd -# openssl hwrng -if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ]; then - sed -i "/-openwrt/iOPENSSL_OPTIONS += enable-ktls '-DDEVRANDOM=\"\\\\\"/dev/hwrng\\\\\"\"\'\n" package/libs/openssl/Makefile -else - sed -i "/-openwrt/iOPENSSL_OPTIONS += enable-ktls '-DDEVRANDOM=\"\\\\\"/dev/urandom\\\\\"\"\'\n" package/libs/openssl/Makefile -fi -# openssl -Ofast -sed -i "s/-O3/-Ofast/g" package/libs/openssl/Makefile +# openssl urandom +sed -i "/-openwrt/iOPENSSL_OPTIONS += enable-ktls '-DDEVRANDOM=\"\\\\\"/dev/urandom\\\\\"\"\'\n" package/libs/openssl/Makefile # openssl - lto if [ "$ENABLE_LTO" = "y" ]; then From f9b0f002fb6ee36bff8900bb5f370e334ad4c8c5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 10:46:33 +0800 Subject: [PATCH 055/425] openwrt-24.10 kernel 6.12 module testing Signed-off-by: sbwml --- openwrt/build.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index ddc17194f..4f2c61627 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -152,11 +152,14 @@ else echo -e "${GREEN_COLOR}Model: nanopi-r4s${RES}" [ "$1" = "rc2" ] && model="nanopi-r4s" fi -curl -s https://$mirror/tags/kernel-$kernel_version > kernel.txt -kmod_hash=$(grep HASH kernel.txt | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}') -kmodpkg_name=$(echo $(grep HASH kernel.txt | awk -F'HASH-' '{print $2}' | awk '{print $1}')-1-$(echo $kmod_hash)) +get_kernel_version=$(curl -s https://$mirror/tags/kernel-$kernel_version) +kmod_hash=$(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}' | tail -1 | md5sum | awk '{print $1}') +if [ "$TESTING_KERNEL" = "y" ]; then + kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) +else + kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')-1-$(echo $kmod_hash)) +fi echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" -rm -f kernel.txt echo -e "${GREEN_COLOR}Date: $CURRENT_DATE${RES}\r\n" echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" @@ -451,8 +454,6 @@ else exit 1 fi -[ "$TESTING_KERNEL" = "y" ] && OTA_PREFIX="test-" || OTA_PREFIX="" - if [ "$platform" = "x86_64" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name @@ -480,7 +481,7 @@ if [ "$platform" = "x86_64" ]; then { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-x86-64-generic-squashfs-combined-efi.img.gz" + "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-x86-64-generic-squashfs-combined-efi.img.gz" } ] } @@ -514,7 +515,7 @@ elif [ "$platform" = "armv8" ]; then { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "https://github.com/sbwml/builder/releases/download/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-armsr-armv8-generic-squashfs-combined-efi.img.gz" + "url": "https://github.com/sbwml/builder/releases/download/v$VERSION/openwrt-$VERSION-armsr-armv8-generic-squashfs-combined-efi.img.gz" } ] } @@ -548,7 +549,7 @@ elif [ "$platform" = "bcm53xx" ]; then { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-bcm53xx-generic-netgear_r8500-squashfs.chk" + "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-bcm53xx-generic-netgear_r8500-squashfs.chk" } ] } @@ -580,7 +581,7 @@ else { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r4s-squashfs-sysupgrade.img.gz" + "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r4s-squashfs-sysupgrade.img.gz" } ] } @@ -595,14 +596,14 @@ EOF { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256_R5C", - "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5c-squashfs-sysupgrade.img.gz" + "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5c-squashfs-sysupgrade.img.gz" } ], "friendlyarm,nanopi-r5s": [ { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256_R5S", - "url": "$OTA_URL/${OTA_PREFIX}v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5s-squashfs-sysupgrade.img.gz" + "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-rockchip-armv8-friendlyarm_nanopi-r5s-squashfs-sysupgrade.img.gz" } ] } From 1e3b5ccc6282e3f9f8f9ff7724d05b0adde2e28f Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 21:47:30 +0800 Subject: [PATCH 056/425] linux-6.12: add legacy cgroup v1 memory controller * docker full function support Signed-off-by: sbwml --- openwrt/23-config-musl-armsr-armv8 | 1 + openwrt/23-config-musl-r4s | 1 + openwrt/23-config-musl-r5s | 1 + openwrt/23-config-musl-x86 | 1 + ...d-legacy-cgroup-v1-memory-controller.patch | 34 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 3 ++ 6 files changed, 41 insertions(+) create mode 100644 openwrt/patch/generic-24.10/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch diff --git a/openwrt/23-config-musl-armsr-armv8 b/openwrt/23-config-musl-armsr-armv8 index d98c3971b..cd6155ab8 100644 --- a/openwrt/23-config-musl-armsr-armv8 +++ b/openwrt/23-config-musl-armsr-armv8 @@ -8,6 +8,7 @@ CONFIG_ALL_KMODS=y CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" +CONFIG_KERNEL_MEMCG_V1=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-r4s b/openwrt/23-config-musl-r4s index 42da9b4ef..d0e0009d5 100644 --- a/openwrt/23-config-musl-r4s +++ b/openwrt/23-config-musl-r4s @@ -8,6 +8,7 @@ CONFIG_ALL_KMODS=y CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" +CONFIG_KERNEL_MEMCG_V1=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-r5s b/openwrt/23-config-musl-r5s index d39a9c132..ed106a735 100644 --- a/openwrt/23-config-musl-r5s +++ b/openwrt/23-config-musl-r5s @@ -11,6 +11,7 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_CFLAGS="-march=armv8.2-a+crypto+crc -mcpu=cortex-a55+crypto+crc -mtune=cortex-a55" +CONFIG_KERNEL_MEMCG_V1=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 435ec41db..7b83c011a 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -9,6 +9,7 @@ CONFIG_ALL_KMODS=y CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" +CONFIG_KERNEL_MEMCG_V1=y CONFIG_PACKAGE_autocore-x86=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/patch/generic-24.10/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch b/openwrt/patch/generic-24.10/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch new file mode 100644 index 000000000..d4786d652 --- /dev/null +++ b/openwrt/patch/generic-24.10/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch @@ -0,0 +1,34 @@ +From b7d40a7057e1ffe5b2dcf734243ef2ae791f5fb1 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 10 Oct 2024 21:40:05 +0800 +Subject: [PATCH] kernel: add legacy cgroup v1 memory controller + +Signed-off-by: sbwml +--- + config/Config-kernel.in | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/config/Config-kernel.in b/config/Config-kernel.in +index c83f2fb..39a9730 100644 +--- a/config/Config-kernel.in ++++ b/config/Config-kernel.in +@@ -934,6 +934,16 @@ if KERNEL_CGROUPS + the kmem extension can use it to guarantee that no group of processes + will ever exhaust kernel resources alone. + ++ config KERNEL_MEMCG_V1 ++ bool "Legacy cgroup v1 memory controller" ++ depends on KERNEL_MEMCG ++ help ++ Legacy cgroup v1 memory controller which has been deprecated by ++ cgroup v2 implementation. The v1 is there for legacy applications ++ which haven't migrated to the new cgroup v2 interface yet. If you ++ do not have any such application then you are completely fine leaving ++ this option disabled. ++ + config KERNEL_CGROUP_PERF + bool "Enable perf_event per-cpu per-container group (cgroup) monitoring" + select KERNEL_PERF_EVENTS +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 53ad5999e..deca10a6f 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -50,6 +50,9 @@ curl -s https://$mirror/openwrt/patch/$generic/0010-include-kernel-add-miss-conf # meson: add platform variable to cross-compilation file curl -s https://$mirror/openwrt/patch/$generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 +# kernel 6.12: add legacy cgroup v1 memory controller +[ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/$generic/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 + # mold if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then curl -s https://$mirror/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 From 4d854d9718c02d6f935091658f9ea24ccc276ae0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Oct 2024 01:14:40 +0800 Subject: [PATCH 057/425] add 10-custom.sh Signed-off-by: sbwml --- openwrt/build.sh | 8 +++++++- openwrt/scripts/10-custom.sh | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 openwrt/scripts/10-custom.sh diff --git a/openwrt/build.sh b/openwrt/build.sh index 4f2c61627..65852ebd3 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -259,6 +259,11 @@ curl -sO https://$mirror/openwrt/scripts/03-convert_translation.sh curl -sO https://$mirror/openwrt/scripts/04-fix_kmod.sh curl -sO https://$mirror/openwrt/scripts/05-fix-source.sh curl -sO https://$mirror/openwrt/scripts/99_clean_build_cache.sh +if [ -z "$git_password" ] && [ -z "$private_url" ]; then + curl -u openwrt:$git_password -sO "$private_url" +else + curl -sO https://$mirror/openwrt/scripts/10-custom.sh +fi chmod 0755 *sh [ "$(whoami)" = "runner" ] && group "patching openwrt" bash 00-prepare_base.sh @@ -267,6 +272,7 @@ bash 02-prepare_package.sh bash 03-convert_translation.sh bash 04-fix_kmod.sh bash 05-fix-source.sh +[ -f "10-custom.sh" ] && bash 10-custom.sh [ "$(whoami)" = "runner" ] && endgroup if [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ] && [ "$version" = "rc2" ]; then @@ -274,7 +280,7 @@ if [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ] && [ "$version" = "rc2" ]; t cp -a ../master/openwrt/toolchain/binutils toolchain/binutils fi -rm -f 0*-*.sh +rm -f 0*-*.sh 10-custom.sh rm -rf ../master # Load devices Config diff --git a/openwrt/scripts/10-custom.sh b/openwrt/scripts/10-custom.sh new file mode 100644 index 000000000..cea74a296 --- /dev/null +++ b/openwrt/scripts/10-custom.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +# 自定义脚本 From 72d231f918d235870fb13020e849bfcd01ef0c14 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Oct 2024 01:15:22 +0800 Subject: [PATCH 058/425] linux-6.6: bump to 6.6.56 Signed-off-by: sbwml --- tags/kernel-6.6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index ee524ccdd..6f72804b8 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .54 -LINUX_KERNEL_HASH-6.6.54 = 5fae869d6a24055c16ffc2d92669e3fb2b258e34d36c850bb8cf9def417ecfa0 +LINUX_VERSION-6.6 = .56 +LINUX_KERNEL_HASH-6.6.56 = f74812f78e88992c416434cb107639e13a551dbaff36bb90d6346ab16ab71a95 From 6fe39f7e7ee4f7837469222643a7abd3c78886d0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Oct 2024 04:46:47 +0800 Subject: [PATCH 059/425] build.sh: fix typo Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 65852ebd3..0e4c25c8b 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -259,7 +259,7 @@ curl -sO https://$mirror/openwrt/scripts/03-convert_translation.sh curl -sO https://$mirror/openwrt/scripts/04-fix_kmod.sh curl -sO https://$mirror/openwrt/scripts/05-fix-source.sh curl -sO https://$mirror/openwrt/scripts/99_clean_build_cache.sh -if [ -z "$git_password" ] && [ -z "$private_url" ]; then +if [ -n "$git_password" ] && [ -n "$private_url" ]; then curl -u openwrt:$git_password -sO "$private_url" else curl -sO https://$mirror/openwrt/scripts/10-custom.sh From 681d7141fe00b2204dcc29fe43d0260f7fff6985 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Oct 2024 06:08:43 +0800 Subject: [PATCH 060/425] config: drop luci-app-accesscontrol Signed-off-by: sbwml --- openwrt/23-config-common | 1 - 1 file changed, 1 deletion(-) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 2cd413be8..ec08db772 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -97,7 +97,6 @@ CONFIG_NGINX_HTTP_SUB=y CONFIG_NGINX_STREAM_REAL_IP=y ### APPS -CONFIG_PACKAGE_luci-app-accesscontrol=y CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-alist=y From 56ff5a38fac381896a0a94ae9a34a1e3659399a0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 12 Oct 2024 08:40:23 +0800 Subject: [PATCH 061/425] openwrt-24.10: kernel: add linux-rt support for aarch64/x86_64 Signed-off-by: sbwml --- ...-linux-rt-support-for-aarch64-x86_64.patch | 37 ++++++ ...empt_disable-enable_rt-where-recomme.patch | 118 ++++++++++++++++++ ...isable-interrupts-on-PREEMPT_RT-duri.patch | 118 ++++++++++++++++++ ...heck-for-atomic-context-on-PREEMPT_R.patch | 38 ++++++ ...Disable-tracing-points-on-PREEMPT_RT.patch | 59 +++++++++ ...spin_lock_irq-instead-of-local_irq_d.patch | 88 +++++++++++++ ...rm-i915-Drop-the-irqs_disabled-check.patch | 39 ++++++ ...Consider-also-RCU-depth-in-busy-loop.patch | 29 +++++ ...Revert-drm-i915-Depend-on-PREEMPT_RT.patch | 23 ++++ openwrt/scripts/00-prepare_base.sh | 3 + openwrt/scripts/01-prepare_base-mainline.sh | 14 +++ 11 files changed, 566 insertions(+) create mode 100644 openwrt/patch/generic-24.10/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch create mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch diff --git a/openwrt/patch/generic-24.10/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch b/openwrt/patch/generic-24.10/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch new file mode 100644 index 000000000..74af18b61 --- /dev/null +++ b/openwrt/patch/generic-24.10/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch @@ -0,0 +1,37 @@ +From bd8a486bf2a805a7783b3a3e329b5756c1ff6127 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sat, 12 Oct 2024 08:36:46 +0800 +Subject: [PATCH] kernel: add PREEMPT_RT support for aarch64/x86_64 + +Signed-off-by: sbwml +--- + config/Config-kernel.in | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/config/Config-kernel.in b/config/Config-kernel.in +index 39a9730..5439219 100644 +--- a/config/Config-kernel.in ++++ b/config/Config-kernel.in +@@ -20,6 +20,19 @@ config KERNEL_BUILD_DOMAIN + returned by 'uname -a' on running systems. + If not set, uses system hostname at build time. + ++config KERNEL_PREEMPT_RT ++ bool "Fully Preemptible Kernel (Real-Time)" ++ depends on (aarch64 || x86_64) && LINUX_6_12 ++ help ++ This option turns the kernel into a real-time kernel by replacing ++ various locking primitives (spinlocks, rwlocks, etc.) with ++ preemptible priority-inheritance aware variants, enforcing ++ interrupt threading and introducing mechanisms to break up long ++ non-preemptible sections. This makes the kernel, except for very ++ low level and critical code paths (entry code, scheduler, low ++ level interrupt handling) fully preemptible and brings most ++ execution contexts under scheduler control. ++ + config KERNEL_PRINTK + bool "Enable support for printk" + default y +-- +2.43.5 + diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch new file mode 100644 index 000000000..a4f91e31c --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch @@ -0,0 +1,118 @@ +From: Mike Galbraith +Date: Sat, 27 Feb 2016 08:09:11 +0100 +Subject: [PATCH 1/8] drm/i915: Use preempt_disable/enable_rt() where + recommended + +Mario Kleiner suggest in commit + ad3543ede630f ("drm/intel: Push get_scanout_position() timestamping into kms driver.") + +a spots where preemption should be disabled on PREEMPT_RT. The +difference is that on PREEMPT_RT the intel_uncore::lock disables neither +preemption nor interrupts and so region remains preemptible. + +The area covers only register reads and writes. The part that worries me +is: +- __intel_get_crtc_scanline() the worst case is 100us if no match is + found. + +- intel_crtc_scanlines_since_frame_timestamp() not sure how long this + may take in the worst case. + +It was in the RT queue for a while and nobody complained. +Disable preemption on PREEPMPT_RT during timestamping. + +[bigeasy: patch description.] + +Cc: Mario Kleiner +Signed-off-by: Mike Galbraith +Signed-off-by: Thomas Gleixner +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/display/intel_vblank.c | 43 +++++++++++++++++++++------- + 1 file changed, 33 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/i915/display/intel_vblank.c ++++ b/drivers/gpu/drm/i915/display/intel_vblank.c +@@ -308,6 +308,20 @@ static void intel_vblank_section_exit(st + struct drm_i915_private *i915 = to_i915(display->drm); + spin_unlock(&i915->uncore.lock); + } ++ ++static void intel_vblank_section_enter_irqf(struct intel_display *display, unsigned long *flags) ++ __acquires(i915->uncore.lock) ++{ ++ struct drm_i915_private *i915 = to_i915(display->drm); ++ spin_lock_irqsave(&i915->uncore.lock, *flags); ++} ++ ++static void intel_vblank_section_exit_irqf(struct intel_display *display, unsigned long flags) ++ __releases(i915->uncore.lock) ++{ ++ struct drm_i915_private *i915 = to_i915(display->drm); ++ spin_unlock_irqrestore(&i915->uncore.lock, flags); ++} + #else + static void intel_vblank_section_enter(struct intel_display *display) + { +@@ -316,6 +330,17 @@ static void intel_vblank_section_enter(s + static void intel_vblank_section_exit(struct intel_display *display) + { + } ++ ++static void intel_vblank_section_enter_irqf(struct intel_display *display, unsigned long *flags) ++{ ++ *flags = 0; ++} ++ ++static void intel_vblank_section_exit_irqf(struct intel_display *display, unsigned long flags) ++{ ++ if (flags) ++ return; ++} + #endif + + static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, +@@ -353,10 +378,10 @@ static bool i915_get_crtc_scanoutpos(str + * timing critical raw register reads, potentially with + * preemption disabled, so the following code must not block. + */ +- local_irq_save(irqflags); +- intel_vblank_section_enter(display); ++ intel_vblank_section_enter_irqf(display, &irqflags); + +- /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_disable(); + + /* Get optional system timestamp before query. */ + if (stime) +@@ -420,10 +445,10 @@ static bool i915_get_crtc_scanoutpos(str + if (etime) + *etime = ktime_get(); + +- /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ ++ if (IS_ENABLED(CONFIG_PREEMPT_RT)) ++ preempt_enable(); + +- intel_vblank_section_exit(display); +- local_irq_restore(irqflags); ++ intel_vblank_section_exit_irqf(display, irqflags); + + /* + * While in vblank, position will be negative +@@ -461,13 +486,11 @@ int intel_get_crtc_scanline(struct intel + unsigned long irqflags; + int position; + +- local_irq_save(irqflags); +- intel_vblank_section_enter(display); ++ intel_vblank_section_enter_irqf(display, &irqflags); + + position = __intel_get_crtc_scanline(crtc); + +- intel_vblank_section_exit(display); +- local_irq_restore(irqflags); ++ intel_vblank_section_exit_irqf(display, irqflags); + + return position; + } diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch new file mode 100644 index 000000000..5d14624b5 --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch @@ -0,0 +1,118 @@ +From: Mike Galbraith +Date: Sat, 27 Feb 2016 09:01:42 +0100 +Subject: [PATCH 2/8] drm/i915: Don't disable interrupts on PREEMPT_RT during + atomic updates + +Commit + 8d7849db3eab7 ("drm/i915: Make sprite updates atomic") + +started disabling interrupts across atomic updates. This breaks on PREEMPT_RT +because within this section the code attempt to acquire spinlock_t locks which +are sleeping locks on PREEMPT_RT. + +According to the comment the interrupts are disabled to avoid random delays and +not required for protection or synchronisation. +If this needs to happen with disabled interrupts on PREEMPT_RT, and the +whole section is restricted to register access then all sleeping locks +need to be acquired before interrupts are disabled and some function +maybe moved after enabling interrupts again. +This includes: +- prepare_to_wait() + finish_wait() due its wake queue. +- drm_crtc_vblank_put() -> vblank_disable_fn() drm_device::vbl_lock. +- skl_pfit_enable(), intel_update_plane(), vlv_atomic_update_fifo() and + maybe others due to intel_uncore::lock +- drm_crtc_arm_vblank_event() due to drm_device::event_lock and + drm_device::vblank_time_lock. + +Don't disable interrupts on PREEMPT_RT during atomic updates. + +[bigeasy: drop local locks, commit message] + +Signed-off-by: Mike Galbraith +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/display/intel_crtc.c | 9 ++++++--- + drivers/gpu/drm/i915/display/intel_cursor.c | 9 ++++++--- + drivers/gpu/drm/i915/display/intel_vblank.c | 6 ++++-- + 3 files changed, 16 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/i915/display/intel_crtc.c ++++ b/drivers/gpu/drm/i915/display/intel_crtc.c +@@ -521,7 +521,8 @@ void intel_pipe_update_start(struct inte + */ + intel_psr_wait_for_idle_locked(new_crtc_state); + +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + + crtc->debug.min_vbl = evade.min; + crtc->debug.max_vbl = evade.max; +@@ -539,7 +540,8 @@ void intel_pipe_update_start(struct inte + return; + + irq_disable: +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + } + + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) +@@ -668,7 +670,8 @@ void intel_pipe_update_end(struct intel_ + */ + intel_vrr_send_push(new_crtc_state); + +- local_irq_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_enable(); + + if (intel_vgpu_active(dev_priv)) + goto out; +--- a/drivers/gpu/drm/i915/display/intel_cursor.c ++++ b/drivers/gpu/drm/i915/display/intel_cursor.c +@@ -895,13 +895,15 @@ intel_legacy_cursor_update(struct drm_pl + */ + intel_psr_wait_for_idle_locked(crtc_state); + +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + + intel_vblank_evade(&evade); + + drm_crtc_vblank_put(&crtc->base); + } else { +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + } + + if (new_plane_state->uapi.visible) { +@@ -911,7 +913,8 @@ intel_legacy_cursor_update(struct drm_pl + intel_plane_disable_arm(plane, crtc_state); + } + +- local_irq_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_enable(); + + intel_psr_unlock(crtc_state); + +--- a/drivers/gpu/drm/i915/display/intel_vblank.c ++++ b/drivers/gpu/drm/i915/display/intel_vblank.c +@@ -711,11 +711,13 @@ int intel_vblank_evade(struct intel_vbla + break; + } + +- local_irq_enable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_enable(); + + timeout = schedule_timeout(timeout); + +- local_irq_disable(); ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) ++ local_irq_disable(); + } + + finish_wait(wq, &wait); diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch new file mode 100644 index 000000000..445ed66cf --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch @@ -0,0 +1,38 @@ +From: Sebastian Andrzej Siewior +Date: Mon, 25 Oct 2021 15:05:18 +0200 +Subject: [PATCH 3/8] drm/i915: Don't check for atomic context on PREEMPT_RT + +The !in_atomic() check in _wait_for_atomic() triggers on PREEMPT_RT +because the uncore::lock is a spinlock_t and does not disable +preemption or interrupts. + +Changing the uncore:lock to a raw_spinlock_t doubles the worst case +latency on an otherwise idle testbox during testing. + +Ignore _WAIT_FOR_ATOMIC_CHECK() on PREEMPT_RT. + +Reviewed-by: Tvrtko Ursulin +Link: https://lore.kernel.org/all/20211006164628.s2mtsdd2jdbfyf7g@linutronix.de/ +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/i915_utils.h | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_utils.h ++++ b/drivers/gpu/drm/i915/i915_utils.h +@@ -269,8 +269,13 @@ wait_remaining_ms_from_jiffies(unsigned + (Wmax)) + #define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) + +-/* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */ +-#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) ++/* ++ * If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. ++ * On PREEMPT_RT the context isn't becoming atomic because it is used in an ++ * interrupt handler or because a spinlock_t is acquired. This leads to ++ * warnings which don't occur otherwise and therefore the check is disabled. ++ */ ++#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT) + # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic()) + #else + # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0) diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch new file mode 100644 index 000000000..1e38b5820 --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch @@ -0,0 +1,59 @@ +From: Sebastian Andrzej Siewior +Date: Thu, 6 Dec 2018 09:52:20 +0100 +Subject: [PATCH 4/8] drm/i915: Disable tracing points on PREEMPT_RT + +Luca Abeni reported this: +| BUG: scheduling while atomic: kworker/u8:2/15203/0x00000003 +| CPU: 1 PID: 15203 Comm: kworker/u8:2 Not tainted 4.19.1-rt3 #10 +| Call Trace: +| rt_spin_lock+0x3f/0x50 +| gen6_read32+0x45/0x1d0 [i915] +| g4x_get_vblank_counter+0x36/0x40 [i915] +| trace_event_raw_event_i915_pipe_update_start+0x7d/0xf0 [i915] + +The tracing events use trace_intel_pipe_update_start() among other events +use functions acquire spinlock_t locks which are transformed into +sleeping locks on PREEMPT_RT. A few trace points use +intel_get_crtc_scanline(), others use ->get_vblank_counter() wich also +might acquire a sleeping locks on PREEMPT_RT. +At the time the arguments are evaluated within trace point, preemption +is disabled and so the locks must not be acquired on PREEMPT_RT. + +Based on this I don't see any other way than disable trace points on +PREMPT_RT. + +Acked-by: Tvrtko Ursulin +Reported-by: Luca Abeni +Cc: Steven Rostedt +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/display/intel_display_trace.h | 4 ++++ + drivers/gpu/drm/i915/i915_trace.h | 4 ++++ + 2 files changed, 8 insertions(+) + +--- a/drivers/gpu/drm/i915/display/intel_display_trace.h ++++ b/drivers/gpu/drm/i915/display/intel_display_trace.h +@@ -9,6 +9,10 @@ + #if !defined(__INTEL_DISPLAY_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) + #define __INTEL_DISPLAY_TRACE_H__ + ++#if defined(CONFIG_PREEMPT_RT) && !defined(NOTRACE) ++#define NOTRACE ++#endif ++ + #include + #include + #include +--- a/drivers/gpu/drm/i915/i915_trace.h ++++ b/drivers/gpu/drm/i915/i915_trace.h +@@ -6,6 +6,10 @@ + #if !defined(_I915_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) + #define _I915_TRACE_H_ + ++#if defined(CONFIG_PREEMPT_RT) && !defined(NOTRACE) ++#define NOTRACE ++#endif ++ + #include + #include + #include diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch new file mode 100644 index 000000000..8cd2a3295 --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch @@ -0,0 +1,88 @@ +From: Sebastian Andrzej Siewior +Date: Wed, 8 Sep 2021 19:03:41 +0200 +Subject: [PATCH 5/8] drm/i915/gt: Use spin_lock_irq() instead of + local_irq_disable() + spin_lock() + +execlists_dequeue() is invoked from a function which uses +local_irq_disable() to disable interrupts so the spin_lock() behaves +like spin_lock_irq(). +This breaks PREEMPT_RT because local_irq_disable() + spin_lock() is not +the same as spin_lock_irq(). + +execlists_dequeue_irq() and execlists_dequeue() has each one caller +only. If intel_engine_cs::active::lock is acquired and released with the +_irq suffix then it behaves almost as if execlists_dequeue() would be +invoked with disabled interrupts. The difference is the last part of the +function which is then invoked with enabled interrupts. +I can't tell if this makes a difference. From looking at it, it might +work to move the last unlock at the end of the function as I didn't find +anything that would acquire the lock again. + +Reported-by: Clark Williams +Signed-off-by: Sebastian Andrzej Siewior +Reviewed-by: Maarten Lankhorst +--- + drivers/gpu/drm/i915/gt/intel_execlists_submission.c | 17 +++++------------ + 1 file changed, 5 insertions(+), 12 deletions(-) + +--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c ++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +@@ -1303,7 +1303,7 @@ static void execlists_dequeue(struct int + * and context switches) submission. + */ + +- spin_lock(&sched_engine->lock); ++ spin_lock_irq(&sched_engine->lock); + + /* + * If the queue is higher priority than the last +@@ -1403,7 +1403,7 @@ static void execlists_dequeue(struct int + * Even if ELSP[1] is occupied and not worthy + * of timeslices, our queue might be. + */ +- spin_unlock(&sched_engine->lock); ++ spin_unlock_irq(&sched_engine->lock); + return; + } + } +@@ -1429,7 +1429,7 @@ static void execlists_dequeue(struct int + + if (last && !can_merge_rq(last, rq)) { + spin_unlock(&ve->base.sched_engine->lock); +- spin_unlock(&engine->sched_engine->lock); ++ spin_unlock_irq(&engine->sched_engine->lock); + return; /* leave this for another sibling */ + } + +@@ -1591,7 +1591,7 @@ done: + */ + sched_engine->queue_priority_hint = queue_prio(sched_engine); + i915_sched_engine_reset_on_empty(sched_engine); +- spin_unlock(&sched_engine->lock); ++ spin_unlock_irq(&sched_engine->lock); + + /* + * We can skip poking the HW if we ended up with exactly the same set +@@ -1617,13 +1617,6 @@ done: + } + } + +-static void execlists_dequeue_irq(struct intel_engine_cs *engine) +-{ +- local_irq_disable(); /* Suspend interrupts across request submission */ +- execlists_dequeue(engine); +- local_irq_enable(); /* flush irq_work (e.g. breadcrumb enabling) */ +-} +- + static void clear_ports(struct i915_request **ports, int count) + { + memset_p((void **)ports, NULL, count); +@@ -2478,7 +2471,7 @@ static void execlists_submission_tasklet + } + + if (!engine->execlists.pending[0]) { +- execlists_dequeue_irq(engine); ++ execlists_dequeue(engine); + start_timeslice(engine); + } + diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch new file mode 100644 index 000000000..0c2018e67 --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch @@ -0,0 +1,39 @@ +From: Sebastian Andrzej Siewior +Date: Fri, 1 Oct 2021 20:01:03 +0200 +Subject: [PATCH 6/8] drm/i915: Drop the irqs_disabled() check + +The !irqs_disabled() check triggers on PREEMPT_RT even with +i915_sched_engine::lock acquired. The reason is the lock is transformed +into a sleeping lock on PREEMPT_RT and does not disable interrupts. + +There is no need to check for disabled interrupts. The lockdep +annotation below already check if the lock has been acquired by the +caller and will yell if the interrupts are not disabled. + +Remove the !irqs_disabled() check. + +Reported-by: Maarten Lankhorst +Acked-by: Tvrtko Ursulin +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/i915_request.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_request.c ++++ b/drivers/gpu/drm/i915/i915_request.c +@@ -608,7 +608,6 @@ bool __i915_request_submit(struct i915_r + + RQ_TRACE(request, "\n"); + +- GEM_BUG_ON(!irqs_disabled()); + lockdep_assert_held(&engine->sched_engine->lock); + + /* +@@ -717,7 +716,6 @@ void __i915_request_unsubmit(struct i915 + */ + RQ_TRACE(request, "\n"); + +- GEM_BUG_ON(!irqs_disabled()); + lockdep_assert_held(&engine->sched_engine->lock); + + /* diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch new file mode 100644 index 000000000..8c3217614 --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch @@ -0,0 +1,29 @@ +From: Sebastian Andrzej Siewior +Date: Tue, 3 Oct 2023 21:37:21 +0200 +Subject: [PATCH 7/8] drm/i915/guc: Consider also RCU depth in busy loop. + +intel_guc_send_busy_loop() looks at in_atomic() and irqs_disabled() to +decide if it should busy-spin while waiting or if it may sleep. +Both checks will report false on PREEMPT_RT if sleeping spinlocks are +acquired leading to RCU splats while the function sleeps. + +Check also if RCU has been disabled. + +Reported-by: "John B. Wyatt IV" +Reviewed-by: Rodrigo Vivi +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/gt/uc/intel_guc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h ++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h +@@ -362,7 +362,7 @@ static inline int intel_guc_send_busy_lo + { + int err; + unsigned int sleep_period_ms = 1; +- bool not_atomic = !in_atomic() && !irqs_disabled(); ++ bool not_atomic = !in_atomic() && !irqs_disabled() && !rcu_preempt_depth(); + + /* + * FIXME: Have caller pass in if we are in an atomic context to avoid diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch new file mode 100644 index 000000000..0ab01fe1e --- /dev/null +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch @@ -0,0 +1,23 @@ +From: Sebastian Andrzej Siewior +Date: Mon, 21 Feb 2022 17:59:14 +0100 +Subject: [PATCH 8/8] Revert "drm/i915: Depend on !PREEMPT_RT." + +Once the known issues are addressed, it should be safe to enable the +driver. + +Acked-by: Tvrtko Ursulin +Signed-off-by: Sebastian Andrzej Siewior +--- + drivers/gpu/drm/i915/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/gpu/drm/i915/Kconfig ++++ b/drivers/gpu/drm/i915/Kconfig +@@ -3,7 +3,6 @@ config DRM_I915 + tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" + depends on DRM + depends on X86 && PCI +- depends on !PREEMPT_RT + select INTEL_GTT if X86 + select INTERVAL_TREE + # we need shmfs for the swappable backing store, and in particular diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index deca10a6f..8c9173b34 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -53,6 +53,9 @@ curl -s https://$mirror/openwrt/patch/$generic/0011-meson-add-platform-variable- # kernel 6.12: add legacy cgroup v1 memory controller [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/$generic/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 +# kernel 6.12: add linux-rt support for aarch64/x86_64 +[ "$version" = "snapshots-24.10" ] && [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/$generic/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch | patch -p1 + # mold if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then curl -s https://$mirror/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 1bca41af0..4744305d8 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -152,6 +152,20 @@ pushd target/linux/generic/hack-$kernel_version curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch popd +# linux-rt - i915 +if [ "$TESTING_KERNEL" = "y" ]; then + pushd target/linux/generic/hack-6.12 + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch + popd +fi + # linux-firmware: rtw89 / rtl8723d / rtl8821c /i915 firmware rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware From 2785e7bb67727aef568db20f68df115b60d66fd7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 12 Oct 2024 08:42:53 +0800 Subject: [PATCH 062/425] config: enable `KERNEL_PREEMPT_RT` Signed-off-by: sbwml --- openwrt/23-config-musl-armsr-armv8 | 1 + openwrt/23-config-musl-r4s | 1 + openwrt/23-config-musl-r5s | 1 + openwrt/23-config-musl-x86 | 1 + 4 files changed, 4 insertions(+) diff --git a/openwrt/23-config-musl-armsr-armv8 b/openwrt/23-config-musl-armsr-armv8 index cd6155ab8..49a9ccf5e 100644 --- a/openwrt/23-config-musl-armsr-armv8 +++ b/openwrt/23-config-musl-armsr-armv8 @@ -9,6 +9,7 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_PREEMPT_RT=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-r4s b/openwrt/23-config-musl-r4s index d0e0009d5..f093e8f85 100644 --- a/openwrt/23-config-musl-r4s +++ b/openwrt/23-config-musl-r4s @@ -9,6 +9,7 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_PREEMPT_RT=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-r5s b/openwrt/23-config-musl-r5s index ed106a735..15d81f0b8 100644 --- a/openwrt/23-config-musl-r5s +++ b/openwrt/23-config-musl-r5s @@ -12,6 +12,7 @@ CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_CFLAGS="-march=armv8.2-a+crypto+crc -mcpu=cortex-a55+crypto+crc -mtune=cortex-a55" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_PREEMPT_RT=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 7b83c011a..854987ab5 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -10,6 +10,7 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_PREEMPT_RT=y CONFIG_PACKAGE_autocore-x86=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y From 83785522d44c69d4a012cf69c00a4260612ce751 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 13 Oct 2024 21:41:56 +0800 Subject: [PATCH 063/425] upnp: update to 2.3.7 Signed-off-by: sbwml --- .../miniupnpd/01-set-presentation_url.patch | 13 - .../patch/miniupnpd/02-force_forwarding.patch | 260 ------------------ ...4-enable-force_forwarding-by-default.patch | 13 - openwrt/scripts/00-prepare_base.sh | 15 +- 4 files changed, 3 insertions(+), 298 deletions(-) delete mode 100644 openwrt/patch/miniupnpd/01-set-presentation_url.patch delete mode 100644 openwrt/patch/miniupnpd/02-force_forwarding.patch delete mode 100644 openwrt/patch/miniupnpd/04-enable-force_forwarding-by-default.patch diff --git a/openwrt/patch/miniupnpd/01-set-presentation_url.patch b/openwrt/patch/miniupnpd/01-set-presentation_url.patch deleted file mode 100644 index c7111295a..000000000 --- a/openwrt/patch/miniupnpd/01-set-presentation_url.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/net/miniupnpd/files/miniupnpd.init b/net/miniupnpd/files/miniupnpd.init -index de3504529..e89e4e55a 100644 ---- a/net/miniupnpd/files/miniupnpd.init -+++ b/net/miniupnpd/files/miniupnpd.init -@@ -217,6 +217,8 @@ stop_service() { - } - - start_service() { -+ uci set upnpd.config.presentation_url="http://$(uci -q get network.lan.ipaddr)/" -+ uci commit upnpd - config_load "upnpd" - config_foreach upnpd "upnpd" - } diff --git a/openwrt/patch/miniupnpd/02-force_forwarding.patch b/openwrt/patch/miniupnpd/02-force_forwarding.patch deleted file mode 100644 index bb414b2cd..000000000 --- a/openwrt/patch/miniupnpd/02-force_forwarding.patch +++ /dev/null @@ -1,260 +0,0 @@ -From 360235fcc0f5c821ad9d99ccbe5b0b465d9c85fa Mon Sep 17 00:00:00 2001 -From: Chen Minqiang -Date: Fri, 2 Jul 2021 17:59:05 +0800 -Subject: [PATCH] miniupnpd: add force_forwarding option support - -This option replace the 'ext_ip_reserved_ignore', and replace the -patch with new one - -as addr_is_reserved() behavior should not be changed, so drop the -ext_ip_reserved_ignore - -use a force_forwarding option to make the port forwarding force to -work when the router is behind NAT - -by default force_forwarding is set to 0(disabled), where change -nothing with the original behavior, and users can turn it on -according to their wishes - -Signed-off-by: Chen Minqiang ---- - net/miniupnpd/files/miniupnpd.init | 3 + - net/miniupnpd/files/upnpd.config | 1 + - ...301-options-force_forwarding-support.patch | 209 ++++++++++++++++++ - 3 files changed, 213 insertions(+) - create mode 100644 net/miniupnpd/patches/301-options-force_forwarding-support.patch - -diff --git a/net/miniupnpd/files/miniupnpd.init b/net/miniupnpd/files/miniupnpd.init -index c5a14ab..5a0696f 100644 ---- a/net/miniupnpd/files/miniupnpd.init -+++ b/net/miniupnpd/files/miniupnpd.init -@@ -63,6 +63,7 @@ upnpd() { - local use_stun stun_host stun_port uuid notify_interval presentation_url - local upnp_lease_file clean_ruleset_threshold clean_ruleset_interval - local ipv6_disable -+ local force_forwarding - - local enabled - config_get_bool enabled config enabled 1 -@@ -90,6 +91,7 @@ upnpd() { - config_get clean_ruleset_threshold config clean_ruleset_threshold - config_get clean_ruleset_interval config clean_ruleset_interval - config_get ipv6_disable config ipv6_disable 0 -+ config_get force_forwarding config force_forwarding 0 - - local conf ifname ifname6 - -@@ -142,6 +144,7 @@ upnpd() { - upnpd_write_bool igdv1 0 force_igd_desc_v1 - upnpd_write_bool use_stun 0 ext_perform_stun - upnpd_write_bool ipv6_disable $ipv6_disable -+ upnpd_write_bool force_forwarding $force_forwarding - - [ "$use_stun" -eq 0 ] || { - [ -n "$stun_host" ] && echo "ext_stun_host=$stun_host" -diff --git a/net/miniupnpd/files/upnpd.config b/net/miniupnpd/files/upnpd.config -index bd7c3ec..b03d60a 100644 ---- a/net/miniupnpd/files/upnpd.config -+++ b/net/miniupnpd/files/upnpd.config -@@ -2,6 +2,7 @@ config upnpd config - option enabled 0 - option enable_natpmp 1 - option enable_upnp 1 -+ option force_forwarding 0 - option secure_mode 1 - option log_output 0 - option download 1024 -diff --git a/net/miniupnpd/patches/301-options-force_forwarding-support.patch b/net/miniupnpd/patches/301-options-force_forwarding-support.patch -new file mode 100644 -index 000000000..ecd4b34c4 ---- /dev/null -+++ b/net/miniupnpd/patches/301-options-force_forwarding-support.patch -@@ -0,0 +1,185 @@ -+From 09690d550a1ad3cc3a8cba79aa2e970c3b2b8fbe Mon Sep 17 00:00:00 2001 -+From: Chen Minqiang -+Date: Sun, 5 Jul 2020 10:42:52 +0800 -+Subject: [PATCH] options: force_forwarding support -+ -+This make the port forwarding force to work even -+when the router is behind NAT -+ -+Signed-off-by: Chen Minqiang -+--- -+ miniupnpd.c | 12 ++++++++---- -+ miniupnpd.conf | 2 ++ -+ natpmp.c | 2 +- -+ options.c | 1 + -+ options.h | 1 + -+ testgetifaddr.c | 2 ++ -+ testportinuse.c | 2 ++ -+ upnpdescgen.c | 2 +- -+ upnpglobalvars.h | 2 ++ -+ upnpredirect.c | 2 +- -+ upnpsoap.c | 6 +++++- -+ 11 files changed, 26 insertions(+), 8 deletions(-) -+ -+--- a/miniupnpd.c -++++ b/miniupnpd.c -+@@ -1010,7 +1010,7 @@ parselanaddr(struct lan_addr_s * lan_add -+ INIT_PRINT_ERR("Error parsing address : %s\n", lan_addr->ext_ip_str); -+ return -1; -+ } -+- if(addr_is_reserved(&lan_addr->ext_ip_addr)) { -++ if(addr_is_reserved(&lan_addr->ext_ip_addr) && !GETFLAG(FORCEFORWARDINGMASK)) { -+ /* error */ -+ INIT_PRINT_ERR("Error: option ext_ip address contains reserved / private address : %s\n", lan_addr->ext_ip_str); -+ return -1; -+@@ -1252,6 +1252,10 @@ init(int argc, char * * argv, struct run -+ case UPNPEXT_IP: -+ use_ext_ip_addr = ary_options[i].value; -+ break; -++ case UPNP_FORCE_FORWARDING: -++ if(strcmp(ary_options[i].value, "yes") == 0) -++ SETFLAG(FORCEFORWARDINGMASK); -++ break; -+ case UPNPEXT_PERFORM_STUN: -+ if(strcmp(ary_options[i].value, "yes") == 0) -+ SETFLAG(PERFORMSTUNMASK); -+@@ -1859,7 +1863,7 @@ init(int argc, char * * argv, struct run -+ INIT_PRINT_ERR("Error: option ext_ip contains invalid address %s\n", use_ext_ip_addr); -+ return 1; -+ } -+- if (addr_is_reserved(&addr)) { -++ if (addr_is_reserved(&addr) && !GETFLAG(FORCEFORWARDINGMASK)) { -+ INIT_PRINT_ERR("Error: option ext_ip contains reserved / private address %s, not public routable\n", use_ext_ip_addr); -+ return 1; -+ } -+@@ -2305,7 +2309,7 @@ main(int argc, char * * argv) -+ if (getifaddr(ext_if_name, if_addr, INET_ADDRSTRLEN, &addr, NULL) < 0) { -+ syslog(LOG_WARNING, "Cannot get IP address for ext interface %s. Network is down", ext_if_name); -+ disable_port_forwarding = 1; -+- } else if (addr_is_reserved(&addr)) { -++ } else if (addr_is_reserved(&addr) && !GETFLAG(FORCEFORWARDINGMASK)) { -+ syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name); -+ syslog(LOG_INFO, "You are probably behind NAT, enable option ext_perform_stun=yes to detect public IP address"); -+ syslog(LOG_INFO, "Or use ext_ip= / -o option to declare public IP address"); -+@@ -2596,7 +2600,7 @@ main(int argc, char * * argv) -+ syslog(LOG_WARNING, "Cannot get IP address for ext interface %s. Network is down", ext_if_name); -+ disable_port_forwarding = 1; -+ } else { -+- int reserved = addr_is_reserved(&addr); -++ int reserved = addr_is_reserved(&addr) && !GETFLAG(FORCEFORWARDINGMASK); -+ if (!disable_port_forwarding && reserved) { -+ syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name); -+ syslog(LOG_INFO, "You are probably behind NAT, enable option ext_perform_stun=yes to detect public IP address"); -+--- a/miniupnpd.conf -++++ b/miniupnpd.conf -+@@ -12,6 +12,9 @@ -+ # the public IP address. -+ #ext_ip= -+ -++# force forwarding enable for upnp: default is no -++#force_forwarding=yes -++ -+ # WAN interface must have public IP address. Otherwise it is behind NAT -+ # and port forwarding is impossible. In some cases WAN interface can be -+ # behind unrestricted full-cone NAT 1:1 when all incoming traffic is NAT-ed and -+--- a/natpmp.c -++++ b/natpmp.c -+@@ -109,7 +109,7 @@ static void FillPublicAddressResponse(un -+ syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name); -+ resp[3] = 3; /* Network Failure (e.g. NAT box itself -+ * has not obtained a DHCP lease) */ -+- } else if (addr_is_reserved(&addr)) { -++ } else if (addr_is_reserved(&addr) && !GETFLAG(FORCEFORWARDINGMASK)) { -+ resp[3] = 3; /* Network Failure, box has not obtained -+ public IP address */ -+ } else { -+--- a/options.c -++++ b/options.c -+@@ -35,6 +35,7 @@ static const struct { -+ { UPNPEXT_IFNAME6, "ext_ifname6" }, -+ #endif -+ { UPNPEXT_IP, "ext_ip" }, -++ { UPNP_FORCE_FORWARDING, "force_forwarding" }, -+ { UPNPEXT_PERFORM_STUN, "ext_perform_stun" }, -+ { UPNPEXT_STUN_HOST, "ext_stun_host" }, -+ { UPNPEXT_STUN_PORT, "ext_stun_port" }, -+--- a/options.h -++++ b/options.h -+@@ -21,6 +21,7 @@ enum upnpconfigoptions { -+ UPNPEXT_IFNAME6, /* ext_ifname6 */ -+ #endif -+ UPNPEXT_IP, /* ext_ip */ -++ UPNP_FORCE_FORWARDING, /* force forwarding enable for upnp */ -+ UPNPEXT_PERFORM_STUN, /* ext_perform_stun */ -+ UPNPEXT_STUN_HOST, /* ext_stun_host */ -+ UPNPEXT_STUN_PORT, /* ext_stun_port */ -+--- a/testgetifaddr.c -++++ b/testgetifaddr.c -+@@ -13,6 +13,8 @@ -+ #include "config.h" -+ #include "getifaddr.h" -+ -++int runtime_flags = 0; -++ -+ #if defined(__sun) -+ /* solaris 10 does not define LOG_PERROR */ -+ #define LOG_PERROR 0 -+--- a/testportinuse.c -++++ b/testportinuse.c -+@@ -14,6 +14,8 @@ -+ #include "config.h" -+ #include "portinuse.h" -+ -++int runtime_flags = 0; -++ -+ int main(int argc, char * * argv) -+ { -+ #ifndef CHECK_PORTINUSE -+--- a/upnpdescgen.c -++++ b/upnpdescgen.c -+@@ -1316,7 +1316,7 @@ genEventVars(int * len, const struct ser -+ else { -+ struct in_addr addr; -+ char ext_ip_addr[INET_ADDRSTRLEN]; -+- if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, &addr, NULL) < 0 || addr_is_reserved(&addr)) { -++ if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, &addr, NULL) < 0 || (addr_is_reserved(&addr) && !GETFLAG(FORCEFORWARDINGMASK))) { -+ str = strcat_str(str, len, &tmplen, "0.0.0.0"); -+ } else { -+ str = strcat_str(str, len, &tmplen, ext_ip_addr); -+--- a/upnpglobalvars.h -++++ b/upnpglobalvars.h -+@@ -87,6 +87,8 @@ extern int runtime_flags; -+ -+ #define PERFORMSTUNMASK 0x1000 -+ -++#define FORCEFORWARDINGMASK 0x2000 -++ -+ #define SETFLAG(mask) runtime_flags |= mask -+ #define GETFLAG(mask) (runtime_flags & mask) -+ #define CLEARFLAG(mask) runtime_flags &= ~mask -+--- a/upnpredirect.c -++++ b/upnpredirect.c -+@@ -444,7 +444,7 @@ upnp_redirect_internal(const char * rhos -+ { -+ /*syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s", -+ eport, iaddr, iport, protocol, desc); */ -+- if(disable_port_forwarding) -++ if(disable_port_forwarding && !GETFLAG(FORCEFORWARDINGMASK)) -+ return -1; -+ if(add_redirect_rule2(ext_if_name, rhost, eport, iaddr, iport, proto, -+ desc, timestamp) < 0) { -+--- a/upnpsoap.c -++++ b/upnpsoap.c -+@@ -348,7 +348,11 @@ GetExternalIPAddress(struct upnphttp * h -+ ext_ip_addr[0] = '\0'; -+ } else if (addr_is_reserved(&addr)) { -+ syslog(LOG_NOTICE, "private/reserved address %s is not suitable for external IP", ext_ip_addr); -+- ext_ip_addr[0] = '\0'; -++ if (!GETFLAG(FORCEFORWARDINGMASK)) { -++ ext_ip_addr[0] = '\0'; -++ } else { -++ syslog(LOG_NOTICE, "force_forwarding enable, private/reserved address %s used as external IP", ext_ip_addr); -++ } -+ } -+ } -+ #else --- -2.39.3 - diff --git a/openwrt/patch/miniupnpd/04-enable-force_forwarding-by-default.patch b/openwrt/patch/miniupnpd/04-enable-force_forwarding-by-default.patch deleted file mode 100644 index 61c88897b..000000000 --- a/openwrt/patch/miniupnpd/04-enable-force_forwarding-by-default.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/net/miniupnpd/files/upnpd.config b/net/miniupnpd/files/upnpd.config -index b03d60a..9070c27 100644 ---- a/net/miniupnpd/files/upnpd.config -+++ b/net/miniupnpd/files/upnpd.config -@@ -2,7 +2,7 @@ config upnpd config - option enabled 0 - option enable_natpmp 1 - option enable_upnp 1 -- option force_forwarding 0 -+ option force_forwarding 1 - option secure_mode 1 - option log_output 0 - option download 1024 diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 8c9173b34..87397e459 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -361,18 +361,9 @@ sed -i 's/procd_set_param stdout 1/procd_set_param stdout 0/g' feeds/packages/ut sed -i 's/procd_set_param stderr 1/procd_set_param stderr 0/g' feeds/packages/utils/ttyd/files/ttyd.init # UPnP -rm -rf feeds/packages/net/miniupnpd -git clone https://$gitea/sbwml/miniupnpd feeds/packages/net/miniupnpd -b v2.3.6 -rm -rf feeds/luci/applications/luci-app-upnp -git clone https://$gitea/sbwml/luci-app-upnp feeds/luci/applications/luci-app-upnp -pushd feeds/packages - curl -s https://$mirror/openwrt/patch/miniupnpd/01-set-presentation_url.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/miniupnpd/02-force_forwarding.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/miniupnpd/04-enable-force_forwarding-by-default.patch | patch -p1 -popd - -# UPnP - Move to network -sed -i 's/services/network/g' feeds/luci/applications/luci-app-upnp/root/usr/share/luci/menu.d/luci-app-upnp.json +rm -rf feeds/{packages/net/miniupnpd,luci/applications/luci-app-upnp} +git clone https://$gitea/sbwml/miniupnpd feeds/packages/net/miniupnpd -b v2.3.7 +git clone https://$gitea/sbwml/luci-app-upnp feeds/luci/applications/luci-app-upnp -b main # nginx-util - fix gcc13 if [ "$version" = "rc2" ]; then From ff56ac80ed8e144fabe5552fdca68049c0038b5c Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 15 Oct 2024 16:22:39 +0800 Subject: [PATCH 064/425] linux-6.12: bump to 6.12rc3 Signed-off-by: sbwml --- README.md | 12 +++++++----- openwrt/build.sh | 14 +++++++------- ...den-app-limited-rate-sample-detectio.patch | 2 +- ...napshot-packets-in-flight-at-transmi.patch | 2 +- ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 2 +- ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 2 +- ...ecord-app-limited-status-of-TLP-repa.patch | 2 +- ...nform-CC-module-of-losses-repaired-b.patch | 2 +- ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 8 ++++---- ...-scheduler-add-entropy-sampling-hook.patch | 2 +- ...-linux-kernel-to-support-shortcut-fe.patch | 6 +++--- openwrt/scripts/00-prepare_base.sh | 19 ++++++++++--------- openwrt/scripts/01-prepare_base-mainline.sh | 14 +++++++------- openwrt/scripts/04-fix_kmod.sh | 10 +++------- tags/kernel-6.12 | 4 ++-- 15 files changed, 50 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index e6419b747..a16f91f1c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ --------------- -## 基于 Linux 6.6 LTS 固件下载: +## 基于 Linux 6.6/6.12 LTS 固件下载: #### NanoPi R4S: https://r4s.cooluc.com @@ -12,6 +12,8 @@ #### X86_64: https://x86.cooluc.com +#### Snapshot 24.10: https://snapshot.cooluc.com + #### 构建来源: https://github.com/sbwml/builder --------------- @@ -149,23 +151,23 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r5s bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 x86_64 ``` -## 构建 OpenWrt 23.05 开发版(23.05-SNAPSHOT) +## 构建 OpenWrt 24.10 开发版(24.10-SNAPSHOT) ### nanopi-r4s ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r4s ``` ### nanopi-r5s/r5c ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r5s ``` ### x86_64 ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 ``` diff --git a/openwrt/build.sh b/openwrt/build.sh index 0e4c25c8b..590ea4520 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -129,11 +129,10 @@ export \ ENABLE_DPDK=$ENABLE_DPDK \ ENABLE_GLIBC=$ENABLE_GLIBC \ ENABLE_LRNG=$ENABLE_LRNG \ - KERNEL_CLANG_LTO=$KERNEL_CLANG_LTO \ - TESTING_KERNEL=$TESTING_KERNEL \ + KERNEL_CLANG_LTO=$KERNEL_CLANG_LTO # kernel version -[ "$TESTING_KERNEL" = "y" ] && export kernel_version=6.12 || export kernel_version=6.6 +[ "$version" = "snapshots-24.10" ] && export kernel_version=6.12 || export kernel_version=6.6 # print version echo -e "\r\n${GREEN_COLOR}Building $branch${RES}\r\n" @@ -154,7 +153,7 @@ else fi get_kernel_version=$(curl -s https://$mirror/tags/kernel-$kernel_version) kmod_hash=$(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}' | tail -1 | md5sum | awk '{print $1}') -if [ "$TESTING_KERNEL" = "y" ]; then +if [ "$version" = "snapshots-24.10" ]; then kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) else kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')-1-$(echo $kmod_hash)) @@ -386,9 +385,10 @@ fi # uhttpd [ "$ENABLE_UHTTPD" = "y" ] && sed -i '/nginx/d' .config && echo 'CONFIG_PACKAGE_ariang=y' >> .config -# test kernel -[ "$TESTING_KERNEL" = "y" ] && [ "$platform" = "bcm53xx" ] && sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config -[ "$TESTING_KERNEL" = "y" ] && sed -i '1i\# Test kernel\nCONFIG_TESTING_KERNEL=y\n' .config +# snapshots-24.10 +[ "$version" = "snapshots-24.10" ] && [ "$platform" = "bcm53xx" ] && sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config +[ "$version" = "snapshots-24.10" ] && sed -i '1i\# Test kernel\nCONFIG_TESTING_KERNEL=y\n' .config +[ "$version" = "rc2" ] && sed -i '/CONFIG_TESTING_KERNEL/d' .config # not all kmod [ "$NO_KMOD" = "y" ] && sed -i '/CONFIG_ALL_KMODS=y/d; /CONFIG_ALL_NONSHARED=y/d' .config diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index 9ad100372..a24a92864 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -32,7 +32,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3934,6 +3934,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -3961,6 +3961,7 @@ static int tcp_ack(struct sock *sk, cons prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; rs.prior_in_flight = tcp_packets_in_flight(tp); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index f9122447e..85828bb6f 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -56,7 +56,7 @@ Signed-off-by: Alexandre Frade struct rate_sample *rs); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2768,6 +2768,7 @@ static bool tcp_write_xmit(struct sock * +@@ -2765,6 +2765,7 @@ static bool tcp_write_xmit(struct sock * skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); tcp_init_tso_segs(skb, mss_now); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index 9ad86848c..fcf83ac0a 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -28,7 +28,7 @@ Signed-off-by: Alexandre Frade struct tcp_congestion_ops { --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4033,6 +4033,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4060,6 +4060,7 @@ static int tcp_ack(struct sock *sk, cons delivered = tcp_newly_delivered(sk, delivered, flag); lost = tp->lost - lost; /* freshly marked lost */ rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 8d2218476..8a0d95145 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5743,13 +5743,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5770,13 +5770,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch index 35cd6d0f1..244903840 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -3006,6 +3006,7 @@ void tcp_send_loss_probe(struct sock *sk +@@ -3003,6 +3003,7 @@ void tcp_send_loss_probe(struct sock *sk if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index 21a505ac8..8ff806a39 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3832,6 +3832,7 @@ static void tcp_process_tlp_ack(struct s +@@ -3859,6 +3859,7 @@ static void tcp_process_tlp_ack(struct s /* ACK advances: there was a loss, so reduce cwnd. Reset * tlp_high_seq in tcp_init_cwnd_reduction() */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index 8a6829803..fed5a4aeb 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3815,7 +3815,8 @@ static void tcp_replace_ts_recent(struct +@@ -3842,7 +3842,8 @@ static void tcp_replace_ts_recent(struct /* This routine deals with acks during a TLP episode and ends an episode by * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack */ @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade { struct tcp_sock *tp = tcp_sk(sk); -@@ -3843,6 +3844,11 @@ static void tcp_process_tlp_ack(struct s +@@ -3870,6 +3871,11 @@ static void tcp_process_tlp_ack(struct s FLAG_NOT_DUP | FLAG_DATA_SACKED))) { /* Pure dupack: original and TLP probe arrived; no loss */ tp->tlp_high_seq = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade } } -@@ -4026,7 +4032,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4053,7 +4059,7 @@ static int tcp_ack(struct sock *sk, cons tcp_rack_update_reo_wnd(sk, &rs); if (tp->tlp_high_seq) @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade if (tcp_ack_is_dubious(sk, flag)) { if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4070,7 +4076,7 @@ no_queue: +@@ -4097,7 +4103,7 @@ no_queue: tcp_ack_probe(sk); if (tp->tlp_high_seq) diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch index 53a43adc5..3bef4a7fe 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -24,7 +24,7 @@ Signed-off-by: Stephan Mueller #include #include #include -@@ -3604,6 +3605,8 @@ ttwu_stat(struct task_struct *p, int cpu +@@ -3606,6 +3607,8 @@ ttwu_stat(struct task_struct *p, int cpu { struct rq *rq; diff --git a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 70dcf3b0c..683f04974 100644 --- a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -111,7 +111,7 @@ Signed-off-by: Xiaoping Fan len = skb->len; trace_net_dev_start_xmit(skb, dev); -@@ -5409,6 +5418,11 @@ void netdev_rx_handler_unregister(struct +@@ -5413,6 +5422,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5457,6 +5471,10 @@ static int __netif_receive_skb_core(stru +@@ -5461,6 +5475,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5495,6 +5513,16 @@ another_round: +@@ -5499,6 +5517,16 @@ another_round: goto out; } diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 87397e459..f79f44655 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -50,11 +50,12 @@ curl -s https://$mirror/openwrt/patch/$generic/0010-include-kernel-add-miss-conf # meson: add platform variable to cross-compilation file curl -s https://$mirror/openwrt/patch/$generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 -# kernel 6.12: add legacy cgroup v1 memory controller -[ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/$generic/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 - -# kernel 6.12: add linux-rt support for aarch64/x86_64 -[ "$version" = "snapshots-24.10" ] && [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/$generic/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch | patch -p1 +if [ "$version" = "snapshots-24.10" ]; then + # kernel 6.12: add legacy cgroup v1 memory controller + curl -s https://$mirror/openwrt/patch/$generic/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 + # kernel 6.12: add linux-rt support for aarch64/x86_64 + curl -s https://$mirror/openwrt/patch/$generic/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch | patch -p1 +fi # mold if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then @@ -200,7 +201,7 @@ if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then # fullcone curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch # bcm fullcone - [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch # kernel version curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch > package/network/config/firewall4/patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch # fix flow offload @@ -212,14 +213,14 @@ if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/libs/libnftnl package/libs/libnftnl mkdir -p package/libs/libnftnl/patches curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/001-libnftnl-add-fullcone-expression-support.patch - [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch sed -i '/PKG_INSTALL:=1/iPKG_FIXUP:=autoreconf' package/libs/libnftnl/Makefile # nftables [ "$version" = "rc2" ] && rm -rf package/network/utils/nftables [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/network/utils/nftables package/network/utils/nftables mkdir -p package/network/utils/nftables/patches curl -s https://$mirror/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/002-nftables-add-fullcone-expression-support.patch - [ "$TESTING_KERNEL" != "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch + [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch # hide nftables warning message pushd feeds/luci curl -s https://$mirror/openwrt/patch/luci/luci-nftables.patch | patch -p1 @@ -242,7 +243,7 @@ pushd feeds/luci curl -s https://$mirror/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 - [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 + [ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 popd # openssl - quictls diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 4744305d8..a6eeaa92c 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -120,7 +120,7 @@ pushd target/linux/generic/backport-"$kernel_version" curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch - [ "$TESTING_KERNEL" = "y" ] && curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch + [ "$version" = "snapshots-24.10" ] && curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch popd # LRNG v54/56 - linux-6.6/6.12 @@ -153,7 +153,7 @@ pushd target/linux/generic/hack-$kernel_version popd # linux-rt - i915 -if [ "$TESTING_KERNEL" = "y" ]; then +if [ "$version" = "snapshots-24.10" ]; then pushd target/linux/generic/hack-6.12 curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch @@ -170,7 +170,7 @@ fi rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware -if [ "$TESTING_KERNEL" = "y" ]; then +if [ "$version" = "snapshots-24.10" ]; then # rtl8812au-ct - fix linux-6.12 rm -rf package/kernel/rtl8812au-ct git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct -b v6.11 @@ -188,7 +188,7 @@ fi rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile -[ "$TESTING_KERNEL" = "y" ] && { +[ "$version" = "snapshots-24.10" ] && { curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch curl -s https://$mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch } @@ -214,7 +214,7 @@ curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > pa rm -rf package/kernel/mac80211 if [ "$version" = "rc2" ]; then git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 - [ "$TESTING_KERNEL" = "y" ] && rm -f package/kernel/mac80211/patches/build/140-trace_backport.patch + [ "$version" = "snapshots-24.10" ] && rm -f package/kernel/mac80211/patches/build/140-trace_backport.patch else git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 fi @@ -231,7 +231,7 @@ curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/arm64/312-arm64-cpu # fullcone curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-$kernel_version/952-net-conntrack-events-support-multiple-registrant.patch # bcm-fullcone -[ "$TESTING_KERNEL" != "y" ] && { +[ "$version" = "rc2" ] && { curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-$kernel_version/982-add-bcm-fullcone-support.patch curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-$kernel_version/983-add-bcm-fullcone-nft_masq-support.patch } @@ -239,7 +239,7 @@ curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/952-net-conntra curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-$kernel_version/601-netfilter-export-udp_get_timeouts-function.patch curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-$kernel_version/953-net-patch-linux-kernel-to-support-shortcut-fe.patch # backport - 6.8 fast-path-variables -if [ "$version" = "rc2" ] && [ "$platform" != "bcm53xx" ] && [ "$TESTING_KERNEL" != "y" ]; then +if [ "$version" = "rc2" ] && [ "$platform" != "bcm53xx" ]; then curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch > target/linux/generic/backport-6.6/901-v6.8-cache-enforce-cache-groups.patch curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch > target/linux/generic/backport-6.6/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch > target/linux/generic/backport-6.6/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index b775b95d3..a8798ff6c 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -71,14 +71,10 @@ if [ "$version" = "rc2" ]; then fi # openvswitch -if [ "$TESTING_KERNEL" = "y" ]; then - sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile -fi +[ "$version" = "snapshots-24.10" ] && sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile # rtpengine -if [ "$TESTING_KERNEL" = "y" ] && [ "$version" = "snapshots-24.10" ]; then - curl -s https://$mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch -fi +[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch # ubootenv-nvram - 6.12 (openwrt-23.05.5) mkdir -p package/kernel/ubootenv-nvram/patches @@ -91,7 +87,7 @@ pushd feeds/packages # fix linux-6.6 [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch > libs/xr_usb_serial_common/patches/900-fix-linux-6.6.patch # fix linux-6.12 - [ "$TESTING_KERNEL" = "y" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch + [ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch # coova-chilli [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/9975e855adcfc24939080a5e0279e0a90553347b.patch | patch -p1 [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/c0683d3f012096fc7b2fbe8b8dc81ea424945e9b.patch | patch -p1 diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 340fa590f..0cde4d606 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -rc2 -LINUX_KERNEL_HASH-6.12-rc2 = 36efbb865ead39771f63ecad7a26adf3dc7de93e27932e59dda81a0bda556b91 +LINUX_VERSION-6.12 = -rc3 +LINUX_KERNEL_HASH-6.12-rc3 = c9b271cc559588796a80f06f4198a4de2823bc28cb5cd2632f3b80401035b91d From c68a060d323e82f305d8323dbc79ecdfeb605708 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 15 Oct 2024 16:41:06 +0800 Subject: [PATCH 065/425] docs: update build parameters Signed-off-by: sbwml --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index a16f91f1c..54358c295 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,22 @@ export MINIMAL_BUILD=y export LAN=10.0.0.1 ``` +### 使用 uhttpd 轻量 web 引擎 +##### 固件默认使用 Nginx(quic) 作为页面引擎,只需在构建固件前执行以下命令即可使用 uhttpd 取代 nginx +##### Nginx 在具备公网的环境下可以提供更丰富的功能支持 + +``` +export ENABLE_UHTTPD=y +``` + +### 禁用全模块编译(For developers) +##### 启用该标志时,固件仅编译 config 指定的软件包和内核模块,但固件不再支持安装内核模块(opkg install kmod-xxx),强制安装模块将会导致内核崩溃 +##### 最大的可能性降低 OpenWrt 的编译耗时,适用于开发者调试构建 + +``` +export NO_KMOD=y +``` + --------------- ## 构建 OpenWrt 23.05 最新 Releases From f5469e7137e02ad5f06a5d0449437ded1094dc30 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 17 Oct 2024 02:52:29 +0800 Subject: [PATCH 066/425] openwrt-24.10: refresh patches Signed-off-by: sbwml --- ...-Add-support-for-llvm-clang-compiler.patch | 41 ++++--------------- ...EEMPT_RT-support-for-aarch64-x86_64.patch} | 6 +-- openwrt/scripts/00-prepare_base.sh | 2 +- 3 files changed, 13 insertions(+), 36 deletions(-) rename openwrt/patch/generic-24.10/{0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch => 0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch} (89%) diff --git a/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch index 5c707ef35..9a46f8425 100644 --- a/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch +++ b/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch @@ -1,15 +1,14 @@ -From ae3e66eb2cca2e1642d4a4816241bfffe488fff8 Mon Sep 17 00:00:00 2001 +From e13ed92005152ae050d4a35f6912547ebe259847 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:51:22 +0800 -Subject: [PATCH 07/11] kernel: Add support for llvm/clang compiler +Subject: [PATCH 07/13] kernel: Add support for llvm/clang compiler Signed-off-by: sbwml --- - config/Config-devel.in | 7 +++++++ - include/kernel-defaults.mk | 11 +++++++++++ - include/kernel.mk | 13 ++++++++++++- - include/package.mk | 4 ++++ - 4 files changed, 34 insertions(+), 1 deletion(-) + config/Config-devel.in | 7 +++++++ + include/kernel.mk | 13 ++++++++++++- + include/package.mk | 4 ++++ + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/config/Config-devel.in b/config/Config-devel.in index cbac91c..9079303 100644 @@ -29,30 +28,8 @@ index cbac91c..9079303 100644 config EXTERNAL_KERNEL_TREE string "Use external kernel tree" if DEVEL default "" -diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index f94ed33..c4a042b 100644 ---- a/include/kernel-defaults.mk -+++ b/include/kernel-defaults.mk -@@ -9,6 +9,17 @@ endif - - INITRAMFS_EXTRA_FILES ?= $(GENERIC_PLATFORM_DIR)/image/initramfs-base-files.txt - -+ifneq (,$(findstring clang,$(KERNEL_CC))) -+ ifneq (,$(filter clang-%,$(KERNEL_CC))) -+ LLVM := $(subst clang-,,$(KERNEL_CC)) -+ LLVM_LLD := ld.lld-$(subst clang-,,$(KERNEL_CC)) -+ else -+ LLVM := 1 -+ LLVM_LLD := ld.lld -+ endif -+ KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)" LD="$(LLVM_LLD)" LD=ld.lld LLVM=$(LLVM) LLVM_IAS=1 -+endif -+ - export HOST_EXTRACFLAGS=-I$(STAGING_DIR_HOST)/include - - # defined in quilt.mk diff --git a/include/kernel.mk b/include/kernel.mk -index 6ef7663..4f89d9f 100644 +index 6ef7663..1648a6f 100644 --- a/include/kernel.mk +++ b/include/kernel.mk @@ -35,7 +35,7 @@ else @@ -76,7 +53,7 @@ index 6ef7663..4f89d9f 100644 + LLVM := 1 + LLVM_LLD := ld.lld + endif -+ KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)" LD="$(LLVM_LLD)" LLVM=$(LLVM) LLVM_IAS=1 ++ KERNEL_MAKE_FLAGS += LD="$(LLVM_LLD)" LLVM=$(LLVM) LLVM_IAS=1 +endif + KERNEL_NOSTDINC_FLAGS = \ @@ -98,5 +75,5 @@ index 7fbecf9..3e988ed 100644 __unknown_flags=$(filter-out no-iremap no-mips16 gc-sections no-gc-sections lto no-lto no-mold,$(PKG_BUILD_FLAGS)) ifneq ($(__unknown_flags),) -- -2.43.5 +2.42.0 diff --git a/openwrt/patch/generic-24.10/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch b/openwrt/patch/generic-24.10/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch similarity index 89% rename from openwrt/patch/generic-24.10/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch rename to openwrt/patch/generic-24.10/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch index 74af18b61..eebac8923 100644 --- a/openwrt/patch/generic-24.10/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch +++ b/openwrt/patch/generic-24.10/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch @@ -1,7 +1,7 @@ -From bd8a486bf2a805a7783b3a3e329b5756c1ff6127 Mon Sep 17 00:00:00 2001 +From 79b76c15bb981843e7a08f0c906c013e96a02d2e Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 12 Oct 2024 08:36:46 +0800 -Subject: [PATCH] kernel: add PREEMPT_RT support for aarch64/x86_64 +Subject: [PATCH 13/13] kernel: add PREEMPT_RT support for aarch64/x86_64 Signed-off-by: sbwml --- @@ -33,5 +33,5 @@ index 39a9730..5439219 100644 bool "Enable support for printk" default y -- -2.43.5 +2.42.0 diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index f79f44655..a23f59075 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -54,7 +54,7 @@ if [ "$version" = "snapshots-24.10" ]; then # kernel 6.12: add legacy cgroup v1 memory controller curl -s https://$mirror/openwrt/patch/$generic/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 # kernel 6.12: add linux-rt support for aarch64/x86_64 - curl -s https://$mirror/openwrt/patch/$generic/0013-kernel-add-linux-rt-support-for-aarch64-x86_64.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/$generic/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 fi # mold From 705d4aa7670f4da13250b9df2c63ad00534a4708 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 17 Oct 2024 03:03:59 +0800 Subject: [PATCH 067/425] toolchain: GCC 15-20241013 Snapshot * This snapshot has been generated from the GCC 15 git branch with the following options: git://gcc.gnu.org/git/gcc.git branch master revision 27f6b376e8e196c7c85c8b47436cd2f2993768da Signed-off-by: sbwml --- .../202-toolchain-gcc-add-support-for-GCC-15.patch | 2 +- .../generic/202-toolchain-gcc-add-support-for-GCC-15.patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch index d76ba43d0..70fb33cad 100644 --- a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -68,7 +68,7 @@ index 0ccf55b..e1b760d 100644 endif +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=56d5e11d0c75077f8c556e57f2f317d9d324b28070a868fc85dc1108bd0508b3 ++ PKG_HASH:=3683fe2ee97d41007fb5fc2f9eb1d4701715ee440920b5765e8c772e088e1021 +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x diff --git a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch index ab5aef54f..f465118ef 100644 --- a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -67,7 +67,7 @@ index a1a5108..feae36a 100644 endif +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=56d5e11d0c75077f8c556e57f2f317d9d324b28070a868fc85dc1108bd0508b3 ++ PKG_HASH:=3683fe2ee97d41007fb5fc2f9eb1d4701715ee440920b5765e8c772e088e1021 +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x From 28e28a12e8a25e2929de434429b884efa5ae2049 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 17 Oct 2024 09:01:32 +0800 Subject: [PATCH 068/425] batman-adv: fix build latest version Signed-off-by: sbwml --- ...-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch | 16 ---------------- openwrt/scripts/04-fix_kmod.sh | 1 - 2 files changed, 17 deletions(-) delete mode 100644 openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch diff --git a/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch b/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch deleted file mode 100644 index 5e622e0d0..000000000 --- a/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/net/batman-adv/soft-interface.c -+++ b/net/batman-adv/soft-interface.c -@@ -1020,8 +1020,13 @@ static void batadv_softif_init_early(str - dev->netdev_ops = &batadv_netdev_ops; - dev->needs_free_netdev = true; - dev->priv_destructor = batadv_softif_free; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) -+ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | dev->netns_local; -+ dev->features |= dev->lltx; -+#else - dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL; - dev->features |= NETIF_F_LLTX; -+#endif - dev->priv_flags |= IFF_NO_QUEUE; - - /* can't call min_mtu, because the needed variables diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index a8798ff6c..1403b6358 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -114,7 +114,6 @@ if [ "$version" = "rc2" ]; then cp -a ../master/routing/batman-adv feeds/routing/batman-adv fi # fix build with linux-6.12 -curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch > feeds/routing/batman-adv/patches/900-netdev_features-convert-NETIF_F_NETNS_LOCAL-to-dev-netns_local.patch curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch > feeds/routing/batman-adv/patches/901-fix-linux-6.12rc2-builds.patch # bcm53xx From d58b0d08d8559531e4196527e7b6717ff98da3f3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 18 Oct 2024 03:38:35 +0800 Subject: [PATCH 069/425] linux-6.6: bump to 6.6.57 Signed-off-by: sbwml --- tags/kernel-6.6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index 6f72804b8..a5048a4e6 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .56 -LINUX_KERNEL_HASH-6.6.56 = f74812f78e88992c416434cb107639e13a551dbaff36bb90d6346ab16ab71a95 +LINUX_VERSION-6.6 = .57 +LINUX_KERNEL_HASH-6.6.57 = 66ce426ef96f99b8e1ef7ac72e780c730ef8b970f7aa5708501c4274d7abb7b3 From abb50d0f382e9ce745b934579bd67b163b4f82ad Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 18 Oct 2024 21:28:52 +0800 Subject: [PATCH 070/425] linux-6.12: cryptodev-linux: fix cryptodev_verbosity sysctl [ 12.029416] sysctl table check failed: ioctl/(null) procname is null [ 12.029429] sysctl table check failed: ioctl/(null) No proc_handler Signed-off-by: sbwml --- ..._verbosity-sysctl-for-Linux-6.11-rc1.patch | 37 ++++++++++++ ...xclude-unused-struct-since-Linux-6.5.patch | 58 +++++++++++++++++++ .../001-Fix-build-for-Linux-6.3-rc1.patch | 0 .../002-fix-build-for-linux-6.7-rc1.patch | 0 openwrt/scripts/04-fix_kmod.sh | 9 ++- 5 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch create mode 100644 openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch rename openwrt/patch/packages-patches/cryptodev-linux/{ => 6.6}/001-Fix-build-for-Linux-6.3-rc1.patch (100%) rename openwrt/patch/packages-patches/cryptodev-linux/{ => 6.6}/002-fix-build-for-linux-6.7-rc1.patch (100%) diff --git a/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch new file mode 100644 index 000000000..2ab956227 --- /dev/null +++ b/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch @@ -0,0 +1,37 @@ +From 3d256971a2a532c974b88418927dd3b3831c27cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= +Date: Fri, 19 Jul 2024 20:18:31 +0000 +Subject: [PATCH] Fix cryptodev_verbosity sysctl for Linux 6.11-rc1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There has been a long-running Linux kernel effort to get rid of the +sentinels of `struct ctl_table`. In Linux 6.11 it has been completed, +and registering a sysctl with a sentinel will fail with a dmesg error: + +> sysctl table check failed: ioctl/(null) procname is null +> sysctl table check failed: ioctl/(null) No proc_handler + +Exclude the sentinels since that version. + +See also: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f8a8b94d0698ccc56c44478169c91ca774540d9f + https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9edbfe92a0a1355bae1e47c8f542ac0d39f19f8c + +Signed-off-by: Joan Bruguera Micó +--- + ioctl.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/ioctl.c ++++ b/ioctl.c +@@ -1239,7 +1239,9 @@ static struct ctl_table verbosity_ctl_di + .mode = 0644, + .proc_handler = proc_dointvec, + }, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0)) + {}, ++#endif + }; + + static struct ctl_table verbosity_ctl_root[] = { diff --git a/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch new file mode 100644 index 000000000..c83d49d8e --- /dev/null +++ b/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch @@ -0,0 +1,58 @@ +From 2669a340472e89a521ac6fbc803961124311453b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= +Date: Fri, 19 Jul 2024 20:10:32 +0000 +Subject: [PATCH] Exclude unused struct since Linux >= 6.5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since Linux >= 6.5 we don't need `struct ctl_table verbosity_ctl_root`, +only the sysctl path, so move it to a constant and exclude the struct. + +This is just a cosmetic change, intended to make it clear that neither +the struct nor the sentinel that follows are needed on newer kernels. + +Signed-off-by: Joan Bruguera Micó +--- + ioctl.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/ioctl.c ++++ b/ioctl.c +@@ -1231,6 +1231,7 @@ cryptodev_deregister(void) + } + + /* ====== Module init/exit ====== */ ++static const char verbosity_ctl_path[] = "ioctl"; + static struct ctl_table verbosity_ctl_dir[] = { + { + .procname = "cryptodev_verbosity", +@@ -1244,16 +1245,16 @@ static struct ctl_table verbosity_ctl_di + #endif + }; + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) + static struct ctl_table verbosity_ctl_root[] = { + { +- .procname = "ioctl", ++ .procname = verbosity_ctl_path, + .mode = 0555, +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) + .child = verbosity_ctl_dir, +-#endif + }, + {}, + }; ++#endif + static struct ctl_table_header *verbosity_sysctl_header; + static int __init init_cryptodev(void) + { +@@ -1274,7 +1275,7 @@ static int __init init_cryptodev(void) + #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) + verbosity_sysctl_header = register_sysctl_table(verbosity_ctl_root); + #else +- verbosity_sysctl_header = register_sysctl(verbosity_ctl_root->procname, verbosity_ctl_dir); ++ verbosity_sysctl_header = register_sysctl(verbosity_ctl_path, verbosity_ctl_dir); + #endif + + pr_info(PFX "driver %s loaded.\n", VERSION); diff --git a/openwrt/patch/packages-patches/cryptodev-linux/001-Fix-build-for-Linux-6.3-rc1.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch similarity index 100% rename from openwrt/patch/packages-patches/cryptodev-linux/001-Fix-build-for-Linux-6.3-rc1.patch rename to openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch diff --git a/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch similarity index 100% rename from openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch rename to openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index 1403b6358..c2051d314 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -3,10 +3,13 @@ # Fix build for linux-6.6/6.12 # cryptodev-linux +mkdir -p package/kernel/cryptodev-linux/patches if [ "$version" = "rc2" ]; then - mkdir -p package/kernel/cryptodev-linux/patches - curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/001-Fix-build-for-Linux-6.3-rc1.patch > package/kernel/cryptodev-linux/patches/001-Fix-build-for-Linux-6.3-rc1.patch - curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/002-fix-build-for-linux-6.7-rc1.patch > package/kernel/cryptodev-linux/patches/002-fix-build-for-linux-6.7-rc1.patch + curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch > package/kernel/cryptodev-linux/patches/001-Fix-build-for-Linux-6.3-rc1.patch + curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch > package/kernel/cryptodev-linux/patches/002-fix-build-for-linux-6.7-rc1.patch +else + curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch + curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch > package/kernel/cryptodev-linux/patches/0006-Exclude-unused-struct-since-Linux-6.5.patch fi # gpio-button-hotplug From ec1fdfd863e6f2248aa77e9a1d9e9ec726ee6415 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 21 Oct 2024 02:37:28 +0800 Subject: [PATCH 071/425] config: disable linux-rt for now * disable linux-rt until Linux 6.12 becomes a stable version Signed-off-by: sbwml --- openwrt/23-config-musl-armsr-armv8 | 2 +- openwrt/23-config-musl-r4s | 2 +- openwrt/23-config-musl-r5s | 2 +- openwrt/23-config-musl-x86 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/23-config-musl-armsr-armv8 b/openwrt/23-config-musl-armsr-armv8 index 49a9ccf5e..4476b0d2e 100644 --- a/openwrt/23-config-musl-armsr-armv8 +++ b/openwrt/23-config-musl-armsr-armv8 @@ -9,7 +9,7 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y -CONFIG_KERNEL_PREEMPT_RT=y +# CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-r4s b/openwrt/23-config-musl-r4s index f093e8f85..60160bb86 100644 --- a/openwrt/23-config-musl-r4s +++ b/openwrt/23-config-musl-r4s @@ -9,7 +9,7 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y -CONFIG_KERNEL_PREEMPT_RT=y +# CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-r5s b/openwrt/23-config-musl-r5s index 15d81f0b8..a0fc3ee69 100644 --- a/openwrt/23-config-musl-r5s +++ b/openwrt/23-config-musl-r5s @@ -12,7 +12,7 @@ CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_CFLAGS="-march=armv8.2-a+crypto+crc -mcpu=cortex-a55+crypto+crc -mtune=cortex-a55" CONFIG_KERNEL_MEMCG_V1=y -CONFIG_KERNEL_PREEMPT_RT=y +# CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 854987ab5..22987a5ed 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -10,7 +10,7 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y -CONFIG_KERNEL_PREEMPT_RT=y +# CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-x86=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y From c7a5455151641839f67b5fc94d251a49103f6e8d Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Oct 2024 03:04:43 +0800 Subject: [PATCH 072/425] linux-6.12: bump to 6.12-rc4 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 0cde4d606..00fd26391 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -rc3 -LINUX_KERNEL_HASH-6.12-rc3 = c9b271cc559588796a80f06f4198a4de2823bc28cb5cd2632f3b80401035b91d +LINUX_VERSION-6.12 = -rc4 +LINUX_KERNEL_HASH-6.12-rc4 = 41356c3cac4b55170506629cab54f3a0ab5a57c0fd1f0e976dbbe66a0a74cc87 From 0cc0ad780989cd10ba5f92f0d7dd2cf6b66a6011 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Oct 2024 07:41:00 +0800 Subject: [PATCH 073/425] update mt76 & mac80211 Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 6 +++--- openwrt/patch/mt76/patches/100-api_update.patch | 11 ----------- openwrt/scripts/01-prepare_base-mainline.sh | 6 ++---- 3 files changed, 5 insertions(+), 18 deletions(-) delete mode 100644 openwrt/patch/mt76/patches/100-api_update.patch diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 070d0f3c2..7023d0047 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2024-09-29 -PKG_SOURCE_VERSION:=680bc70f161fde0f167e2ae50c771be4775eb50a -PKG_MIRROR_HASH:=bcdb95e40cfceba56a565ad6b6d9f92a122e7230d0f7f950b3d39e4280723cca +PKG_SOURCE_DATE:=2024-10-11 +PKG_SOURCE_VERSION:=ecca0e77b4bce629ec1f79d83bbd14a68f919188 +PKG_MIRROR_HASH:=a8852a446d4fbd7e022c669a3c574c8ba0cc1dcdc987c9d7d5a148113a71d842 PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 diff --git a/openwrt/patch/mt76/patches/100-api_update.patch b/openwrt/patch/mt76/patches/100-api_update.patch deleted file mode 100644 index 8b528f05f..000000000 --- a/openwrt/patch/mt76/patches/100-api_update.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/tx.c -+++ b/tx.c -@@ -350,7 +350,7 @@ mt76_tx(struct mt76_phy *phy, struct iee - info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); - - if ((info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || -- (info->control.flags & IEEE80211_TX_CTRL_SCAN_TX)) -+ (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) - head = &wcid->tx_offchannel; - else - head = &wcid->tx_pending; diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index a6eeaa92c..4b379d23d 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -184,7 +184,7 @@ else git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac fi -# mt76 - 2024-09-29 +# mt76 - 2024-10-11 rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile @@ -192,7 +192,6 @@ curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefi curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch curl -s https://$mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch } -[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/mt76/patches/100-api_update.patch > package/kernel/mt76/patches/100-api_update.patch # iwinfo: add mt7922 device id if [ "$version" = "rc2" ]; then @@ -210,11 +209,10 @@ if [ "$version" = "rc2" ]; then fi curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - fix linux 6.6 & add rtw89 +# mac80211 rm -rf package/kernel/mac80211 if [ "$version" = "rc2" ]; then git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 - [ "$version" = "snapshots-24.10" ] && rm -f package/kernel/mac80211/patches/build/140-trace_backport.patch else git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 fi From 54f09dc01038bcc50e84f184848f7ce9d698d84c Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Oct 2024 09:26:57 +0800 Subject: [PATCH 074/425] gpio-nct5104d: remove outdated patches Signed-off-by: sbwml --- .../fix-build-for-linux-6.12.patch | 41 ------------------- openwrt/scripts/04-fix_kmod.sh | 3 +- 2 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch diff --git a/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch b/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch deleted file mode 100644 index 6b1874d24..000000000 --- a/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch +++ /dev/null @@ -1,41 +0,0 @@ -diff --git a/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c b/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c -index f453a2b..8409515 100644 ---- a/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c -+++ b/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c -@@ -283,7 +283,11 @@ static int nct5104d_gpio_probe(struct platform_device *pdev) - bank->chip.parent = &pdev->dev; - bank->data = data; - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,11,0) -+ err = gpiochip_add_data(&bank->chip, bank); -+#else - err = gpiochip_add(&bank->chip); -+#endif - if (err) { - dev_err(&pdev->dev, - "Failed to register gpiochip %d: %d\n", -@@ -304,7 +308,13 @@ err_gpiochip: - return err; - } - --static int nct5104d_gpio_remove(struct platform_device *pdev) -+static -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0) -+int -+#else -+void -+#endif -+nct5104d_gpio_remove(struct platform_device *pdev) - { - int i; - struct nct5104d_gpio_data *data = platform_get_drvdata(pdev); -@@ -315,7 +325,9 @@ static int nct5104d_gpio_remove(struct platform_device *pdev) - gpiochip_remove (&bank->chip); - } - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0) - return 0; -+#endif - } - - static int __init nct5104d_find(int addr, struct nct5104d_sio *sio) diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index c2051d314..bdeaad819 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -17,8 +17,7 @@ fi curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 # gpio-nct5104d -curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.12.patch | patch -p1 +[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch | patch -p1 # dmx_usb_module if [ "$version" = "rc2" ]; then From bfa6137a44369599491ad4066f85389a7fb22f90 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Oct 2024 09:41:15 +0800 Subject: [PATCH 075/425] snapshots: fix mbedtls build use gcc14 Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 94451396b..6393286d8 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -6,9 +6,6 @@ sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/l # grub2 - disable `gc-sections` flag sed -i '/PKG_BUILD_FLAGS/ s/$/ no-gc-sections/' package/boot/grub2/Makefile -# mbedtls -[ "$version" = "snapshots-24.10" ] && sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile - # haproxy - fix build with quictls [ "$version" = "snapshots-24.10" ] && sed -i '/USE_QUIC_OPENSSL_COMPAT/d' feeds/packages/net/haproxy/Makefile @@ -96,6 +93,7 @@ fi if [ "$USE_GCC15" = y ]; then # Mbedtls curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch > package/libs/mbedtls/patches/901-tests-fix-string-initialization-error-on-gcc15.patch + [ "$version" = "snapshots-24.10" ] && sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile # elfutils curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch # libwebsockets From 73831a5589bef9642cc0d6405bfa2a9c1cf07339 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Oct 2024 10:05:48 +0800 Subject: [PATCH 076/425] openwrt-23.05: update mac80211 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 4b379d23d..7c29299e9 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -209,13 +209,9 @@ if [ "$version" = "rc2" ]; then fi curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 +# mac80211 - 6.11 rm -rf package/kernel/mac80211 -if [ "$version" = "rc2" ]; then - git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.11 -else - git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 -fi +git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b $openwrt_version # ath10k-ct rm -rf package/kernel/ath10k-ct From 5be0bc52feb3e01cc789882a9cdc9f986e4c7bed Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Oct 2024 21:08:02 +0800 Subject: [PATCH 077/425] openwrt-24.10: dnsmasq: fix compatibility issues Signed-off-by: sbwml --- ...dnsmasq-drop-extraconftext-parameter.patch | 54 + openwrt/patch/dnsmasq/dnsmasq.init | 1372 +++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 6 + 3 files changed, 1432 insertions(+) create mode 100644 openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch create mode 100644 openwrt/patch/dnsmasq/dnsmasq.init diff --git a/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch b/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch new file mode 100644 index 000000000..7717b2faa --- /dev/null +++ b/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch @@ -0,0 +1,54 @@ +From 01e9c5d991cbe0dad0283e102be9c5570f4549f6 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Tue, 22 Oct 2024 21:00:28 +0800 +Subject: [PATCH] dnsmasq: drop 'extraconftext' parameter + +Signed-off-by: sbwml +--- + .../services/dnsmasq/files/dnsmasq.init | 23 ++++++------------- + 1 file changed, 7 insertions(+), 16 deletions(-) + +diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init +index b864ea9069..96110c2b38 100755 +--- a/package/network/services/dnsmasq/files/dnsmasq.init ++++ b/package/network/services/dnsmasq/files/dnsmasq.init +@@ -12,7 +12,6 @@ ADD_WAN_FQDN=0 + ADD_LOCAL_FQDN="" + + BASECONFIGFILE="/var/etc/dnsmasq.conf" +-EXTRACONFFILE="extraconfig.conf" + BASEHOSTFILE="/tmp/hosts/dhcp" + TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf" + TIMEVALIDFILE="/var/state/dnsmasqsec" +@@ -1145,21 +1144,13 @@ dnsmasq_start() + xappend "--dhcp-broadcast=tag:needs-broadcast" + + +- # Create a dnsmasq.d dir for each instance +- config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq${cfg:+.$cfg}.d" +- # Ensure dnsmasqconfdir is an absolute path +- [ "${dnsmasqconfdir:0:1}" = '/' ] && { +- xappend "--conf-dir=$dnsmasqconfdir" +- dnsmasqconfdir="${dnsmasqconfdir%%,*}" +- [ ! -d "$dnsmasqconfdir" ] && mkdir -p "$dnsmasqconfdir" +- xappend "--user=dnsmasq" +- xappend "--group=dnsmasq" +- echo >> "$CONFIGFILE_TMP" +- +- # EXTRACONFFILE allows new dnsmasq parameters before they are natively handled in this init file +- config_get extraconftext "$cfg" extraconftext +- [ -n "$extraconftext" ] && echo -e "$extraconftext" > "$dnsmasqconfdir"/"$EXTRACONFFILE" +- } ++ config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d" ++ xappend "--conf-dir=$dnsmasqconfdir" ++ dnsmasqconfdir="${dnsmasqconfdir%%,*}" ++ [ ! -d "$dnsmasqconfdir" ] && mkdir -p "$dnsmasqconfdir" ++ xappend "--user=dnsmasq" ++ xappend "--group=dnsmasq" ++ echo >> "$CONFIGFILE_TMP" + + config_get_bool enable_tftp "$cfg" enable_tftp 0 + [ "$enable_tftp" -gt 0 ] && { +-- +2.42.0 + diff --git a/openwrt/patch/dnsmasq/dnsmasq.init b/openwrt/patch/dnsmasq/dnsmasq.init new file mode 100644 index 000000000..96110c2b3 --- /dev/null +++ b/openwrt/patch/dnsmasq/dnsmasq.init @@ -0,0 +1,1372 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2007-2012 OpenWrt.org + +START=19 + +USE_PROCD=1 +PROG=/usr/sbin/dnsmasq + +ADD_LOCAL_DOMAIN=1 +ADD_LOCAL_HOSTNAME=1 +ADD_WAN_FQDN=0 +ADD_LOCAL_FQDN="" + +BASECONFIGFILE="/var/etc/dnsmasq.conf" +BASEHOSTFILE="/tmp/hosts/dhcp" +TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf" +TIMEVALIDFILE="/var/state/dnsmasqsec" +BASEDHCPSTAMPFILE="/var/run/dnsmasq" +DHCPBOGUSHOSTNAMEFILE="/usr/share/dnsmasq/dhcpbogushostname.conf" +RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf" +DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh" +DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus" + +DNSMASQ_DHCP_VER=4 + +dnsmasq_ignore_opt() { + local opt="$1" + + if [ -z "$dnsmasq_features" ]; then + dnsmasq_features="$(dnsmasq --version | grep -m1 'Compile time options:' | cut -d: -f2) " + [ "${dnsmasq_features#* DHCP }" = "$dnsmasq_features" ] || dnsmasq_has_dhcp=1 + [ "${dnsmasq_features#* DHCPv6 }" = "$dnsmasq_features" ] || dnsmasq_has_dhcp6=1 + [ "${dnsmasq_features#* DNSSEC }" = "$dnsmasq_features" ] || dnsmasq_has_dnssec=1 + [ "${dnsmasq_features#* TFTP }" = "$dnsmasq_features" ] || dnsmasq_has_tftp=1 + [ "${dnsmasq_features#* ipset }" = "$dnsmasq_features" ] || dnsmasq_has_ipset=1 + [ "${dnsmasq_features#* nftset }" = "$dnsmasq_features" ] || dnsmasq_has_nftset=1 + fi + + case "$opt" in + dhcp-duid|\ + ra-param) + [ -z "$dnsmasq_has_dhcp6" ] ;; + dhcp-*|\ + bootp-*|\ + pxe-*) + [ -z "$dnsmasq_has_dhcp" ] ;; + dnssec*|\ + trust-anchor) + if [ -z "$dnsmasq_has_dnssec" ]; then + echo "dnsmasq: \"$opt\" requested, but dnssec support is not available" >&2 + exit 1 + fi + return 1 + ;; + tftp-*) + [ -z "$dnsmasq_has_tftp" ] ;; + ipset) + [ -z "$dnsmasq_has_ipset" ] ;; + nftset) + [ -z "$dnsmasq_has_nftset" ] ;; + *) + return 1 + esac +} + +xappend() { + local value="${1#--}" + local opt="${value%%=*}" + + if ! dnsmasq_ignore_opt "$opt"; then + echo "$value" >>"$CONFIGFILE_TMP" + fi +} + +hex_to_hostid() { + local var="$1" + local hex="${2#0x}" # strip optional "0x" prefix + + if [ -n "${hex//[0-9a-fA-F]/}" ]; then + # is invalid hex literal + return 1 + fi + + # convert into host id + export "$var=$( + printf "%0x:%0x" \ + $(((0x$hex >> 16) % 65536)) \ + $(( 0x$hex % 65536)) + )" + + return 0 +} + +dhcp_calc() { + local ip="$1" + local res=0 + + while [ -n "$ip" ]; do + part="${ip%%.*}" + res="$(($res * 256))" + res="$(($res + $part))" + [ "${ip%.*}" != "$ip" ] && ip="${ip#*.}" || ip= + done + echo "$res" +} + +dhcp_check() { + local ifname="$1" + local stamp="${BASEDHCPSTAMPFILE_CFG}.${ifname}.dhcp" + local rv=0 + + [ -s "$stamp" ] && return $(cat "$stamp") + + # If interface is down, skip it. + # The init script will be called again once the link is up + case "$(devstatus "$ifname" | jsonfilter -e @.up)" in + false) return 1;; + esac + + udhcpc -n -q -s /bin/true -t 1 -i "$ifname" >&- && rv=1 || rv=0 + + echo $rv > "$stamp" + return $rv +} + +log_once() { + pidof dnsmasq >/dev/null || \ + logger -t dnsmasq "$@" +} + +has_handler() { + local file + + for file in /etc/hotplug.d/dhcp/* /etc/hotplug.d/tftp/* /etc/hotplug.d/neigh/*; do + [ -f "$file" ] && return 0 + done + + return 1 +} + +append_bool() { + local section="$1" + local option="$2" + local value="$3" + local default="$4" + local _loctmp + [ -z "$default" ] && default="0" + config_get_bool _loctmp "$section" "$option" "$default" + [ $_loctmp -gt 0 ] && xappend "$value" +} + +append_parm() { + local section="$1" + local option="$2" + local switch="$3" + local default="$4" + local _loctmp + config_get _loctmp "$section" "$option" "$default" + [ -z "$_loctmp" ] && return 0 + xappend "$switch=$_loctmp" +} + +append_server() { + xappend "--server=$1" +} + +append_rev_server() { + xappend "--rev-server=$1" +} + +append_address() { + xappend "--address=$1" +} + +append_connmark_allowlist() { + xappend "--connmark-allowlist=$1" +} + +append_interface() { + network_get_device ifname "$1" || ifname="$1" + xappend "--interface=$ifname" +} + +append_listenaddress() { + xappend "--listen-address=$1" +} + +append_notinterface() { + network_get_device ifname "$1" || ifname="$1" + xappend "--except-interface=$ifname" +} + +ismounted() { + local filename="$1" + local dirname + for dirname in $EXTRA_MOUNT ; do + case "$filename" in + "${dirname}/"* | "${dirname}" ) + return 0 + ;; + esac + done + + return 1 +} + +append_extramount() { + ismounted "$1" || append EXTRA_MOUNT "$1" +} + +append_addnhosts() { + append_extramount "$1" + xappend "--addn-hosts=$1" +} + +append_bogusnxdomain() { + xappend "--bogus-nxdomain=$1" +} + +append_pxe_service() { + xappend "--pxe-service=$1" +} + +append_interface_name() { + xappend "--interface-name=$1,$2" +} + +filter_dnsmasq() { + local cfg="$1" func="$2" match_cfg="$3" found_cfg + + # use entry when no instance entry set, or if it matches + config_get found_cfg "$cfg" "instance" + if [ -z "$found_cfg" ] || [ "$found_cfg" = "$match_cfg" ]; then + $func $cfg + fi +} + +dhcp_subscrid_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get subscriberid "$cfg" subscriberid + [ -n "$subscriberid" ] || return 0 + + xappend "--dhcp-subscrid=set:$networkid,$subscriberid" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_remoteid_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get remoteid "$cfg" remoteid + [ -n "$remoteid" ] || return 0 + + xappend "--dhcp-remoteid=set:$networkid,$remoteid" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_circuitid_add() { + # TODO: DHCPV6 does not have circuitid; catch "option6:" + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get circuitid "$cfg" circuitid + [ -n "$circuitid" ] || return 0 + + xappend "--dhcp-circuitid=set:$networkid,$circuitid" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_userclass_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get userclass "$cfg" userclass + [ -n "$userclass" ] || return 0 + + xappend "--dhcp-userclass=set:$networkid,$userclass" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_vendorclass_add() { + # TODO: DHCPV6 vendor class has stricter definitions; catch? fixup? + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get vendorclass "$cfg" vendorclass + [ -n "$vendorclass" ] || return 0 + + xappend "--dhcp-vendorclass=set:$networkid,$vendorclass" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_match_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get match "$cfg" match + [ -n "$match" ] || return 0 + + xappend "--dhcp-match=set:$networkid,$match" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_host_add() { + local cfg="$1" + local hosttag nametime addrs duids macs tags mtags + + config_get_bool force "$cfg" force 0 + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] && dhcp_option_add "$cfg" "$networkid" "$force" + + config_get_bool enable "$cfg" enable 1 + [ "$enable" = "0" ] && return 0 + + config_get name "$cfg" name + config_get ip "$cfg" ip + config_get hostid "$cfg" hostid + + [ -z "$ip" ] && [ -z "$name" ] && [ -z "$hostid" ] && return 0 + + config_get_bool dns "$cfg" dns 0 + [ "$dns" = "1" ] && [ -n "$ip" ] && [ -n "$name" ] && { + echo "$ip $name${DOMAIN:+.$DOMAIN}" >> "$HOSTFILE_TMP" + } + + config_get mac "$cfg" mac + config_get duid "$cfg" duid + config_get tag "$cfg" tag + + add_tag() { + mtags="${mtags}tag:$1," + } + config_list_foreach "$cfg" match_tag add_tag + + if [ -n "$mac" ]; then + # --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap + # many MAC are possible to track a laptop ON/OFF dock + for m in $mac; do append macs "$m" ","; done + fi + + if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ -n "$duid" ]; then + # --dhcp-host=id:00:03:00:01:12:00:00:01:02:03,[::beef],lap + # one (virtual) machine gets one DUID per RFC3315 + duids="id:${duid// */}" + fi + + if [ -z "$macs" ] && [ -z "$duids" ]; then + # --dhcp-host=lap,192.168.0.199,[::beef] + [ -n "$name" ] || return 0 + macs="$name" + name="" + fi + + if [ -n "$hostid" ]; then + hex_to_hostid hostid "$hostid" + fi + + if [ -n "$tag" ]; then + for t in $tag; do append tags "$t" ",set:"; done + fi + + config_get_bool broadcast "$cfg" broadcast 0 + config_get leasetime "$cfg" leasetime + + [ "$broadcast" = "0" ] && broadcast= || broadcast=",set:needs-broadcast" + + hosttag="${networkid:+,set:${networkid}}${tags:+,set:${tags}}$broadcast" + nametime="${name:+,$name}${leasetime:+,$leasetime}" + + if [ $DNSMASQ_DHCP_VER -eq 6 ]; then + addrs="${ip:+,$ip}${hostid:+,[::$hostid]}" + xappend "--dhcp-host=$mtags$macs${duids:+,$duids}$hosttag$addrs$nametime" + else + xappend "--dhcp-host=$mtags$macs$hosttag${ip:+,$ip}$nametime" + fi +} + +dhcp_this_host_add() { + local net="$1" + local ifname="$2" + local mode="$3" + local routerstub routername ifdashname + local lanaddr lanaddr6 lanaddrs6 ulaprefix + + if [ "$mode" -gt 0 ] ; then + ifdashname="${ifname//./-}" + routerstub="$( md5sum /etc/os-release )" + routerstub="router-${routerstub// */}" + routername="$( uci_get system @system[0] hostname $routerstub )" + + if [ "$mode" -gt 1 ] ; then + if [ "$mode" -gt 2 ] ; then + if [ "$mode" -gt 3 ] ; then + append_interface_name "$ifdashname.$routername.$DOMAIN" "$ifname" + fi + + append_interface_name "$routername.$DOMAIN" "$ifname" + fi + + # All IP addresses discovered by dnsmasq will be labeled (except fe80::) + append_interface_name "$routername" "$ifname" + + else + # This uses a static host file entry for only limited addresses. + # Use dnsmasq option "--expandhosts" to enable FQDN on host files. + ulaprefix="$(uci_get network @globals[0] ula_prefix)" + network_get_ipaddr lanaddr "$net" + network_get_ipaddrs6 lanaddrs6 "$net" + + if [ -n "$lanaddr" ] ; then + dhcp_domain_add "" "$routername" "$lanaddr" + fi + + if [ -n "$ulaprefix" ] && [ -n "$lanaddrs6" ] ; then + for lanaddr6 in $lanaddrs6 ; do + case "$lanaddr6" in + "${ulaprefix%%:/*}"*) + dhcp_domain_add "" "$routername" "$lanaddr6" + ;; + esac + done + fi + fi + fi +} + +dhcp_tag_add() { + # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions + local cfg="$1" + + tag="$cfg" + + [ -n "$tag" ] || return 0 + + config_get_bool force "$cfg" force 0 + [ "$force" = "0" ] && force= + + config_get option "$cfg" dhcp_option + for o in $option; do + xappend "--dhcp-option${force:+-force}=tag:$tag,$o" + done +} + +dhcp_mac_add() { + local cfg="$1" + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || return 0 + + config_get mac "$cfg" mac + [ -n "$mac" ] || return 0 + + xappend "--dhcp-mac=$networkid,$mac" + + dhcp_option_add "$cfg" "$networkid" +} + +dhcp_boot_add() { + # TODO: BOOTURL is different between DHCPv4 and DHCPv6 + local cfg="$1" + + config_get networkid "$cfg" networkid + + config_get filename "$cfg" filename + [ -n "$filename" ] || return 0 + + config_get servername "$cfg" servername + config_get serveraddress "$cfg" serveraddress + + [ -n "$serveraddress" ] && [ ! -n "$servername" ] && return 0 + + xappend "--dhcp-boot=${networkid:+tag:$networkid,}${filename}${servername:+,$servername}${serveraddress:+,$serveraddress}" + + config_get_bool force "$cfg" force 0 + + dhcp_option_add "$cfg" "$networkid" "$force" +} + +dhcp_add() { + local cfg="$1" + local dhcp6range="::" + local nettag + local tags + + config_get net "$cfg" interface + [ -n "$net" ] || return 0 + + config_get networkid "$cfg" networkid + [ -n "$networkid" ] || networkid="$net" + + network_get_device ifname "$net" || return 0 + + [ "$cachelocal" = "0" ] && network_get_dnsserver dnsserver "$net" && { + DNS_SERVERS="$DNS_SERVERS $dnsserver" + } + + append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && { + # Many ISP do not have useful names for DHCP customers (your WAN). + dhcp_this_host_add "$net" "$ifname" "$ADD_WAN_FQDN" + return 0 + } + + network_get_subnet subnet "$net" || return 0 + network_get_protocol proto "$net" || return 0 + + # Do not support non-static interfaces for now + [ static = "$proto" ] || return 0 + + ipaddr="${subnet%%/*}" + prefix_or_netmask="${subnet##*/}" + + # Override interface netmask with dhcp config if applicable + config_get netmask "$cfg" netmask + + [ -n "$netmask" ] && prefix_or_netmask="$netmask" + + #check for an already active dhcp server on the interface, unless 'force' is set + config_get_bool force "$cfg" force 0 + [ $force -gt 0 ] || dhcp_check "$ifname" || { + logger -t dnsmasq \ + "found already running DHCP-server on interface '$ifname'" \ + "refusing to start, use 'option force 1' to override" + return 0 + } + + config_get start "$cfg" start 100 + config_get limit "$cfg" limit 150 + config_get leasetime "$cfg" leasetime 12h + config_get options "$cfg" options + config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1 + config_get_bool dynamicdhcpv4 "$cfg" dynamicdhcpv4 $dynamicdhcp + config_get_bool dynamicdhcpv6 "$cfg" dynamicdhcpv6 $dynamicdhcp + + config_get dhcpv4 "$cfg" dhcpv4 + config_get dhcpv6 "$cfg" dhcpv6 + + config_get ra "$cfg" ra + config_get ra_management "$cfg" ra_management + config_get ra_preference "$cfg" ra_preference + config_get dns "$cfg" dns + config_get dns_sl "$cfg" domain + + config_list_foreach "$cfg" "interface_name" append_interface_name "$ifname" + + # Put the router host name on this DHCP served interface address(es) + dhcp_this_host_add "$net" "$ifname" "$ADD_LOCAL_FQDN" + + start="$( dhcp_calc "$start" )" + + add_tag() { + tags="${tags}tag:$1," + } + config_list_foreach "$cfg" tag add_tag + + nettag="${networkid:+set:${networkid},}" + + # make sure the DHCP range is not empty + if [ "$dhcpv4" != "disabled" ] && ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit" ; then + [ "$dynamicdhcpv4" = "0" ] && END="static" + + xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}" + fi + + if [ "$dynamicdhcpv6" = "0" ] ; then + dhcp6range="::,static" + else + dhcp6range="::1000,::ffff" + fi + + + if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ "$ra" = "server" ] ; then + # Note: dnsmasq cannot just be a DHCPv6 server (all-in-1) + # and let some other machine(s) send RA pointing to it. + + case $ra_preference in + *high*) + xappend "--ra-param=$ifname,high,0,7200" + ;; + *low*) + xappend "--ra-param=$ifname,low,0,7200" + ;; + *) + # Send UNSOLICITED RA at default interval and live for 2 hours. + # TODO: convert flexible lease time into route life time (only seconds). + xappend "--ra-param=$ifname,0,7200" + ;; + esac + + if [ "$dhcpv6" = "disabled" ] ; then + ra_management="3" + fi + + + case $ra_management in + 0) + # SLACC with DCHP for extended options + xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-stateless,ra-names" + ;; + 2) + # DHCP address and RA only for management redirection + xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,$leasetime" + ;; + 3) + # SLAAC only but dnsmasq attempts to link HOSTNAME, DHCPv4 MAC, and SLAAC + xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-only,ra-names" + ;; + *) + # SLAAC and full DHCP + xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,slaac,ra-names,$leasetime" + ;; + esac + + if [ -n "$dns" ]; then + dnss="" + for d in $dns; do append dnss "[$d]" ","; done + else + dnss="[::]" + fi + + dhcp_option_append "option6:dns-server,$dnss" "$networkid" + + if [ -n "$dns_sl" ]; then + ddssl="" + for dd in $dns_sl; do append ddssl "$dd" ","; done + fi + + dhcp_option_append "option6:domain-search,$ddssl" "$networkid" + fi + + dhcp_option_add "$cfg" "$networkid" 0 + dhcp_option_add "$cfg" "$networkid" 2 +} + +dhcp_option_append() { + local option="$1" + local networkid="$2" + local force="$3" + + xappend "--dhcp-option${force:+-force}=${networkid:+$networkid,}$option" +} + +dhcp_option_add() { + # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions + local cfg="$1" + local networkid="$2" + local force="$3" + local opt="dhcp_option" + + [ "$force" = "0" ] && force= + [ "$force" = "2" ] && opt="dhcp_option_force" + + local list_len + config_get list_len "$cfg" "${opt}_LENGTH" + + if [ -n "$list_len" ]; then + config_list_foreach "$cfg" "$opt" dhcp_option_append "$networkid" "$force" + else + config_get dhcp_option "$cfg" "$opt" + + [ -n "$dhcp_option" ] && echo "Warning: the 'option $opt' syntax is deprecated, use 'list $opt'" >&2 + + local option + for option in $dhcp_option; do + dhcp_option_append "$option" "$networkid" "$force" + done + fi +} + +dhcp_domain_add() { + local cfg="$1" + local ip name names record + + config_get names "$cfg" name "$2" + [ -n "$names" ] || return 0 + + config_get ip "$cfg" ip "$3" + [ -n "$ip" ] || return 0 + + for name in $names; do + record="${record:+$record }$name" + done + + echo "$ip $record" >> "$HOSTFILE_TMP" +} + +dhcp_srv_add() { + local cfg="$1" + + config_get srv "$cfg" srv + [ -n "$srv" ] || return 0 + + config_get target "$cfg" target + [ -n "$target" ] || return 0 + + config_get port "$cfg" port + [ -n "$port" ] || return 0 + + config_get class "$cfg" class + config_get weight "$cfg" weight + + local service="$srv,$target,$port${class:+,$class${weight:+,$weight}}" + + xappend "--srv-host=$service" +} + +dhcp_mx_add() { + local cfg="$1" + local domain relay pref + + config_get domain "$cfg" domain + [ -n "$domain" ] || return 0 + + config_get relay "$cfg" relay + [ -n "$relay" ] || return 0 + + config_get pref "$cfg" pref 0 + + local service="$domain,$relay,$pref" + + xappend "--mx-host=$service" +} + +dhcp_cname_add() { + local cfg="$1" + local cname target + + config_get cname "$cfg" cname + [ -n "$cname" ] || return 0 + + config_get target "$cfg" target + [ -n "$target" ] || return 0 + + xappend "--cname=${cname},${target}" +} + +dhcp_hostrecord_add() { + local cfg="$1" + local names addresses record val + + config_get names "$cfg" name "$2" + if [ -z "$names" ]; then + return 0 + fi + + config_get addresses "$cfg" ip "$3" + if [ -z "$addresses" ]; then + return 0 + fi + + for val in $names $addresses; do + record="${record:+$record,}$val" + done + + xappend "--host-record=$record" +} + +dhcp_dnsrr_add() { + #This adds arbitrary resource record types (of IN class) whose optional data must be hex + local cfg="$1" + local rrname rrnumber hexdata + + config_get rrname "$cfg" rrname + [ -n "$rrname" ] || return 0 + + config_get rrnumber "$cfg" rrnumber + [ -n "$rrnumber" ] && [ "$rrnumber" -gt 0 ] || return 0 + + config_get hexdata "$cfg" hexdata + + # dnsmasq accepts colon XX:XX:.., space XX XX .., or contiguous XXXX.. hex forms or mixtures thereof + if [ -n "${hexdata//[0-9a-fA-F\:\ ]/}" ]; then + # is invalid hex literal + echo "dnsmasq: \"$hexdata\" is malformed hexadecimal (separate hex with colon, space or not at all)." >&2 + return 1 + fi + + xappend "--dns-rr=${rrname},${rrnumber}${hexdata:+,$hexdata}" +} + +dhcp_relay_add() { + local cfg="$1" + local local_addr server_addr interface + + config_get local_addr "$cfg" local_addr + [ -n "$local_addr" ] || return 0 + + config_get server_addr "$cfg" server_addr + [ -n "$server_addr" ] || return 0 + + config_get interface "$cfg" interface + if [ -z "$interface" ]; then + xappend "--dhcp-relay=$local_addr,$server_addr" + else + network_get_device ifname "$interface" || return + xappend "--dhcp-relay=$local_addr,$server_addr,$ifname" + fi +} + +dnsmasq_ipset_add() { + local cfg="$1" + local ipsets nftsets domains + + add_ipset() { + ipsets="${ipsets:+$ipsets,}$1" + } + + add_nftset() { + local IFS=, + for set in $1; do + local fam="$family" + [ -n "$fam" ] || fam=$(echo "$set" | sed -nre \ + 's#^.*[^0-9]([46])$|^.*[-_]([46])[-_].*$|^([46])[^0-9].*$#\1\2\3#p') + [ -n "$fam" ] || \ + fam=$(nft -t list set "$table_family" "$table" "$set" 2>&1 | sed -nre \ + 's#^\t\ttype .*\bipv([46])_addr\b.*$#\1#p') + + [ -n "$fam" ] || \ + logger -t dnsmasq "Cannot infer address family from non-existent nftables set '$set'" + + nftsets="${nftsets:+$nftsets,}${fam:+$fam#}$table_family#$table#$set" + done + } + + add_domain() { + # leading '/' is expected + domains="$domains/$1" + } + + config_get table "$cfg" table 'fw4' + config_get table_family "$cfg" table_family 'inet' + if [ "$table_family" = "ip" ] ; then + family="4" + elif [ "$table_family" = "ip6" ] ; then + family="6" + else + config_get family "$cfg" family + fi + + config_list_foreach "$cfg" "name" add_ipset + config_list_foreach "$cfg" "name" add_nftset + config_list_foreach "$cfg" "domain" add_domain + + if [ -z "$ipsets" ] || [ -z "$nftsets" ] || [ -z "$domains" ]; then + return 0 + fi + + xappend "--ipset=$domains/$ipsets" + xappend "--nftset=$domains/$nftsets" +} + +dnsmasq_start() +{ + local cfg="$1" + local disabled user_dhcpscript logfacility + local resolvfile resolvdir localuse=1 + + config_get_bool disabled "$cfg" disabled 0 + [ "$disabled" -gt 0 ] && return 0 + + # reset list of DOMAINS, DNS servers and EXTRA mounts (for each dnsmasq instance) + DNS_SERVERS="" + DOMAIN="" + EXTRA_MOUNT="" + CONFIGFILE="${BASECONFIGFILE}.${cfg}" + CONFIGFILE_TMP="${CONFIGFILE}.$$" + HOSTFILE="${BASEHOSTFILE}.${cfg}" + HOSTFILE_TMP="${HOSTFILE}.$$" + HOSTFILE_DIR="$(dirname "$HOSTFILE")" + BASEDHCPSTAMPFILE_CFG="${BASEDHCPSTAMPFILE}.${cfg}" + + # before we can call xappend + umask u=rwx,g=rx,o=rx + mkdir -p /var/run/dnsmasq/ + mkdir -p "$(dirname "$CONFIGFILE")" + mkdir -p "$HOSTFILE_DIR" + mkdir -p /var/lib/misc + chown dnsmasq:dnsmasq /var/run/dnsmasq + + echo "# auto-generated config file from /etc/config/dhcp" > "$CONFIGFILE_TMP" + echo "# auto-generated config file from /etc/config/dhcp" > "$HOSTFILE_TMP" + + local dnsmasqconffile="/etc/dnsmasq.${cfg}.conf" + if [ ! -r "$dnsmasqconffile" ]; then + dnsmasqconffile=/etc/dnsmasq.conf + fi + + # if we did this last, we could override auto-generated config + [ -f "${dnsmasqconffile}" ] && { + xappend "--conf-file=${dnsmasqconffile}" + } + + $PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0 + + + if [ -x /usr/sbin/odhcpd ] && [ -x /etc/init.d/odhcpd ] ; then + local odhcpd_is_main odhcpd_is_enabled + config_get odhcpd_is_main odhcpd maindhcp 0 + /etc/init.d/odhcpd enabled && odhcpd_is_enabled=1 || odhcpd_is_enabled=0 + + + if [ "$odhcpd_is_enabled" -eq 0 ] && [ "$DHCPv6CAPABLE" -eq 1 ] ; then + # DHCP V4 and V6 in DNSMASQ + DNSMASQ_DHCP_VER=6 + elif [ "$odhcpd_is_main" -gt 0 ] ; then + # ODHCPD is doing it all + DNSMASQ_DHCP_VER=0 + else + # You have ODHCPD but use DNSMASQ for DHCPV4 + DNSMASQ_DHCP_VER=4 + fi + + elif [ "$DHCPv6CAPABLE" -eq 1 ] ; then + # DHCP V4 and V6 in DNSMASQ + DNSMASQ_DHCP_VER=6 + else + DNSMASQ_DHCP_VER=4 + fi + + # Allow DHCP/DHCPv6 to be handled by ISC DHCPD + if [ -x /usr/sbin/dhcpd ] ; then + if [ -x /etc/init.d/dhcpd ] ; then + /etc/init.d/dhcpd enabled && DNSMASQ_DHCP_VER=0 + fi + if [ -x /etc/init.d/dhcpd6 ] && [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then + /etc/init.d/dhcpd6 enabled && DNSMASQ_DHCP_VER=4 + fi + fi + + append_bool "$cfg" authoritative "--dhcp-authoritative" + append_bool "$cfg" nodaemon "--no-daemon" + append_bool "$cfg" domainneeded "--domain-needed" + append_bool "$cfg" filterwin2k "--filterwin2k" + append_bool "$cfg" nohosts "--no-hosts" + append_bool "$cfg" nonegcache "--no-negcache" + append_bool "$cfg" strictorder "--strict-order" + append_bool "$cfg" logqueries "--log-queries=extra" + append_bool "$cfg" noresolv "--no-resolv" + append_bool "$cfg" localise_queries "--localise-queries" + append_bool "$cfg" readethers "--read-ethers" + + local instance_name="dnsmasq.$cfg" + if [ "$cfg" = "$DEFAULT_INSTANCE" ]; then + instance_name="dnsmasq" + fi + config_get_bool dbus "$cfg" "dbus" 0 + [ $dbus -gt 0 ] && xappend "--enable-dbus=uk.org.thekelleys.$instance_name" + config_get_bool ubus "$cfg" "ubus" 1 + [ $ubus -gt 0 ] && xappend "--enable-ubus=$instance_name" + + append_bool "$cfg" expandhosts "--expand-hosts" + config_get tftp_root "$cfg" "tftp_root" + [ -n "$tftp_root" ] && mkdir -p "$tftp_root" && append_bool "$cfg" enable_tftp "--enable-tftp" + append_bool "$cfg" tftp_no_fail "--tftp-no-fail" + append_bool "$cfg" nonwildcard "--bind-dynamic" 1 + append_bool "$cfg" fqdn "--dhcp-fqdn" + append_bool "$cfg" proxydnssec "--proxy-dnssec" + append_bool "$cfg" localservice "--local-service" + append_bool "$cfg" logdhcp "--log-dhcp" + append_bool "$cfg" quietdhcp "--quiet-dhcp" + append_bool "$cfg" sequential_ip "--dhcp-sequential-ip" + append_bool "$cfg" allservers "--all-servers" + append_bool "$cfg" noping "--no-ping" + append_bool "$cfg" rapidcommit "--dhcp-rapid-commit" + append_bool "$cfg" scriptarp "--script-arp" + + # deprecate or remove filter-X in favor of filter-rr? + append_bool "$cfg" filter_aaaa "--filter-AAAA" + append_bool "$cfg" filter_a "--filter-A" + append_parm "$cfg" filter_rr "--filter-rr" + append_parm "$cfg" cache_rr "--cache-rr" + + append_parm "$cfg" logfacility "--log-facility" + config_get logfacility "$cfg" "logfacility" + append_parm "$cfg" cachesize "--cache-size" + append_parm "$cfg" dnsforwardmax "--dns-forward-max" + append_parm "$cfg" port "--port" + append_parm "$cfg" ednspacket_max "--edns-packet-max" + append_parm "$cfg" dhcpleasemax "--dhcp-lease-max" + append_parm "$cfg" "queryport" "--query-port" + append_parm "$cfg" "minport" "--min-port" + append_parm "$cfg" "maxport" "--max-port" + append_parm "$cfg" "domain" "--domain" + append_parm "$cfg" "local" "--local" + config_list_foreach "$cfg" "listen_address" append_listenaddress + config_list_foreach "$cfg" "server" append_server + config_list_foreach "$cfg" "rev_server" append_rev_server + config_list_foreach "$cfg" "address" append_address + + local connmark_allowlist_enable + config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0 + [ "$connmark_allowlist_enable" -gt 0 ] && { + append_parm "$cfg" "connmark_allowlist_enable" "--connmark-allowlist-enable" + config_list_foreach "$cfg" "connmark_allowlist" append_connmark_allowlist + } + + [ -n "$BOOT" ] || { + config_list_foreach "$cfg" "interface" append_interface + config_list_foreach "$cfg" "notinterface" append_notinterface + } + config_get_bool ignore_hosts_dir "$cfg" ignore_hosts_dir 0 + if [ "$ignore_hosts_dir" = "1" ]; then + xappend "--addn-hosts=$HOSTFILE" + append EXTRA_MOUNT "$HOSTFILE" + else + xappend "--addn-hosts=$HOSTFILE_DIR" + append EXTRA_MOUNT "$HOSTFILE_DIR" + fi + config_list_foreach "$cfg" "addnhosts" append_addnhosts + config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain + append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases" + + local serversfile + config_get serversfile "$cfg" "serversfile" + [ -n "$serversfile" ] && { + xappend "--servers-file=$serversfile" + append EXTRA_MOUNT "$serversfile" + } + + append_parm "$cfg" "tftp_root" "--tftp-root" + append_parm "$cfg" "dhcp_boot" "--dhcp-boot" + append_parm "$cfg" "local_ttl" "--local-ttl" + append_parm "$cfg" "max_ttl" "--max-ttl" + append_parm "$cfg" "min_cache_ttl" "--min-cache-ttl" + append_parm "$cfg" "max_cache_ttl" "--max-cache-ttl" + append_parm "$cfg" "pxe_prompt" "--pxe-prompt" + append_parm "$cfg" "tftp_unique_root" "--tftp-unique-root" + config_list_foreach "$cfg" "pxe_service" append_pxe_service + config_get DOMAIN "$cfg" domain + + config_get_bool ADD_LOCAL_DOMAIN "$cfg" add_local_domain 1 + config_get_bool ADD_LOCAL_HOSTNAME "$cfg" add_local_hostname 1 + config_get ADD_LOCAL_FQDN "$cfg" add_local_fqdn "" + config_get ADD_WAN_FQDN "$cfg" add_wan_fqdn 0 + + if [ -z "$ADD_LOCAL_FQDN" ] ; then + # maintain support for previous UCI + ADD_LOCAL_FQDN="$ADD_LOCAL_HOSTNAME" + fi + + config_get user_dhcpscript $cfg dhcpscript + if has_handler || [ -n "$user_dhcpscript" ]; then + xappend "--dhcp-script=$DHCPSCRIPT" + xappend "--script-arp" + fi + + config_get leasefile $cfg leasefile "/tmp/dhcp.leases" + [ -n "$leasefile" ] && [ ! -e "$leasefile" ] && touch "$leasefile" + config_get_bool cachelocal "$cfg" cachelocal 1 + + config_get_bool noresolv "$cfg" noresolv 0 + if [ "$noresolv" != "1" ]; then + config_get resolvfile "$cfg" resolvfile /tmp/resolv.conf.d/resolv.conf.auto + [ -n "$resolvfile" ] && [ ! -e "$resolvfile" ] && touch "$resolvfile" + xappend "--resolv-file=$resolvfile" + [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0 + resolvdir="$(dirname "$resolvfile")" + fi + config_get_bool localuse "$cfg" localuse "$localuse" + + config_get hostsfile "$cfg" dhcphostsfile + [ -e "$hostsfile" ] && xappend "--dhcp-hostsfile=$hostsfile" + + local rebind + config_get_bool rebind "$cfg" rebind_protection 1 + [ $rebind -gt 0 ] && { + log_once \ + "DNS rebinding protection is active," \ + "will discard upstream RFC1918 responses!" + xappend "--stop-dns-rebind" + + local rebind_localhost + config_get_bool rebind_localhost "$cfg" rebind_localhost 0 + [ $rebind_localhost -gt 0 ] && { + log_once "Allowing 127.0.0.0/8 responses" + xappend "--rebind-localhost-ok" + } + + append_rebind_domain() { + log_once "Allowing RFC1918 responses for domain $1" + xappend "--rebind-domain-ok=$1" + } + + config_list_foreach "$cfg" rebind_domain append_rebind_domain + } + + config_get_bool dnssec "$cfg" dnssec 0 + [ "$dnssec" -gt 0 ] && { + xappend "--conf-file=$TRUSTANCHORSFILE" + xappend "--dnssec" + [ -x /etc/init.d/sysntpd ] && { + if /etc/init.d/sysntpd enabled || [ "$(uci_get system.ntp.enabled)" = "1" ] ; then + [ -f "$TIMEVALIDFILE" ] || xappend "--dnssec-no-timecheck" + fi + } + config_get_bool dnsseccheckunsigned "$cfg" dnsseccheckunsigned 1 + [ "$dnsseccheckunsigned" -eq 0 ] && xappend "--dnssec-check-unsigned=no" + } + + config_get addmac "$cfg" addmac 0 + [ "$addmac" != "0" ] && { + [ "$addmac" = "1" ] && addmac= + xappend "--add-mac${addmac:+="$addmac"}" + } + append_bool "$cfg" stripmac "--strip-mac" + append_parm "$cfg" addsubnet "--add-subnet" + append_bool "$cfg" stripsubnet "--strip-subnet" + + dhcp_option_add "$cfg" "" 0 + dhcp_option_add "$cfg" "" 2 + + xappend "--dhcp-broadcast=tag:needs-broadcast" + + + config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d" + xappend "--conf-dir=$dnsmasqconfdir" + dnsmasqconfdir="${dnsmasqconfdir%%,*}" + [ ! -d "$dnsmasqconfdir" ] && mkdir -p "$dnsmasqconfdir" + xappend "--user=dnsmasq" + xappend "--group=dnsmasq" + echo >> "$CONFIGFILE_TMP" + + config_get_bool enable_tftp "$cfg" enable_tftp 0 + [ "$enable_tftp" -gt 0 ] && { + config_get tftp_root "$cfg" tftp_root + append EXTRA_MOUNT $tftp_root + } + + config_foreach filter_dnsmasq host dhcp_host_add "$cfg" + echo >> "$CONFIGFILE_TMP" + + config_get_bool dhcpbogushostname "$cfg" dhcpbogushostname 1 + [ "$dhcpbogushostname" -gt 0 ] && { + xappend "--dhcp-ignore-names=tag:dhcp_bogus_hostname" + [ -r "$DHCPBOGUSHOSTNAMEFILE" ] && xappend "--conf-file=$DHCPBOGUSHOSTNAMEFILE" + } + + config_foreach filter_dnsmasq boot dhcp_boot_add "$cfg" + config_foreach filter_dnsmasq mac dhcp_mac_add "$cfg" + config_foreach filter_dnsmasq tag dhcp_tag_add "$cfg" + config_foreach filter_dnsmasq vendorclass dhcp_vendorclass_add "$cfg" + config_foreach filter_dnsmasq userclass dhcp_userclass_add "$cfg" + config_foreach filter_dnsmasq circuitid dhcp_circuitid_add "$cfg" + config_foreach filter_dnsmasq remoteid dhcp_remoteid_add "$cfg" + config_foreach filter_dnsmasq subscrid dhcp_subscrid_add "$cfg" + config_foreach filter_dnsmasq match dhcp_match_add "$cfg" + config_foreach filter_dnsmasq domain dhcp_domain_add "$cfg" + config_foreach filter_dnsmasq hostrecord dhcp_hostrecord_add "$cfg" + config_foreach filter_dnsmasq dnsrr dhcp_dnsrr_add "$cfg" + [ -n "$BOOT" ] || config_foreach filter_dnsmasq relay dhcp_relay_add "$cfg" + + echo >> "$CONFIGFILE_TMP" + config_foreach filter_dnsmasq srvhost dhcp_srv_add "$cfg" + config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg" + echo >> "$CONFIGFILE_TMP" + + config_get_bool boguspriv "$cfg" boguspriv 1 + [ "$boguspriv" -gt 0 ] && { + xappend "--bogus-priv" + [ -r "$RFC6761FILE" ] && xappend "--conf-file=$RFC6761FILE" + } + + if [ "$DNSMASQ_DHCP_VER" -gt 4 ] ; then + # Enable RA feature for when/if it is constructed, + # and RA is selected per interface pool (RA, DHCP, or both), + # but no one (should) want RA broadcast in syslog + [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg" + xappend "--enable-ra" + xappend "--quiet-ra" + append_bool "$cfg" quietdhcp "--quiet-dhcp6" + + elif [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then + [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg" + fi + + + echo >> "$CONFIGFILE_TMP" + config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg" + echo >> "$CONFIGFILE_TMP" + + echo >> "$CONFIGFILE_TMP" + config_foreach filter_dnsmasq ipset dnsmasq_ipset_add "$cfg" + echo >> "$CONFIGFILE_TMP" + + mv -f "$CONFIGFILE_TMP" "$CONFIGFILE" + mv -f "$HOSTFILE_TMP" "$HOSTFILE" + + [ "$localuse" -gt 0 ] && { + rm -f /tmp/resolv.conf + [ $ADD_LOCAL_DOMAIN -eq 1 ] && [ -n "$DOMAIN" ] && { + echo "search $DOMAIN" >> /tmp/resolv.conf + } + DNS_SERVERS="$DNS_SERVERS 127.0.0.1" + [ -e /proc/sys/net/ipv6 ] && DNS_SERVERS="$DNS_SERVERS ::1" + for DNS_SERVER in $DNS_SERVERS ; do + echo "nameserver $DNS_SERVER" >> /tmp/resolv.conf + done + } + + config_list_foreach "$cfg" addnmount append_extramount + + procd_open_instance $cfg + procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid + procd_set_param file $CONFIGFILE + [ -n "$user_dhcpscript" ] && procd_set_param env USER_DHCPSCRIPT="$user_dhcpscript" + procd_set_param respawn + + local instance_ifc instance_netdev + config_get instance_ifc "$cfg" interface + [ -n "$instance_ifc" ] && network_get_device instance_netdev "$instance_ifc" && + [ -n "$instance_netdev" ] && procd_set_param netdev $instance_netdev + + procd_add_jail dnsmasq ubus log + procd_add_jail_mount $CONFIGFILE $DHCPBOGUSHOSTNAMEFILE $DHCPSCRIPT $DHCPSCRIPT_DEPENDS + procd_add_jail_mount $EXTRA_MOUNT $RFC6761FILE $TRUSTANCHORSFILE + procd_add_jail_mount $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript + procd_add_jail_mount /etc/passwd /etc/group /etc/TZ /etc/hosts /etc/ethers + procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile + case "$logfacility" in */*) + [ ! -e "$logfacility" ] && touch "$logfacility" + procd_add_jail_mount_rw "$logfacility" + esac + [ -e "$hostsfile" ] && procd_add_jail_mount $hostsfile + + procd_close_instance +} + +dnsmasq_stop() +{ + local cfg="$1" + local noresolv resolvfile localuse=1 + + config_get_bool noresolv "$cfg" noresolv 0 + config_get resolvfile "$cfg" "resolvfile" + + [ "$noresolv" = 0 ] && [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0 + config_get_bool localuse "$cfg" localuse "$localuse" + [ "$localuse" -gt 0 ] && ln -sf "/tmp/resolv.conf.d/resolv.conf.auto" /tmp/resolv.conf + + rm -f ${BASEDHCPSTAMPFILE}.${cfg}.*.dhcp +} + +add_interface_trigger() +{ + local interface ifname ignore + + config_get interface "$1" interface + config_get_bool ignore "$1" ignore 0 + network_get_device ifname "$interface" || ignore=0 + + [ -n "$interface" ] && [ $ignore -eq 0 ] && procd_add_interface_trigger "interface.*" "$interface" /etc/init.d/dnsmasq reload +} + +service_triggers() +{ + procd_add_reload_trigger "dhcp" "system" + + config_load dhcp + config_foreach add_interface_trigger dhcp + config_foreach add_interface_trigger relay +} + +boot() +{ + BOOT=1 + start "$@" +} + +start_service() { + local instance="$1" + local instance_found=0 + local first_instance="" + + . /lib/functions/network.sh + + config_cb() { + local type="$1" + local name="$2" + if [ "$type" = "dnsmasq" ]; then + if [ -n "$instance" ] && [ "$instance" = "$name" ]; then + instance_found=1 + fi + if [ -z "$DEFAULT_INSTANCE" ]; then + local disabled + config_get_bool disabled "$name" disabled 0 + if [ "$disabled" -eq 0 ]; then + # First enabled section will be assigned default instance name. + # Unnamed sections get precedence over named sections. + if expr "$cfg" : 'cfg[0-9a-f]*$' >/dev/null = "9"; then # See uci_fixup_section. + DEFAULT_INSTANCE="$name" # Unnamed config section. + elif [ -z "$first_instance" ]; then + first_instance="$name" + fi + fi + fi + fi + } + + DEFAULT_INSTANCE="" + config_load dhcp + if [ -z "$DEFAULT_INSTANCE" ]; then + DEFAULT_INSTANCE="$first_instance" # No unnamed config section was found. + fi + + if [ -n "$instance" ]; then + [ "$instance_found" -gt 0 ] || return + dnsmasq_start "$instance" + else + config_foreach dnsmasq_start dnsmasq + fi +} + +reload_service() { + rc_procd start_service "$@" + procd_send_signal dnsmasq "$@" +} + +stop_service() { + local instance="$1" + local instance_found=0 + + config_cb() { + local type="$1" + local name="$2" + if [ "$type" = "dnsmasq" ]; then + if [ -n "$instance" ] && [ "$instance" = "$name" ]; then + instance_found=1 + fi + fi + } + + config_load dhcp + + if [ -n "$instance" ]; then + [ "$instance_found" -gt 0 ] || return + dnsmasq_stop "$instance" + else + config_foreach dnsmasq_stop dnsmasq + fi +} diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index a23f59075..9cb6123f1 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -189,6 +189,12 @@ fi # Shortcut Forwarding Engine git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe +# dnsmasq +if [ "$version" = "snapshots-24.10" ]; then + curl -s https://$mirror/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch | patch -p1 + [ "$?" -ne 0 ] && curl -s https://init2.cooluc.com/openwrt/patch/dnsmasq/dnsmasq.init > package/network/services/dnsmasq/files/dnsmasq.init +fi + # Patch FireWall 4 if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then # firewall4 - master From 3324b5206fd2843bbaa54635e3b21f4dc9fe66ad Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Oct 2024 21:32:04 +0800 Subject: [PATCH 078/425] ci: allow building snapshot version Signed-off-by: sbwml --- .github/workflows/build-release.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index def0bfba1..7bea7471c 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: device: - description: 'Select device to build' + description: 'Select the build device' required: true default: 'x86_64' type: choice @@ -14,6 +14,14 @@ on: - 'nanopi-r5s' - 'netgear_r8500' - 'x86_64' + version: + description: 'Select the build version' + required: true + default: 'release' + type: choice + options: + - 'release' + - 'snapshot' build_options: description: 'Build options (separate multiple options with spaces)' required: false @@ -35,6 +43,7 @@ jobs: git config --global user.name 'actions' git config --global user.email 'action@github.com' echo WORKDIR="/builder" >> "$GITHUB_ENV" + [ "${{ github.event.inputs.version }}" = release ] && echo build_version="rc2" >> "$GITHUB_ENV" || echo build_version="dev" >> "$GITHUB_ENV" - name: Show system run: | @@ -65,9 +74,13 @@ jobs: run: | export GITHUB_REPO=${{ github.repository }} export ${{ github.event.inputs.build_options }} - bash <(curl -sS https://raw.githubusercontent.com/${{ github.repository }}/master/openwrt/build.sh) rc2 ${{ github.event.inputs.device }} + bash <(curl -sS https://raw.githubusercontent.com/${{ github.repository }}/master/openwrt/build.sh) ${{ env.build_version }} ${{ github.event.inputs.device }} cd openwrt - tags=$(git describe --abbrev=0 --tags) + if [ "${{ github.event.inputs.version }}" = release ]; then + tags=$(git describe --abbrev=0 --tags) + else + tags=snapshot-$(git log -n 1 --date=format:"%Y%m%d" --format="%cd")-$(git log --pretty=format:"%h" -1) + fi echo "latest_release=$tags" >>$GITHUB_ENV - name: Extensive logs after a failed compilation From 7b5f17faa34d6c4a5e94fca9052859d2392fb6f9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 23 Oct 2024 18:24:27 +0800 Subject: [PATCH 079/425] config-common: add `bash-completion` Signed-off-by: sbwml --- openwrt/23-config-common | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index ec08db772..93072b086 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -231,6 +231,7 @@ CONFIG_PACKAGE_kmod-mt7921u=y ### Utilities CONFIG_PACKAGE_bash=y +CONFIG_PACKAGE_bash-completion=y CONFIG_PACKAGE_dmesg=y CONFIG_PACKAGE_dosfstools=y CONFIG_PACKAGE_exfat-fsck=y From c9ae8f961b235aaff60b8ab7ff3a77e026bbfc9a Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 23 Oct 2024 18:24:56 +0800 Subject: [PATCH 080/425] dpdk: enable shared libraries by default * fix build for openwrt-24.10 Signed-off-by: sbwml --- openwrt/patch/dpdk/dpdk/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/patch/dpdk/dpdk/Makefile b/openwrt/patch/dpdk/dpdk/Makefile index b13764a2b..f92a757dd 100644 --- a/openwrt/patch/dpdk/dpdk/Makefile +++ b/openwrt/patch/dpdk/dpdk/Makefile @@ -154,6 +154,7 @@ MESON_ARGS+= \ $(if $(CONFIG_aarch64), -Dplatform=$(PLATFORM)) \ $(if $(CONFIG_x86_64),-Dplatform=generic -Dcpu_instruction_set=$(CPU_INST)) \ -Denable_drivers=$(subst $(SPACE),$(COMMA),$(strip $(DRIVERS))) \ + -Ddefault_library=shared define Package/libdpdk SECTION:=libs From 146c99d33164d377b7663206af642730da9a411f Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 23 Oct 2024 18:25:37 +0800 Subject: [PATCH 081/425] linux-6.6: bump to 6.6.58 Signed-off-by: sbwml --- tags/kernel-6.6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 index a5048a4e6..df3464ab4 100644 --- a/tags/kernel-6.6 +++ b/tags/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .57 -LINUX_KERNEL_HASH-6.6.57 = 66ce426ef96f99b8e1ef7ac72e780c730ef8b970f7aa5708501c4274d7abb7b3 +LINUX_VERSION-6.6 = .58 +LINUX_KERNEL_HASH-6.6.58 = e7df81e588d70fab5ec3ec3bb04ac53d51f0860fc3b1ec45e0a4167a026899db From e5050be1bae7e17dcd4b7e448a439250950cd72d Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 24 Oct 2024 15:43:23 +0800 Subject: [PATCH 082/425] snapshots: luci-nginx: temp fix Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 6393286d8..0c5336910 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,5 +1,10 @@ #!/bin/bash +# openwrt-24.xx - temp fix +if [ "$version" = "snapshots-24.10" ]; then + sed -i 's/luci-app-opkg/luci-app-package-manager/g' feeds/luci/collections/luci-nginx/Makefile +fi + # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile From e394126db745dd711db711cb5481df68b9c1f629 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 24 Oct 2024 18:24:02 +0800 Subject: [PATCH 083/425] x86: drop `kmod-drm-amdgpu` Signed-off-by: sbwml --- openwrt/23-config-musl-x86 | 1 - 1 file changed, 1 deletion(-) diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 22987a5ed..74b5fad14 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -41,7 +41,6 @@ CONFIG_PACKAGE_kmod-nvme=y ### Display & Extra Drivers CONFIG_PACKAGE_kmod-backlight-pwm=y CONFIG_PACKAGE_kmod-backlight=y -CONFIG_PACKAGE_kmod-drm-amdgpu=y CONFIG_PACKAGE_kmod-drm-i915=y CONFIG_PACKAGE_kmod-drm-kms-helper=y CONFIG_PACKAGE_kmod-drm-radeon=y From 4a9fafefd67172e074fa62cbe3570c4e197376b3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 24 Oct 2024 18:24:46 +0800 Subject: [PATCH 084/425] snapshots: apk-tools: hack build for linux pre-releases Signed-off-by: sbwml --- .../9999-hack-for-linux-pre-releases.patch | 23 +++++++++++++++++++ openwrt/scripts/05-fix-source.sh | 6 ++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch diff --git a/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch b/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch new file mode 100644 index 000000000..55fdbdd55 --- /dev/null +++ b/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch @@ -0,0 +1,23 @@ +--- a/src/apk_adb.c ++++ b/src/apk_adb.c +@@ -177,7 +177,6 @@ static struct adb_scalar_schema scalar_n + + static adb_val_t version_fromstring(struct adb *db, apk_blob_t val) + { +- if (!apk_version_validate(val)) return ADB_ERROR(APKE_PKGVERSION_FORMAT); + return adb_w_blob(db, val); + } + +@@ -338,12 +337,6 @@ static int dependency_fromstring(struct + apk_blob_t bname, bver; + int op; + +- if (apk_dep_parse(bdep, &bname, &op, &bver) != 0) goto fail; +- if ((op & APK_DEPMASK_CHECKSUM) != APK_DEPMASK_CHECKSUM && +- !apk_version_validate(bver)) goto fail; +- +- if (apk_blob_spn(bname, APK_CTYPE_DEPENDENCY_NAME, NULL, NULL)) goto fail; +- + adb_wo_blob(obj, ADBI_DEP_NAME, bname); + if (op != APK_DEPMASK_ANY) { + adb_wo_blob(obj, ADBI_DEP_VERSION, bver); diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 0c5336910..d8b5d6705 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,9 +1,13 @@ #!/bin/bash -# openwrt-24.xx - temp fix +######################### temp fix ########################### if [ "$version" = "snapshots-24.10" ]; then + # luci-nginx sed -i 's/luci-app-opkg/luci-app-package-manager/g' feeds/luci/collections/luci-nginx/Makefile + # apk-tools + curl -s https://init2.cooluc.com/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch fi +######################### temp fix ########################### # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile From 9ccdbbdc026d1fbcbec9ed266b4fee22c263e647 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 24 Oct 2024 18:41:30 +0800 Subject: [PATCH 085/425] minimal-common: add nginx config Signed-off-by: sbwml --- openwrt/23-config-minimal-common | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/openwrt/23-config-minimal-common b/openwrt/23-config-minimal-common index 8f37e65ea..63075d680 100644 --- a/openwrt/23-config-minimal-common +++ b/openwrt/23-config-minimal-common @@ -57,12 +57,30 @@ CONFIG_PACKAGE_luci-lib-ip=y CONFIG_PACKAGE_luci-lib-ipkg=y CONFIG_PACKAGE_luci-lib-jsonc=y CONFIG_PACKAGE_luci-lib-nixio=y -CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_nginx-all-module=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set +### Nginx +# openwrt-23.05 +CONFIG_PACKAGE_nginx-all-module=y +# openwrt-24.10 +CONFIG_PACKAGE_nginx-ssl=y +CONFIG_PACKAGE_nginx-mod-brotli=y +CONFIG_PACKAGE_nginx-mod-luci=y +CONFIG_PACKAGE_nginx-mod-rtmp=y +CONFIG_PACKAGE_nginx-mod-stream=y +CONFIG_PACKAGE_nginx-mod-ubus=y +CONFIG_PACKAGE_nginx-mod-zstd=y +CONFIG_PACKAGE_nginx-ssl-util=y +CONFIG_NGINX_DAV=y +CONFIG_NGINX_HTTP_AUTH_BASIC=y +CONFIG_NGINX_HTTP_QUIC=y +CONFIG_NGINX_HTTP_REAL_IP=y +CONFIG_NGINX_HTTP_SUB=y +CONFIG_NGINX_STREAM_REAL_IP=y + ### APPS CONFIG_PACKAGE_luci-app-autoreboot=y CONFIG_PACKAGE_luci-app-cpufreq=y From be1ce2e833e80f56cb1d39fef98994448737b43f Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 07:36:58 +0800 Subject: [PATCH 086/425] fixup 9ccdbbdc026d1fbcbec9ed266b4fee22c263e647 Signed-off-by: sbwml --- openwrt/23-config-minimal-common | 2 +- openwrt/scripts/00-prepare_base.sh | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openwrt/23-config-minimal-common b/openwrt/23-config-minimal-common index 63075d680..11e85efea 100644 --- a/openwrt/23-config-minimal-common +++ b/openwrt/23-config-minimal-common @@ -57,7 +57,7 @@ CONFIG_PACKAGE_luci-lib-ip=y CONFIG_PACKAGE_luci-lib-ipkg=y CONFIG_PACKAGE_luci-lib-jsonc=y CONFIG_PACKAGE_luci-lib-nixio=y -CONFIG_PACKAGE_nginx-all-module=y +CONFIG_PACKAGE_luci-nginx=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 9cb6123f1..8920bbde9 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -446,8 +446,10 @@ curl -s https://$mirror/openwrt/patch/luci/dhcp/${openwrt_version}-dhcp.js > fee [ "$platform" = "bcm53xx" ] && sed -i -e '/if (has_ap_sae || has_sta_sae) {/{N;N;N;N;d;}' feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js # ppp - 2.5.0 -rm -rf package/network/services/ppp -git clone https://$github/sbwml/package_network_services_ppp package/network/services/ppp +if [ "$version" = "rc2" ]; then + rm -rf package/network/services/ppp + git clone https://$github/sbwml/package_network_services_ppp package/network/services/ppp +fi # odhcpd RFC-9096 if [ "$version" = "rc2" ]; then From e4905d27613760181a8efebe9087874ee8c60a2b Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 08:35:23 +0800 Subject: [PATCH 087/425] nginx: move brotli & zstd configuration Signed-off-by: sbwml --- openwrt/nginx/openwrt-24.10-uci.conf.template | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/openwrt/nginx/openwrt-24.10-uci.conf.template b/openwrt/nginx/openwrt-24.10-uci.conf.template index 94d57c3ed..6ea39ae43 100644 --- a/openwrt/nginx/openwrt-24.10-uci.conf.template +++ b/openwrt/nginx/openwrt-24.10-uci.conf.template @@ -32,23 +32,6 @@ http { gzip on; gzip_vary on; gzip_proxied any; - brotli on; - brotli_comp_level 6; - brotli_static on; - brotli_types application/atom+xml application/javascript application/json application/rss+xml - application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype - application/x-font-ttf application/x-javascript application/xhtml+xml application/xml - font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon - image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; - zstd on; - zstd_comp_level 7; - zstd_min_length 1k; - zstd_static on; - zstd_types application/atom+xml application/javascript application/json application/rss+xml - application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype - application/x-font-ttf application/x-javascript application/xhtml+xml application/xml - font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon - image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; root /www; From 41d296d80cdcaf5b1cc9eb8bca4c774220da4a77 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 18:11:57 +0800 Subject: [PATCH 088/425] luci-app-firewall: Update Shortcut-FE and Natflow patches for snapshot Signed-off-by: sbwml --- ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 0 ...-app-firewall-add-shortcut-fe-option.patch | 0 ...uci-app-firewall-add-ipv6-nat-option.patch | 0 ...firewall-add-custom-nft-rule-support.patch | 0 ...firewall-add-natflow-offload-support.patch | 0 ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 34 ++++++++ ...-app-firewall-add-shortcut-fe-option.patch | 60 ++++++++++++++ ...uci-app-firewall-add-ipv6-nat-option.patch | 30 +++++++ ...firewall-add-custom-nft-rule-support.patch | 82 +++++++++++++++++++ ...firewall-add-natflow-offload-support.patch | 72 ++++++++++++++++ ...-luci-app-firewall-drop-bcm-fullcone.patch | 4 +- openwrt/scripts/00-prepare_base.sh | 12 +-- 12 files changed, 286 insertions(+), 8 deletions(-) rename openwrt/patch/firewall4/{ => openwrt-23.05}/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch (100%) rename openwrt/patch/firewall4/{ => openwrt-23.05}/0002-luci-app-firewall-add-shortcut-fe-option.patch (100%) rename openwrt/patch/firewall4/{ => openwrt-23.05}/0003-luci-app-firewall-add-ipv6-nat-option.patch (100%) rename openwrt/patch/firewall4/{ => openwrt-23.05}/0004-luci-add-firewall-add-custom-nft-rule-support.patch (100%) rename openwrt/patch/firewall4/{ => openwrt-23.05}/0005-luci-app-firewall-add-natflow-offload-support.patch (100%) create mode 100644 openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch create mode 100644 openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch create mode 100644 openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch create mode 100644 openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch create mode 100644 openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch rename openwrt/patch/firewall4/{ => openwrt-24.10}/0400-luci-app-firewall-drop-bcm-fullcone.patch (92%) diff --git a/openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/openwrt-23.05/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch similarity index 100% rename from openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch rename to openwrt/patch/firewall4/openwrt-23.05/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch diff --git a/openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/openwrt-23.05/0002-luci-app-firewall-add-shortcut-fe-option.patch similarity index 100% rename from openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch rename to openwrt/patch/firewall4/openwrt-23.05/0002-luci-app-firewall-add-shortcut-fe-option.patch diff --git a/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/openwrt-23.05/0003-luci-app-firewall-add-ipv6-nat-option.patch similarity index 100% rename from openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch rename to openwrt/patch/firewall4/openwrt-23.05/0003-luci-app-firewall-add-ipv6-nat-option.patch diff --git a/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/openwrt-23.05/0004-luci-add-firewall-add-custom-nft-rule-support.patch similarity index 100% rename from openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch rename to openwrt/patch/firewall4/openwrt-23.05/0004-luci-add-firewall-add-custom-nft-rule-support.patch diff --git a/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/openwrt-23.05/0005-luci-app-firewall-add-natflow-offload-support.patch similarity index 100% rename from openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch rename to openwrt/patch/firewall4/openwrt-23.05/0005-luci-app-firewall-add-natflow-offload-support.patch diff --git a/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch new file mode 100644 index 000000000..f3bf0e80b --- /dev/null +++ b/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch @@ -0,0 +1,34 @@ +From 06b6225c078330a3a56c201e1e152e9e7402ca92 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 4 Sep 2024 12:22:05 +0800 +Subject: [PATCH 1/5] luci-app-firewall: add nft-fullcone and bcm-fullcone + option + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/zones.js | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index 41b9834..404af97 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -58,6 +58,15 @@ return view.extend({ + + o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets')); + ++ if (L.hasSystemFeature('fullcone')) { ++ o = s.option(form.Flag, 'fullcone', _('Enable FullCone NAT')); ++ ++ o = s.option(form.Flag, 'brcmfullcone', _('BCM FullCone NAT scheme'), ++ _('Use the Broadcom FullCone NAT scheme if enabled, and use the NFT FullCone scheme if the option is disabled.')); ++ o.modalonly = true; ++ o.depends('fullcone', '1'); ++ }; ++ + var p = [ + s.option(form.ListValue, 'input', _('Input')), + s.option(form.ListValue, 'output', _('Output')), +-- +2.42.0 + diff --git a/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch new file mode 100644 index 000000000..12e2fcec8 --- /dev/null +++ b/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch @@ -0,0 +1,60 @@ +From a1f59bba3c004d0874e3c05c65217f37209638ae Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 25 Oct 2024 17:40:35 +0800 +Subject: [PATCH 2/5] luci-app-firewall: add shortcut-fe option + +Signed-off-by: sbwml +--- + .../resources/view/firewall/zones.js | 27 ++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index 404af97..396d61e 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -92,18 +92,39 @@ return view.extend({ + o.value('0', _("None")); + o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); + o.value('2', _("Hardware flow offloading"), _('Hardware based offloading for routing with/without NAT.') + ' ' + _(' Requires hardware NAT support.')); ++ if (L.hasSystemFeature('shortcutfe')) { ++ o.value('3', _("Shortcut-FE flow offloading"), _('Shortcut-FE based offloading for routing/NAT')); ++ } + o.optional = false; + o.load = function (section_id) { + var flow_offloading = uci.get('firewall', section_id, 'flow_offloading'); + var flow_offloading_hw = uci.get('firewall', section_id, 'flow_offloading_hw'); +- return (flow_offloading === '1') +- ? (flow_offloading_hw === '1' ? '2' : '1') +- : '0'; ++ var shortcut_fe = uci.get('firewall', section_id, 'shortcut_fe'); ++ if (flow_offloading === '1') { ++ return flow_offloading_hw === '1' ? '2' : '1'; ++ } else { ++ return shortcut_fe === '1' ? '3' : '0'; ++ } + }; + o.write = function(section_id, value) { ++ uci.unset('firewall', section_id, 'shortcut_fe'); + uci.set('firewall', section_id, 'flow_offloading', value === '0' ? null : '1'); + uci.set('firewall', section_id, 'flow_offloading_hw', value === '2' ? '1' : null); ++ if (value === '3') { ++ uci.unset('firewall', section_id, 'flow_offloading'); ++ uci.unset('firewall', section_id, 'flow_offloading_hw'); ++ uci.set('firewall', section_id, 'shortcut_fe', value === '3' ? '1' : null); ++ } + }; ++ ++ /* Shortcut-FE flow connection manager */ ++ o = s.option(form.ListValue, 'shortcut_fe_module', ++ _('Connection Manager'), ++ _('Set up the Shortcut-FE engine connection manager')); ++ o.value('shortcut-fe-cm', _('shortcut-fe-cm')); ++ o.value('fast-classifier', _('fast-classifier')); ++ o.default = 'shortcut-fe-cm'; ++ o.depends('offloading_type', '3'); + } + + +-- +2.42.0 + diff --git a/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch new file mode 100644 index 000000000..817a1b612 --- /dev/null +++ b/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch @@ -0,0 +1,30 @@ +From fe9ef405cbaf838d3920dab9439ab28db2d832d1 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 4 Sep 2024 12:35:13 +0800 +Subject: [PATCH 3/5] luci-app-firewall: add ipv6 nat option + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/zones.js | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index 396d61e..f26dba0 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -67,6 +67,12 @@ return view.extend({ + o.depends('fullcone', '1'); + }; + ++ if (L.hasSystemFeature('ipv6')) { ++ o = s.option(form.Flag, 'nat6', ++ _('IPv6 NAT'), ++ _('Applicable to internet environments where the router is not assigned an IPv6 prefix, such as when using an upstream optical modem for dial-up.')); ++ }; ++ + var p = [ + s.option(form.ListValue, 'input', _('Input')), + s.option(form.ListValue, 'output', _('Output')), +-- +2.42.0 + diff --git a/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch new file mode 100644 index 000000000..4d08d77dd --- /dev/null +++ b/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch @@ -0,0 +1,82 @@ +From 8ff3c9caad7446d191c7d40575a55e7753bcdaf5 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 4 Sep 2024 12:36:11 +0800 +Subject: [PATCH 4/5] luci-add-firewall: add custom nft rule support + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/custom.js | 6 +++--- + .../root/usr/share/luci/menu.d/luci-app-firewall.json | 3 --- + .../root/usr/share/rpcd/acl.d/luci-app-firewall.json | 6 ++++-- + 3 files changed, 7 insertions(+), 8 deletions(-) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js +index 1997a72..b3183d6 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js +@@ -5,13 +5,13 @@ + + return view.extend({ + load: function() { +- return L.resolveDefault(fs.read('/etc/firewall.user'), ''); ++ return L.resolveDefault(fs.read('/etc/firewall4.user'), ''); + }, + + handleSave: function(ev) { + var value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n'; + +- return fs.write('/etc/firewall.user', value).then(function(rc) { ++ return fs.write('/etc/firewall4.user', value).then(function(rc) { + document.querySelector('textarea').value = value; + ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'); + fs.exec('/etc/init.d/firewall', ['restart']); +@@ -23,7 +23,7 @@ return view.extend({ + render: function(fwuser) { + return E([ + E('h2', _('Firewall - Custom Rules')), +- E('p', {}, _('Custom rules allow you to execute arbitrary iptables commands which are not otherwise covered by the firewall framework. The commands are executed after each firewall restart, right after the default ruleset has been loaded.')), ++ E('p', {}, _('Custom rules allow you to execute arbitrary nft commands which are not otherwise covered by the firewall framework. The rules are executed after each firewall restart, right after the default ruleset has been loaded.')), + E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 25 }, [ fwuser != null ? fwuser : '' ])) + ]); + }, +diff --git a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json +index f024dcf..8aea702 100644 +--- a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json ++++ b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json +@@ -64,9 +64,6 @@ + "action": { + "type": "view", + "path": "firewall/custom" +- }, +- "depends": { +- "fs": { "/usr/share/fw3/helpers.conf": "file" } + } + } + } +diff --git a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json +index 17d1fba..7e06de7 100644 +--- a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json ++++ b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json +@@ -3,7 +3,8 @@ + "description": "Grant access to firewall configuration", + "read": { + "file": { +- "/etc/firewall.user": [ "read" ] ++ "/etc/firewall.user": [ "read" ], ++ "/etc/firewall4.user": [ "read" ] + }, + "ubus": { + "file": [ "read" ], +@@ -13,7 +14,8 @@ + }, + "write": { + "file": { +- "/etc/firewall.user": [ "write" ] ++ "/etc/firewall.user": [ "write" ], ++ "/etc/firewall4.user": [ "write" ] + }, + "ubus": { + "file": [ "write" ] +-- +2.42.0 + diff --git a/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch new file mode 100644 index 000000000..1584619ab --- /dev/null +++ b/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch @@ -0,0 +1,72 @@ +From f5532b047cbc0cc3fa4a9aa6ca8df7389ef85d51 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 25 Oct 2024 17:58:57 +0800 +Subject: [PATCH 5/5] luci-app-firewall: add natflow offload support + +Signed-off-by: sbwml +--- + .../resources/view/firewall/zones.js | 23 ++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index f26dba0..39faff5 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -101,25 +101,38 @@ return view.extend({ + if (L.hasSystemFeature('shortcutfe')) { + o.value('3', _("Shortcut-FE flow offloading"), _('Shortcut-FE based offloading for routing/NAT')); + } ++ if (L.hasSystemFeature('natflow')) { ++ o.value('4', _("Natflow offloading"), _('Natflow based offloading for routing/NAT')); ++ } + o.optional = false; + o.load = function (section_id) { + var flow_offloading = uci.get('firewall', section_id, 'flow_offloading'); + var flow_offloading_hw = uci.get('firewall', section_id, 'flow_offloading_hw'); + var shortcut_fe = uci.get('firewall', section_id, 'shortcut_fe'); ++ var natflow = uci.get('firewall', section_id, 'natflow'); + if (flow_offloading === '1') { + return flow_offloading_hw === '1' ? '2' : '1'; +- } else { ++ } else if (shortcut_fe === '1') { + return shortcut_fe === '1' ? '3' : '0'; ++ } else if (natflow === '1'){ ++ return natflow === '1' ? '4' : '0'; + } + }; + o.write = function(section_id, value) { + uci.unset('firewall', section_id, 'shortcut_fe'); ++ uci.unset('firewall', section_id, 'natflow'); + uci.set('firewall', section_id, 'flow_offloading', value === '0' ? null : '1'); + uci.set('firewall', section_id, 'flow_offloading_hw', value === '2' ? '1' : null); + if (value === '3') { + uci.unset('firewall', section_id, 'flow_offloading'); + uci.unset('firewall', section_id, 'flow_offloading_hw'); ++ uci.unset('firewall', section_id, 'natflow'); + uci.set('firewall', section_id, 'shortcut_fe', value === '3' ? '1' : null); ++ } else if (value === '4') { ++ uci.unset('firewall', section_id, 'flow_offloading'); ++ uci.unset('firewall', section_id, 'flow_offloading_hw'); ++ uci.unset('firewall', section_id, 'shortcut_fe'); ++ uci.set('firewall', section_id, 'natflow', value === '4' ? '1' : null); + } + }; + +@@ -131,6 +144,14 @@ return view.extend({ + o.value('fast-classifier', _('fast-classifier')); + o.default = 'shortcut-fe-cm'; + o.depends('offloading_type', '3'); ++ ++ /* Natflow delay packet */ ++ o = s.option(form.Value, 'natflow_delay_pkts', ++ _('Natflow delay packet'), ++ _('Set up the natflow delay packet')); ++ o.datatype = 'and(uinteger,min(0))'; ++ o.default = 4; ++ o.depends('offloading_type', '4'); + } + + +-- +2.42.0 + diff --git a/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch b/openwrt/patch/firewall4/openwrt-24.10/0400-luci-app-firewall-drop-bcm-fullcone.patch similarity index 92% rename from openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch rename to openwrt/patch/firewall4/openwrt-24.10/0400-luci-app-firewall-drop-bcm-fullcone.patch index bf41475fd..224c65912 100644 --- a/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch +++ b/openwrt/patch/firewall4/openwrt-24.10/0400-luci-app-firewall-drop-bcm-fullcone.patch @@ -1,4 +1,4 @@ -From a98c7f7c38228f17813744c0c4b82b3e92ee4654 Mon Sep 17 00:00:00 2001 +From 92d9b5d3b489188ccd51b1134e5bc028ccee44ba Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Oct 2024 22:54:31 +0800 Subject: [PATCH] luci-app-firewall: drop bcm-fullcone @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 5 deletions(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 522d001..9e86b35 100644 +index 39faff5..4776423 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -60,11 +60,6 @@ return view.extend({ diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 8920bbde9..7f625d9a1 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -244,12 +244,12 @@ git clone https://$github/sbwml/package_new_natflow package/new/natflow # Patch Luci add nft_fullcone/bcm_fullcone & shortcut-fe & natflow & ipv6-nat & custom nft command option pushd feeds/luci - curl -s https://$mirror/openwrt/patch/firewall4/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 - [ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/firewall4/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 + [ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 popd # openssl - quictls From 78c877178c7603ea49814a48d430663ac889e499 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 21:14:10 +0800 Subject: [PATCH 089/425] luci-app-firewall: enable hardware offload only on devices with `offload_hw` system feature Signed-off-by: sbwml --- ...l-enable-hardware-offload-only-on-de.patch | 29 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 5 +++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch diff --git a/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch b/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch new file mode 100644 index 000000000..6a7be872b --- /dev/null +++ b/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch @@ -0,0 +1,29 @@ +From f054cbad10a0a6f2cebf639e6b89b92c2d926447 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 25 Oct 2024 21:04:10 +0800 +Subject: [PATCH] luci-app-firewall: enable hardware offload only on devices + with `offload_hw` system feature + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/firewall/zones.js | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index 39faff5..ae16088 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -97,7 +97,9 @@ return view.extend({ + o = s.option(form.RichListValue, "offloading_type", _("Flow offloading type")); + o.value('0', _("None")); + o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); +- o.value('2', _("Hardware flow offloading"), _('Hardware based offloading for routing with/without NAT.') + ' ' + _(' Requires hardware NAT support.')); ++ if (L.hasSystemFeature('offload_hw')) { ++ o.value('2', _("Hardware flow offloading"), _('Hardware based offloading for routing with/without NAT.') + ' ' + _(' Requires hardware NAT support.')); ++ } + if (L.hasSystemFeature('shortcutfe')) { + o.value('3', _("Shortcut-FE flow offloading"), _('Shortcut-FE based offloading for routing/NAT')); + } +-- +2.42.0 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 7f625d9a1..80d893e33 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -249,7 +249,10 @@ pushd feeds/luci curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 - [ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 + [ "$version" = "snapshots-24.10" ] && { + curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 + } popd # openssl - quictls From 8cf9f7e43a599959a5a5754f21aece9359722fc2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 02:57:06 +0800 Subject: [PATCH 090/425] linux-6.12: re-add brcm fullcone support Signed-off-by: sbwml --- ...ftnl-add-fullcone-expression-support.patch | 4 +- ...2-libnftnl-add-brcm-fullcone-support.patch | 24 +++--- openwrt/patch/firewall4/libnftnl/Makefile | 75 ++++++++++++++++ ...bles-add-fullcone-expression-support.patch | 18 ++-- ...ftables-add-brcm-fullconenat-support.patch | 24 +++--- openwrt/patch/firewall4/nftables/Makefile | 85 +++++++++++++++++++ ...-luci-app-firewall-drop-bcm-fullcone.patch | 29 ------- openwrt/scripts/00-prepare_base.sh | 19 ++--- openwrt/scripts/01-prepare_base-mainline.sh | 7 +- 9 files changed, 206 insertions(+), 79 deletions(-) create mode 100644 openwrt/patch/firewall4/libnftnl/Makefile create mode 100644 openwrt/patch/firewall4/nftables/Makefile delete mode 100644 openwrt/patch/firewall4/openwrt-24.10/0400-luci-app-firewall-drop-bcm-fullcone.patch diff --git a/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch b/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch index 88e10ccc8..5e47e78b8 100644 --- a/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch +++ b/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch @@ -15,7 +15,7 @@ Signed-off-by: Syrone Wong --- a/include/libnftnl/expr.h +++ b/include/libnftnl/expr.h -@@ -245,6 +245,12 @@ enum { +@@ -272,6 +272,12 @@ enum { }; enum { @@ -226,7 +226,7 @@ Signed-off-by: Syrone Wong +struct expr_ops expr_ops_fullcone = { + .name = "fullcone", + .alloc_len = sizeof(struct nftnl_expr_fullcone), -+ .max_attr = NFTA_FULLCONE_MAX, ++ .nftnl_max_attr = NFTA_FULLCONE_MAX, + .set = nftnl_expr_fullcone_set, + .get = nftnl_expr_fullcone_get, + .parse = nftnl_expr_fullcone_parse, diff --git a/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch b/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch index f40a7a167..a4291e7f6 100644 --- a/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch +++ b/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch @@ -1,14 +1,14 @@ --- a/include/libnftnl/expr.h +++ b/include/libnftnl/expr.h -@@ -242,6 +242,8 @@ enum { +@@ -268,6 +268,8 @@ enum { NFTNL_EXPR_MASQ_FLAGS = NFTNL_EXPR_BASE, NFTNL_EXPR_MASQ_REG_PROTO_MIN, NFTNL_EXPR_MASQ_REG_PROTO_MAX, + NFTNL_EXPR_MASQ_REG_ADDR_MIN, + NFTNL_EXPR_MASQ_REG_ADDR_MAX, + __NFTNL_EXPR_MASQ_MAX }; - enum { --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -1453,12 +1453,16 @@ enum nft_tproxy_attributes { @@ -41,18 +41,18 @@ static int @@ -42,6 +44,12 @@ nftnl_expr_masq_set(struct nftnl_expr *e case NFTNL_EXPR_MASQ_REG_PROTO_MAX: - memcpy(&masq->sreg_proto_max, data, sizeof(masq->sreg_proto_max)); + memcpy(&masq->sreg_proto_max, data, data_len); break; + case NFTNL_EXPR_MASQ_REG_ADDR_MIN: -+ memcpy(&masq->sreg_addr_min, data, sizeof(masq->sreg_addr_min)); ++ memcpy(&masq->sreg_addr_min, data, data_len); + break; + case NFTNL_EXPR_MASQ_REG_ADDR_MAX: -+ memcpy(&masq->sreg_addr_max, data, sizeof(masq->sreg_addr_max)); ++ memcpy(&masq->sreg_addr_max, data, data_len); + break; - default: - return -1; } -@@ -64,6 +72,12 @@ nftnl_expr_masq_get(const struct nftnl_e + return 0; + } +@@ -62,6 +70,12 @@ nftnl_expr_masq_get(const struct nftnl_e case NFTNL_EXPR_MASQ_REG_PROTO_MAX: *data_len = sizeof(masq->sreg_proto_max); return &masq->sreg_proto_max; @@ -65,7 +65,7 @@ } return NULL; } -@@ -80,6 +94,8 @@ static int nftnl_expr_masq_cb(const stru +@@ -78,6 +92,8 @@ static int nftnl_expr_masq_cb(const stru case NFTA_MASQ_REG_PROTO_MIN: case NFTA_MASQ_REG_PROTO_MAX: case NFTA_MASQ_FLAGS: @@ -74,7 +74,7 @@ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; -@@ -102,6 +118,12 @@ nftnl_expr_masq_build(struct nlmsghdr *n +@@ -100,6 +116,12 @@ nftnl_expr_masq_build(struct nlmsghdr *n if (e->flags & (1 << NFTNL_EXPR_MASQ_REG_PROTO_MAX)) mnl_attr_put_u32(nlh, NFTA_MASQ_REG_PROTO_MAX, htobe32(masq->sreg_proto_max)); @@ -87,7 +87,7 @@ } static int -@@ -127,6 +149,16 @@ nftnl_expr_masq_parse(struct nftnl_expr +@@ -125,6 +147,16 @@ nftnl_expr_masq_parse(struct nftnl_expr be32toh(mnl_attr_get_u32(tb[NFTA_MASQ_REG_PROTO_MAX])); e->flags |= (1 << NFTNL_EXPR_MASQ_REG_PROTO_MAX); } @@ -104,7 +104,7 @@ return 0; } -@@ -151,6 +183,16 @@ static int nftnl_expr_masq_snprintf(char +@@ -149,6 +181,16 @@ static int nftnl_expr_masq_snprintf(char ret = snprintf(buf + offset, remain, "flags 0x%x ", masq->flags); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } diff --git a/openwrt/patch/firewall4/libnftnl/Makefile b/openwrt/patch/firewall4/libnftnl/Makefile new file mode 100644 index 000000000..f06b22399 --- /dev/null +++ b/openwrt/patch/firewall4/libnftnl/Makefile @@ -0,0 +1,75 @@ +# +# Copyright (C) 2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=libnftnl +PKG_CPE_ID:=cpe:/a:netfilter:libnftnl +PKG_VERSION:=1.2.8 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz +PKG_SOURCE_URL:=https://netfilter.org/projects/$(PKG_NAME)/files +PKG_HASH:=37fea5d6b5c9b08de7920d298de3cdc942e7ae64b1a3e8b880b2d390ae67ad95 + +PKG_MAINTAINER:=Steven Barth +PKG_LICENSE:=GPL-2.0-or-later +PKG_LICENSE_FILES:=COPYING + +PKG_INSTALL:=1 +PKG_BUILD_PARALLEL:=1 +PKG_BUILD_FLAGS:=lto + +include $(INCLUDE_DIR)/package.mk + +DISABLE_NLS:= + +define Package/libnftnl + SECTION:=libs + CATEGORY:=Libraries + DEPENDS:=+libmnl + TITLE:=Low-level netlink library for the nf_tables subsystem + URL:=http://www.netfilter.org/projects/libnftnl + ABI_VERSION:=11 +endef + +define Package/libnftnl/description + libnftnl is a userspace library providing a low-level netlink + programming interface (API) to the in-kernel nf_tables subsystem. +endef + +TARGET_CFLAGS += $(FPIC) + +CONFIGURE_ARGS += \ + --enable-static \ + --enable-shared + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include/libnftnl + $(CP) \ + $(PKG_INSTALL_DIR)/usr/include/libnftnl/*.h \ + $(1)/usr/include/libnftnl/ + + $(INSTALL_DIR) $(1)/usr/lib + $(CP) \ + $(PKG_INSTALL_DIR)/usr/lib/libnftnl.{so*,a,la} \ + $(1)/usr/lib/ + + $(INSTALL_DIR) $(1)/usr/lib/pkgconfig + $(CP) \ + $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnftnl.pc \ + $(1)/usr/lib/pkgconfig/ +endef + +define Package/libnftnl/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) \ + $(PKG_INSTALL_DIR)/usr/lib/libnftnl.so.* \ + $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,libnftnl)) diff --git a/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch b/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch index f1bf9c5d6..06679839e 100644 --- a/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch +++ b/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch @@ -51,7 +51,7 @@ Signed-off-by: Syrone Wong --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c -@@ -1471,6 +1471,53 @@ out_err: +@@ -1467,6 +1467,53 @@ out_err: stmt_free(stmt); } @@ -105,7 +105,7 @@ Signed-off-by: Syrone Wong static void netlink_parse_redir(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) -@@ -1901,6 +1948,7 @@ static const struct expr_handler netlink +@@ -1897,6 +1944,7 @@ static const struct expr_handler netlink { .name = "tproxy", .parse = netlink_parse_tproxy }, { .name = "notrack", .parse = netlink_parse_notrack }, { .name = "masq", .parse = netlink_parse_masq }, @@ -115,7 +115,7 @@ Signed-off-by: Syrone Wong { .name = "queue", .parse = netlink_parse_queue }, --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c -@@ -1222,6 +1222,13 @@ static void netlink_gen_nat_stmt(struct +@@ -1226,6 +1226,13 @@ static void netlink_gen_nat_stmt(struct nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN; nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX; break; @@ -131,7 +131,7 @@ Signed-off-by: Syrone Wong --- a/src/parser_bison.y +++ b/src/parser_bison.y -@@ -623,6 +623,7 @@ int nft_lex(void *, void *, void *); +@@ -643,6 +643,7 @@ int nft_lex(void *, void *, void *); %token SNAT "snat" %token DNAT "dnat" %token MASQUERADE "masquerade" @@ -139,7 +139,7 @@ Signed-off-by: Syrone Wong %token REDIRECT "redirect" %token RANDOM "random" %token FULLY_RANDOM "fully-random" -@@ -757,8 +758,8 @@ int nft_lex(void *, void *, void *); +@@ -784,8 +785,8 @@ int nft_lex(void *, void *, void *); %type limit_burst_pkts limit_burst_bytes limit_mode limit_bytes time_unit quota_mode %type reject_stmt reject_stmt_alloc %destructor { stmt_free($$); } reject_stmt reject_stmt_alloc @@ -150,7 +150,7 @@ Signed-off-by: Syrone Wong %type nf_nat_flags nf_nat_flag offset_opt %type tproxy_stmt %destructor { stmt_free($$); } tproxy_stmt -@@ -3070,6 +3071,7 @@ stmt : verdict_stmt +@@ -3216,6 +3217,7 @@ stmt : verdict_stmt | queue_stmt | ct_stmt | masq_stmt close_scope_nat @@ -158,7 +158,7 @@ Signed-off-by: Syrone Wong | redir_stmt close_scope_nat | dup_stmt close_scope_dup | fwd_stmt close_scope_fwd -@@ -3982,6 +3984,28 @@ masq_stmt_args : TO COLON stmt_expr +@@ -3999,6 +4001,28 @@ masq_stmt_args : TO COLON stmt_expr { $0->nat.proto = $3; } @@ -189,7 +189,7 @@ Signed-off-by: Syrone Wong $0->nat.proto = $3; --- a/src/scanner.l +++ b/src/scanner.l -@@ -463,6 +463,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr +@@ -462,6 +462,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr "snat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; } "dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; } "masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; } @@ -199,7 +199,7 @@ Signed-off-by: Syrone Wong { --- a/src/statement.c +++ b/src/statement.c -@@ -678,6 +678,7 @@ const char *nat_etype2str(enum nft_nat_e +@@ -674,6 +674,7 @@ const char *nat_etype2str(enum nft_nat_e [NFT_NAT_SNAT] = "snat", [NFT_NAT_DNAT] = "dnat", [NFT_NAT_MASQ] = "masquerade", diff --git a/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch b/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch index 1253e3df3..a3e891a29 100644 --- a/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch +++ b/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch @@ -19,7 +19,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c -@@ -1430,6 +1430,7 @@ static void netlink_parse_masq(struct ne +@@ -1426,6 +1426,7 @@ static void netlink_parse_masq(struct ne { enum nft_registers reg1, reg2; struct expr *proto; @@ -27,7 +27,7 @@ struct stmt *stmt; uint32_t flags = 0; -@@ -1465,6 +1466,29 @@ static void netlink_parse_masq(struct ne +@@ -1461,6 +1462,29 @@ static void netlink_parse_masq(struct ne stmt->nat.proto = proto; } @@ -59,7 +59,7 @@ out_err: --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c -@@ -1201,7 +1201,10 @@ static void netlink_gen_nat_stmt(struct +@@ -1205,7 +1205,10 @@ static void netlink_gen_nat_stmt(struct int registers = 0; int nftnl_flag_attr; int nftnl_reg_pmin, nftnl_reg_pmax; @@ -70,7 +70,7 @@ switch (stmt->nat.type) { case NFT_NAT_SNAT: case NFT_NAT_DNAT: -@@ -1221,6 +1224,8 @@ static void netlink_gen_nat_stmt(struct +@@ -1225,6 +1228,8 @@ static void netlink_gen_nat_stmt(struct nftnl_flag_attr = NFTNL_EXPR_MASQ_FLAGS; nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN; nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX; @@ -79,7 +79,7 @@ break; case NFT_NAT_FULLCONE: nle = alloc_nft_expr("fullcone"); -@@ -1254,13 +1259,13 @@ static void netlink_gen_nat_stmt(struct +@@ -1258,13 +1263,13 @@ static void netlink_gen_nat_stmt(struct netlink_gen_expr(ctx, stmt->nat.addr->left, amin_reg); netlink_gen_expr(ctx, stmt->nat.addr->right, amax_reg); @@ -96,7 +96,7 @@ amin_reg); if (stmt->nat.addr->etype == EXPR_MAP && stmt->nat.addr->mappings->set->data->flags & EXPR_F_INTERVAL) { -@@ -1269,7 +1274,7 @@ static void netlink_gen_nat_stmt(struct +@@ -1273,7 +1278,7 @@ static void netlink_gen_nat_stmt(struct netlink_put_register(nle, nftnl_reg_pmin, amin_reg); } else { @@ -105,7 +105,7 @@ amin_reg); } } -@@ -1285,7 +1290,7 @@ static void netlink_gen_nat_stmt(struct +@@ -1289,7 +1294,7 @@ static void netlink_gen_nat_stmt(struct if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL) { pmin_reg += netlink_register_space(nat_addrlen(family)); @@ -116,7 +116,7 @@ --- a/src/parser_bison.y +++ b/src/parser_bison.y -@@ -624,6 +624,7 @@ int nft_lex(void *, void *, void *); +@@ -644,6 +644,7 @@ int nft_lex(void *, void *, void *); %token DNAT "dnat" %token MASQUERADE "masquerade" %token FULLCONE "fullcone" @@ -124,7 +124,7 @@ %token REDIRECT "redirect" %token RANDOM "random" %token FULLY_RANDOM "fully-random" -@@ -3993,6 +3994,15 @@ masq_stmt_args : TO COLON stmt_expr +@@ -4010,6 +4011,15 @@ masq_stmt_args : TO COLON stmt_expr { $0->nat.flags = $1; } @@ -142,7 +142,7 @@ fullcone_stmt : fullcone_stmt_alloc fullcone_stmt_args --- a/src/scanner.l +++ b/src/scanner.l -@@ -464,6 +464,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr +@@ -463,6 +463,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr "dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; } "masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; } "fullcone" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return FULLCONE; } @@ -152,7 +152,7 @@ { --- a/src/statement.c +++ b/src/statement.c -@@ -687,6 +687,7 @@ const char *nat_etype2str(enum nft_nat_e +@@ -683,6 +683,7 @@ const char *nat_etype2str(enum nft_nat_e static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { @@ -160,7 +160,7 @@ nft_print(octx, "%s", nat_etype2str(stmt->nat.type)); if (stmt->nat.addr || stmt->nat.proto) { switch (stmt->nat.family) { -@@ -700,11 +701,13 @@ static void nat_stmt_print(const struct +@@ -696,11 +697,13 @@ static void nat_stmt_print(const struct if (stmt->nat.type_flags & STMT_NAT_F_PREFIX) nft_print(octx, " prefix"); diff --git a/openwrt/patch/firewall4/nftables/Makefile b/openwrt/patch/firewall4/nftables/Makefile new file mode 100644 index 000000000..06b3fcfcd --- /dev/null +++ b/openwrt/patch/firewall4/nftables/Makefile @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2015 OpenWrt.org +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=nftables +PKG_VERSION:=1.1.1 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz +PKG_SOURCE_URL:=https://netfilter.org/projects/$(PKG_NAME)/files +PKG_HASH:=6358830f3a64f31e39b0ad421d7dadcd240b72343ded48d8ef13b8faf204865a + +PKG_MAINTAINER:= +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:=COPYING + +PKG_FIXUP:=autoreconf +PKG_INSTALL:=1 + +PKG_BUILD_FLAGS:=lto + +include $(INCLUDE_DIR)/package.mk + +DISABLE_NLS:= + +CONFIGURE_ARGS += \ + --disable-debug \ + --disable-man-doc \ + --with-mini-gmp \ + --without-cli \ + --disable-python + +define Package/nftables/Default + SECTION:=net + CATEGORY:=Network + SUBMENU:=Firewall + TITLE:=nftables userspace utility + DEPENDS:=+kmod-nft-core +libnftnl + URL:=http://netfilter.org/projects/nftables/ + PROVIDES:=nftables +endef + +define Package/nftables-nojson + $(Package/nftables/Default) + TITLE+= no JSON support + VARIANT:=nojson + DEFAULT_VARIANT:=1 + CONFLICTS:=nftables-json +endef + +define Package/nftables-json + $(Package/nftables/Default) + TITLE+= with JSON support + VARIANT:=json + DEPENDS+=+jansson +endef + +ifeq ($(BUILD_VARIANT),json) + CONFIGURE_ARGS += --with-json +endif + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/lib $(1)/usr/include + $(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/ + $(CP) $(PKG_INSTALL_DIR)/usr/include/nftables $(1)/usr/include/ + $(INSTALL_DIR) $(1)/usr/lib/pkgconfig + $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnftables.pc \ + $(1)/usr/lib/pkgconfig/ +endef + +define Package/nftables/install/Default + $(INSTALL_DIR) $(1)/usr/sbin + $(CP) $(PKG_INSTALL_DIR)/usr/sbin/nft $(1)/usr/sbin/ + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/ +endef + +Package/nftables-nojson/install = $(Package/nftables/install/Default) +Package/nftables-json/install = $(Package/nftables/install/Default) + +$(eval $(call BuildPackage,nftables-nojson)) +$(eval $(call BuildPackage,nftables-json)) diff --git a/openwrt/patch/firewall4/openwrt-24.10/0400-luci-app-firewall-drop-bcm-fullcone.patch b/openwrt/patch/firewall4/openwrt-24.10/0400-luci-app-firewall-drop-bcm-fullcone.patch deleted file mode 100644 index 224c65912..000000000 --- a/openwrt/patch/firewall4/openwrt-24.10/0400-luci-app-firewall-drop-bcm-fullcone.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 92d9b5d3b489188ccd51b1134e5bc028ccee44ba Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Tue, 1 Oct 2024 22:54:31 +0800 -Subject: [PATCH] luci-app-firewall: drop bcm-fullcone - -Signed-off-by: sbwml ---- - .../htdocs/luci-static/resources/view/firewall/zones.js | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 39faff5..4776423 100644 ---- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -+++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -60,11 +60,6 @@ return view.extend({ - - if (L.hasSystemFeature('fullcone')) { - o = s.option(form.Flag, 'fullcone', _('Enable FullCone NAT')); -- -- o = s.option(form.Flag, 'brcmfullcone', _('BCM FullCone NAT scheme'), -- _('Use the Broadcom FullCone NAT scheme if enabled, and use the NFT FullCone scheme if the option is disabled.')); -- o.modalonly = true; -- o.depends('fullcone', '1'); - }; - - if (L.hasSystemFeature('ipv6')) { --- -2.42.0 - diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 80d893e33..b65e93770 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -215,22 +215,18 @@ if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then # add custom nft command support curl -s https://$mirror/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch | patch -p1 # libnftnl - [ "$version" = "rc2" ] && rm -rf package/libs/libnftnl - [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/libs/libnftnl package/libs/libnftnl + rm -rf package/libs/libnftnl mkdir -p package/libs/libnftnl/patches + curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/Makefile > package/libs/libnftnl/Makefile curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/001-libnftnl-add-fullcone-expression-support.patch - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch + curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch sed -i '/PKG_INSTALL:=1/iPKG_FIXUP:=autoreconf' package/libs/libnftnl/Makefile # nftables - [ "$version" = "rc2" ] && rm -rf package/network/utils/nftables - [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/network/utils/nftables package/network/utils/nftables + rm -rf package/network/utils/nftables mkdir -p package/network/utils/nftables/patches + curl -s https://$mirror/openwrt/patch/firewall4/nftables/Makefile > package/network/utils/nftables/Makefile curl -s https://$mirror/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/002-nftables-add-fullcone-expression-support.patch - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch - # hide nftables warning message - pushd feeds/luci - curl -s https://$mirror/openwrt/patch/luci/luci-nftables.patch | patch -p1 - popd + curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch fi # FullCone module @@ -251,8 +247,9 @@ pushd feeds/luci curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 [ "$version" = "snapshots-24.10" ] && { curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0400-luci-app-firewall-drop-bcm-fullcone.patch | patch -p1 } + # hide nftables warning message + curl -s https://$mirror/openwrt/patch/luci/luci-nftables.patch | patch -p1 popd # openssl - quictls diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 7c29299e9..d1e92001c 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -225,13 +225,12 @@ curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/arm64/312-arm64-cpu # fullcone curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-$kernel_version/952-net-conntrack-events-support-multiple-registrant.patch # bcm-fullcone -[ "$version" = "rc2" ] && { - curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-$kernel_version/982-add-bcm-fullcone-support.patch - curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-$kernel_version/983-add-bcm-fullcone-nft_masq-support.patch -} +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-$kernel_version/982-add-bcm-fullcone-support.patch +curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-$kernel_version/983-add-bcm-fullcone-nft_masq-support.patch # shortcut-fe curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-$kernel_version/601-netfilter-export-udp_get_timeouts-function.patch curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-$kernel_version/953-net-patch-linux-kernel-to-support-shortcut-fe.patch + # backport - 6.8 fast-path-variables if [ "$version" = "rc2" ] && [ "$platform" != "bcm53xx" ]; then curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch > target/linux/generic/backport-6.6/901-v6.8-cache-enforce-cache-groups.patch From 815beac75295f638f1b1a50b1c650b6e1b290504 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 03:43:18 +0800 Subject: [PATCH 091/425] luci-app-firewall: make a dropdown list for fullcone nat options * openwrt-24.10 Signed-off-by: sbwml --- ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 40 ++++++++++++------- ...-app-firewall-add-shortcut-fe-option.patch | 8 ++-- ...uci-app-firewall-add-ipv6-nat-option.patch | 14 +++---- ...firewall-add-custom-nft-rule-support.patch | 4 +- ...firewall-add-natflow-offload-support.patch | 10 ++--- ...l-enable-hardware-offload-only-on-de.patch | 10 ++--- 6 files changed, 49 insertions(+), 37 deletions(-) diff --git a/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch index f3bf0e80b..ac61cf2b1 100644 --- a/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch +++ b/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch @@ -1,30 +1,42 @@ -From 06b6225c078330a3a56c201e1e152e9e7402ca92 Mon Sep 17 00:00:00 2001 +From 314fbe82b79b19499507ec5e8043a4b32c9885a8 Mon Sep 17 00:00:00 2001 From: sbwml -Date: Wed, 4 Sep 2024 12:22:05 +0800 -Subject: [PATCH 1/5] luci-app-firewall: add nft-fullcone and bcm-fullcone +Date: Sat, 26 Oct 2024 03:35:05 +0800 +Subject: [PATCH 1/6] luci-app-firewall: add nft-fullcone and bcm-fullcone option Signed-off-by: sbwml --- - .../htdocs/luci-static/resources/view/firewall/zones.js | 9 +++++++++ - 1 file changed, 9 insertions(+) + .../resources/view/firewall/zones.js | 21 +++++++++++++++++++ + 1 file changed, 21 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 41b9834..404af97 100644 +index 41b9834..b41ebae 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -58,6 +58,15 @@ return view.extend({ +@@ -58,6 +58,27 @@ return view.extend({ o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets')); -+ if (L.hasSystemFeature('fullcone')) { -+ o = s.option(form.Flag, 'fullcone', _('Enable FullCone NAT')); ++ /* Netfilter FullCone NAT support */ + -+ o = s.option(form.Flag, 'brcmfullcone', _('BCM FullCone NAT scheme'), -+ _('Use the Broadcom FullCone NAT scheme if enabled, and use the NFT FullCone scheme if the option is disabled.')); -+ o.modalonly = true; -+ o.depends('fullcone', '1'); -+ }; ++ if (L.hasSystemFeature('fullcone')) { ++ o = s.option(form.RichListValue, "fullcone_type", _("Full Cone NAT")); ++ o.value('0', _("Disable")); ++ o.value('1', _("Nftables Fullcone nat"), _('Nftables based fullcone nat scheme.')); ++ o.value('2', _("Broadcom Fullcone nat"), _('Broadcom based fullcone nat scheme.')); ++ o.optional = false; ++ o.load = function (section_id) { ++ var fullcone = uci.get('firewall', section_id, 'fullcone'); ++ var brcmfullcone = uci.get('firewall', section_id, 'brcmfullcone'); ++ return (fullcone === '1') ++ ? (brcmfullcone === '1' ? '2' : '1') ++ : '0'; ++ }; ++ o.write = function(section_id, value) { ++ uci.set('firewall', section_id, 'fullcone', value === '0' ? null : '1'); ++ uci.set('firewall', section_id, 'brcmfullcone', value === '2' ? '1' : null); ++ }; ++ } + var p = [ s.option(form.ListValue, 'input', _('Input')), diff --git a/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch index 12e2fcec8..68cdcad6b 100644 --- a/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch +++ b/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch @@ -1,7 +1,7 @@ -From a1f59bba3c004d0874e3c05c65217f37209638ae Mon Sep 17 00:00:00 2001 +From 23efb4fefdc8acf49623b67b93079f79b3594b69 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 17:40:35 +0800 -Subject: [PATCH 2/5] luci-app-firewall: add shortcut-fe option +Subject: [PATCH 2/6] luci-app-firewall: add shortcut-fe option Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 404af97..396d61e 100644 +index b41ebae..12626c5 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -92,18 +92,39 @@ return view.extend({ +@@ -104,18 +104,39 @@ return view.extend({ o.value('0', _("None")); o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); o.value('2', _("Hardware flow offloading"), _('Hardware based offloading for routing with/without NAT.') + ' ' + _(' Requires hardware NAT support.')); diff --git a/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch index 817a1b612..14ceec8c7 100644 --- a/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch +++ b/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch @@ -1,7 +1,7 @@ -From fe9ef405cbaf838d3920dab9439ab28db2d832d1 Mon Sep 17 00:00:00 2001 +From fdf42e33bb356f2cf86edc42926f508a1c74624d Mon Sep 17 00:00:00 2001 From: sbwml -Date: Wed, 4 Sep 2024 12:35:13 +0800 -Subject: [PATCH 3/5] luci-app-firewall: add ipv6 nat option +Date: Sat, 26 Oct 2024 03:37:02 +0800 +Subject: [PATCH 3/6] luci-app-firewall: add ipv6 nat option Signed-off-by: sbwml --- @@ -9,12 +9,12 @@ Signed-off-by: sbwml 1 file changed, 6 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 396d61e..f26dba0 100644 +index 12626c5..a1fb06d 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -67,6 +67,12 @@ return view.extend({ - o.depends('fullcone', '1'); - }; +@@ -79,6 +79,12 @@ return view.extend({ + }; + } + if (L.hasSystemFeature('ipv6')) { + o = s.option(form.Flag, 'nat6', diff --git a/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch index 4d08d77dd..858e9da34 100644 --- a/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch +++ b/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch @@ -1,7 +1,7 @@ -From 8ff3c9caad7446d191c7d40575a55e7753bcdaf5 Mon Sep 17 00:00:00 2001 +From 523ec5d7928c348370e9de52adc6d14e5a13c63f Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Sep 2024 12:36:11 +0800 -Subject: [PATCH 4/5] luci-add-firewall: add custom nft rule support +Subject: [PATCH 4/6] luci-add-firewall: add custom nft rule support Signed-off-by: sbwml --- diff --git a/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch index 1584619ab..ab56b1827 100644 --- a/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch +++ b/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch @@ -1,7 +1,7 @@ -From f5532b047cbc0cc3fa4a9aa6ca8df7389ef85d51 Mon Sep 17 00:00:00 2001 +From 880db92c404fb4842fa31439c174224da4fd245d Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 17:58:57 +0800 -Subject: [PATCH 5/5] luci-app-firewall: add natflow offload support +Subject: [PATCH 5/6] luci-app-firewall: add natflow offload support Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index f26dba0..39faff5 100644 +index a1fb06d..447c42b 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -101,25 +101,38 @@ return view.extend({ +@@ -113,25 +113,38 @@ return view.extend({ if (L.hasSystemFeature('shortcutfe')) { o.value('3', _("Shortcut-FE flow offloading"), _('Shortcut-FE based offloading for routing/NAT')); } @@ -52,7 +52,7 @@ index f26dba0..39faff5 100644 } }; -@@ -131,6 +144,14 @@ return view.extend({ +@@ -143,6 +156,14 @@ return view.extend({ o.value('fast-classifier', _('fast-classifier')); o.default = 'shortcut-fe-cm'; o.depends('offloading_type', '3'); diff --git a/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch b/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch index 6a7be872b..32a0fc54b 100644 --- a/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch +++ b/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch @@ -1,8 +1,8 @@ -From f054cbad10a0a6f2cebf639e6b89b92c2d926447 Mon Sep 17 00:00:00 2001 +From 8fd15c7ea624ba143176caeca61fd34cbbb6a195 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 21:04:10 +0800 -Subject: [PATCH] luci-app-firewall: enable hardware offload only on devices - with `offload_hw` system feature +Subject: [PATCH 6/6] luci-app-firewall: enable hardware offload only on + devices with `offload_hw` system feature Signed-off-by: sbwml --- @@ -10,10 +10,10 @@ Signed-off-by: sbwml 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 39faff5..ae16088 100644 +index 447c42b..a527abb 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -97,7 +97,9 @@ return view.extend({ +@@ -109,7 +109,9 @@ return view.extend({ o = s.option(form.RichListValue, "offloading_type", _("Flow offloading type")); o.value('0', _("None")); o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); From a9a1cd1475f35680242d8af9fe89a316104f2d11 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 03:56:37 +0800 Subject: [PATCH 092/425] scripts: clean up Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index b65e93770..4aae706f7 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -248,8 +248,6 @@ pushd feeds/luci [ "$version" = "snapshots-24.10" ] && { curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 } - # hide nftables warning message - curl -s https://$mirror/openwrt/patch/luci/luci-nftables.patch | patch -p1 popd # openssl - quictls From 9a9ff575f196ff4d0c7bc975f6dd42a2cacbb9a8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 04:17:55 +0800 Subject: [PATCH 093/425] kernel-6.6/6.12: enable Multi-Path TCP for aarch64 & x86_64 Signed-off-by: sbwml --- openwrt/23-config-musl-armsr-armv8 | 2 + openwrt/23-config-musl-r4s | 2 + openwrt/23-config-musl-r5s | 2 + openwrt/23-config-musl-x86 | 2 + ...lti-Path-TCP-for-SMALL_FLASH-targets.patch | 39 +++++++++++++++++++ ...lti-Path-TCP-for-SMALL_FLASH-targets.patch | 39 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 3 ++ 7 files changed, 89 insertions(+) create mode 100644 openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch create mode 100644 openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch diff --git a/openwrt/23-config-musl-armsr-armv8 b/openwrt/23-config-musl-armsr-armv8 index 4476b0d2e..c4da496ef 100644 --- a/openwrt/23-config-musl-armsr-armv8 +++ b/openwrt/23-config-musl-armsr-armv8 @@ -9,6 +9,8 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_MPTCP=y +CONFIG_KERNEL_MPTCP_IPV6=y # CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y diff --git a/openwrt/23-config-musl-r4s b/openwrt/23-config-musl-r4s index 60160bb86..2bd107954 100644 --- a/openwrt/23-config-musl-r4s +++ b/openwrt/23-config-musl-r4s @@ -9,6 +9,8 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_MPTCP=y +CONFIG_KERNEL_MPTCP_IPV6=y # CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y diff --git a/openwrt/23-config-musl-r5s b/openwrt/23-config-musl-r5s index a0fc3ee69..c5224bfee 100644 --- a/openwrt/23-config-musl-r5s +++ b/openwrt/23-config-musl-r5s @@ -12,6 +12,8 @@ CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_CFLAGS="-march=armv8.2-a+crypto+crc -mcpu=cortex-a55+crypto+crc -mtune=cortex-a55" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_MPTCP=y +CONFIG_KERNEL_MPTCP_IPV6=y # CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y diff --git a/openwrt/23-config-musl-x86 b/openwrt/23-config-musl-x86 index 74b5fad14..f15626697 100644 --- a/openwrt/23-config-musl-x86 +++ b/openwrt/23-config-musl-x86 @@ -10,6 +10,8 @@ CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_MPTCP=y +CONFIG_KERNEL_MPTCP_IPV6=y # CONFIG_KERNEL_PREEMPT_RT is not set CONFIG_PACKAGE_autocore-x86=y CONFIG_PACKAGE_bind-host=y diff --git a/openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch b/openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch new file mode 100644 index 000000000..f620553af --- /dev/null +++ b/openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch @@ -0,0 +1,39 @@ +From 8db51ea9c7c8d9949d22c63fad65459ccf47e954 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 25 Oct 2024 18:15:41 +0100 +Subject: [PATCH] kernel: enable Multi-Path TCP for !SMALL_FLASH targets + +Expose Kernel's CONFIG_MPTCP option and enable it by default for +!SMALL_FLASH targets. + +Signed-off-by: Daniel Golle +--- + config/Config-kernel.in | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/config/Config-kernel.in b/config/Config-kernel.in +index 5439219..0b781b4 100644 +--- a/config/Config-kernel.in ++++ b/config/Config-kernel.in +@@ -1227,6 +1227,18 @@ config KERNEL_PAGE_POOL_STATS + bool "Page pool stats support" + depends on KERNEL_PAGE_POOL + ++config KERNEL_MPTCP ++ bool "Multi-Path TCP support" ++ default y if !SMALL_FLASH ++ help ++ Select this option to enable support for Multi-Path TCP. ++ Increases the compressed kernel size by ~214kB (as of Linux 6.6). ++ ++config KERNEL_MPTCP_IPV6 ++ bool "IPv6 support for Multipath TCP" ++ depends on KERNEL_MPTCP ++ default KERNEL_MPTCP ++ + # + # NFS related symbols + # +-- +2.42.0 + diff --git a/openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch b/openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch new file mode 100644 index 000000000..290d5c712 --- /dev/null +++ b/openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch @@ -0,0 +1,39 @@ +From f30ae23e29ba9a00280dc1498d8dfda373cc1eb9 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 25 Oct 2024 18:15:41 +0100 +Subject: [PATCH] kernel: enable Multi-Path TCP for !SMALL_FLASH targets + +Expose Kernel's CONFIG_MPTCP option and enable it by default for +!SMALL_FLASH targets. + +Signed-off-by: Daniel Golle +--- + config/Config-kernel.in | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/config/Config-kernel.in b/config/Config-kernel.in +index a262d59..c83337d 100644 +--- a/config/Config-kernel.in ++++ b/config/Config-kernel.in +@@ -1126,6 +1126,18 @@ config KERNEL_PAGE_POOL_STATS + bool "Page pool stats support" + depends on KERNEL_PAGE_POOL + ++config KERNEL_MPTCP ++ bool "Multi-Path TCP support" ++ default y if !SMALL_FLASH ++ help ++ Select this option to enable support for Multi-Path TCP. ++ Increases the compressed kernel size by ~214kB (as of Linux 6.6). ++ ++config KERNEL_MPTCP_IPV6 ++ bool "IPv6 support for Multipath TCP" ++ depends on KERNEL_MPTCP ++ default KERNEL_MPTCP ++ + # + # NFS related symbols + # +-- +2.42.0 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 4aae706f7..1315d4970 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -57,6 +57,9 @@ if [ "$version" = "snapshots-24.10" ]; then curl -s https://$mirror/openwrt/patch/$generic/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 fi +# kernel: enable Multi-Path TCP +curl -s https://$mirror/openwrt/patch/$generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch | patch -p1 + # mold if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then curl -s https://$mirror/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 From 24feceea30abd07184ccf3d46d8e72f1fbf23eaa Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 06:54:48 +0800 Subject: [PATCH 094/425] nftables: fix a corrupted tarball * Aborting. Reject files found. nftables-1.1.1.tar.xz 6358830f3a64f31e39b0ad421d7dadcd240b72343ded48d8ef13b8faf204865a tests/shell/run-tests.sh.rej Signed-off-by: sbwml --- ...ibnftnl-add-fullcone-expression-support.patch} | 4 ++-- ...0002-libnftnl-add-brcm-fullcone-support.patch} | 12 ++++++++++++ ...ftables-add-fullcone-expression-support.patch} | 4 ++-- ...2-nftables-add-brcm-fullconenat-support.patch} | 15 +++++++++++++++ openwrt/patch/firewall4/nftables/Makefile | 4 ++-- openwrt/scripts/00-prepare_base.sh | 9 ++++----- 6 files changed, 37 insertions(+), 11 deletions(-) rename openwrt/patch/firewall4/libnftnl/{001-libnftnl-add-fullcone-expression-support.patch => 0001-libnftnl-add-fullcone-expression-support.patch} (98%) rename openwrt/patch/firewall4/libnftnl/{002-libnftnl-add-brcm-fullcone-support.patch => 0002-libnftnl-add-brcm-fullcone-support.patch} (90%) rename openwrt/patch/firewall4/nftables/{002-nftables-add-fullcone-expression-support.patch => 0001-nftables-add-fullcone-expression-support.patch} (98%) rename openwrt/patch/firewall4/nftables/{003-nftables-add-brcm-fullconenat-support.patch => 0002-nftables-add-brcm-fullconenat-support.patch} (91%) diff --git a/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch b/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch similarity index 98% rename from openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch rename to openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch index 5e47e78b8..c55f55624 100644 --- a/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch +++ b/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch @@ -1,7 +1,7 @@ -From 6c39f04febd7cfdbd474233379416babcd0fc341 Mon Sep 17 00:00:00 2001 +From d1fb9ccb094e6cb9d33c3eae427003c9aefb5c99 Mon Sep 17 00:00:00 2001 From: Syrone Wong Date: Fri, 8 Apr 2022 23:52:11 +0800 -Subject: [PATCH] libnftnl: add fullcone expression support +Subject: [PATCH 1/2] libnftnl: add fullcone expression support Signed-off-by: Syrone Wong --- diff --git a/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch b/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch similarity index 90% rename from openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch rename to openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch index a4291e7f6..7606571f9 100644 --- a/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch +++ b/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch @@ -1,3 +1,15 @@ +From 945f840452091ded57ed9db799991bde6b8f6fe3 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sat, 26 Oct 2024 06:08:38 +0800 +Subject: [PATCH 2/2] libnftnl: add brcm fullcone support + +Signed-off-by: sbwml +--- + include/libnftnl/expr.h | 2 ++ + include/linux/netfilter/nf_tables.h | 4 +++ + src/expr/masq.c | 42 +++++++++++++++++++++++++++++ + 3 files changed, 48 insertions(+) + --- a/include/libnftnl/expr.h +++ b/include/libnftnl/expr.h @@ -268,6 +268,8 @@ enum { diff --git a/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch b/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch similarity index 98% rename from openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch rename to openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch index 06679839e..086bf8f79 100644 --- a/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch +++ b/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch @@ -1,7 +1,7 @@ -From 58c89e8768711a959fdc6e953df3ea2254ff93c1 Mon Sep 17 00:00:00 2001 +From 8c921fcda2d782f95864efc37989a153c16fc673 Mon Sep 17 00:00:00 2001 From: Syrone Wong Date: Sat, 9 Apr 2022 00:38:51 +0800 -Subject: [PATCH] nftables: add fullcone expression support +Subject: [PATCH 1/2] nftables: add fullcone expression support Signed-off-by: Syrone Wong --- diff --git a/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch b/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch similarity index 91% rename from openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch rename to openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch index a3e891a29..25c5f830b 100644 --- a/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch +++ b/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch @@ -1,3 +1,18 @@ +From ae87b5c969b8020a229054493467b272a3f2a79d Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sat, 26 Oct 2024 06:06:30 +0800 +Subject: [PATCH 2/2] nftables: add brcm fullconenat support + +Signed-off-by: sbwml +--- + include/linux/netfilter/nf_tables.h | 4 ++++ + src/netlink_delinearize.c | 24 ++++++++++++++++++++++++ + src/netlink_linearize.c | 15 ++++++++++----- + src/parser_bison.y | 10 ++++++++++ + src/scanner.l | 1 + + src/statement.c | 9 ++++++--- + 6 files changed, 55 insertions(+), 8 deletions(-) + --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -1474,12 +1474,16 @@ enum nft_tproxy_attributes { diff --git a/openwrt/patch/firewall4/nftables/Makefile b/openwrt/patch/firewall4/nftables/Makefile index 06b3fcfcd..f8159155c 100644 --- a/openwrt/patch/firewall4/nftables/Makefile +++ b/openwrt/patch/firewall4/nftables/Makefile @@ -10,8 +10,8 @@ PKG_VERSION:=1.1.1 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz -PKG_SOURCE_URL:=https://netfilter.org/projects/$(PKG_NAME)/files -PKG_HASH:=6358830f3a64f31e39b0ad421d7dadcd240b72343ded48d8ef13b8faf204865a +PKG_SOURCE_URL:=https://github.com/sbwml/nftables/releases/download/v$(PKG_VERSION)/ +PKG_HASH:=d702a729cf1069622187d8921ad8ed74898677fffb003059368112db5dc984c1 PKG_MAINTAINER:= PKG_LICENSE:=GPL-2.0 diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 1315d4970..f533f5946 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -221,15 +221,14 @@ if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then rm -rf package/libs/libnftnl mkdir -p package/libs/libnftnl/patches curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/Makefile > package/libs/libnftnl/Makefile - curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/001-libnftnl-add-fullcone-expression-support.patch - curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/002-libnftnl-add-brcm-fullcone-support.patch - sed -i '/PKG_INSTALL:=1/iPKG_FIXUP:=autoreconf' package/libs/libnftnl/Makefile + curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/0001-libnftnl-add-fullcone-expression-support.patch + curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/0002-libnftnl-add-brcm-fullcone-support.patch # nftables rm -rf package/network/utils/nftables mkdir -p package/network/utils/nftables/patches curl -s https://$mirror/openwrt/patch/firewall4/nftables/Makefile > package/network/utils/nftables/Makefile - curl -s https://$mirror/openwrt/patch/firewall4/nftables/002-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/002-nftables-add-fullcone-expression-support.patch - curl -s https://$mirror/openwrt/patch/firewall4/nftables/003-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/003-nftables-add-brcm-fullconenat-support.patch + curl -s https://$mirror/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/0001-nftables-add-fullcone-expression-support.patch + curl -s https://$mirror/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/0002-nftables-add-brcm-fullconenat-support.patch fi # FullCone module From 889cc66ee44de503c10ff1051046296fc15a995a Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 19:37:09 +0800 Subject: [PATCH 095/425] snapshots: firewall4: enable bcm fullcone support Signed-off-by: sbwml --- .../net/983-add-bcm-fullcone-nft_masq-support.patch | 4 ++-- openwrt/scripts/00-prepare_base.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch index b8c16c605..0cbe5a3a7 100644 --- a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -50,13 +50,13 @@ } + if (tb[NFTA_MASQ_REG_ADDR_MIN]) { -+ err = nft_parse_register_load(ctx, tb[NFTA_MASQ_REG_ADDR_MIN], ++ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MIN], + &priv->sreg_addr_min, alen); + if (err < 0) + return err; + + if (tb[NFTA_MASQ_REG_ADDR_MAX]) { -+ err = nft_parse_register_load(ctx, tb[NFTA_MASQ_REG_ADDR_MAX], ++ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MAX], + &priv->sreg_addr_max, + alen); + if (err < 0) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index f533f5946..9c6fa2d57 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -210,7 +210,7 @@ if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then # fullcone curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch # bcm fullcone - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch + curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch # kernel version curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch > package/network/config/firewall4/patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch # fix flow offload From c9ea978ad5b5a606a3864ca650f98819e36e004b Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 21:09:19 +0800 Subject: [PATCH 096/425] linux-6.12: bcmfullcone: use nft_parse_register_load_legacy function Signed-off-by: sbwml --- ...83-add-bcm-fullcone-nft_masq-support.patch | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch index 0cbe5a3a7..4f0f40b51 100644 --- a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -1,3 +1,14 @@ +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -256,6 +256,8 @@ static inline enum nft_registers nft_typ + int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest); + int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg); + ++int nft_parse_register_load_legacy(const struct nlattr *attr, u8 *sreg, u32 len); ++ + int nft_parse_register_load(const struct nft_ctx *ctx, + const struct nlattr *attr, u8 *sreg, u32 len); + int nft_parse_register_store(const struct nft_ctx *ctx, --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1481,12 +1481,16 @@ enum nft_tproxy_attributes { @@ -17,6 +28,33 @@ __NFTA_MASQ_MAX }; #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -11082,6 +11082,24 @@ static int nft_validate_register_load(en + return 0; + } + ++int nft_parse_register_load_legacy(const struct nlattr *attr, u8 *sreg, u32 len) ++{ ++ u32 reg; ++ int err; ++ ++ err = nft_parse_register(attr, ®); ++ if (err < 0) ++ return err; ++ ++ err = nft_validate_register_load(reg, len); ++ if (err < 0) ++ return err; ++ ++ *sreg = reg; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nft_parse_register_load_legacy); ++ + int nft_parse_register_load(const struct nft_ctx *ctx, + const struct nlattr *attr, u8 *sreg, u32 len) + { --- a/net/netfilter/nft_masq.c +++ b/net/netfilter/nft_masq.c @@ -17,6 +17,8 @@ struct nft_masq { @@ -50,13 +88,13 @@ } + if (tb[NFTA_MASQ_REG_ADDR_MIN]) { -+ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MIN], ++ err = nft_parse_register_load_legacy(tb[NFTA_MASQ_REG_ADDR_MIN], + &priv->sreg_addr_min, alen); + if (err < 0) + return err; + + if (tb[NFTA_MASQ_REG_ADDR_MAX]) { -+ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MAX], ++ err = nft_parse_register_load_legacy(tb[NFTA_MASQ_REG_ADDR_MAX], + &priv->sreg_addr_max, + alen); + if (err < 0) From da6f3d13064e5d387dd18ac0a6f0a5738cc9ecb7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 27 Oct 2024 03:24:39 +0800 Subject: [PATCH 097/425] kernel: add MultiPath TCP diag kernel module Signed-off-by: sbwml --- ...lti-Path-TCP-for-SMALL_FLASH-targets.patch | 39 ------------------- .../patch/openwrt-6.x/modules/netsupport.mk | 15 +++++++ openwrt/scripts/00-prepare_base.sh | 2 +- 3 files changed, 16 insertions(+), 40 deletions(-) delete mode 100644 openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch diff --git a/openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch b/openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch deleted file mode 100644 index f620553af..000000000 --- a/openwrt/patch/generic-24.10/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 8db51ea9c7c8d9949d22c63fad65459ccf47e954 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Fri, 25 Oct 2024 18:15:41 +0100 -Subject: [PATCH] kernel: enable Multi-Path TCP for !SMALL_FLASH targets - -Expose Kernel's CONFIG_MPTCP option and enable it by default for -!SMALL_FLASH targets. - -Signed-off-by: Daniel Golle ---- - config/Config-kernel.in | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index 5439219..0b781b4 100644 ---- a/config/Config-kernel.in -+++ b/config/Config-kernel.in -@@ -1227,6 +1227,18 @@ config KERNEL_PAGE_POOL_STATS - bool "Page pool stats support" - depends on KERNEL_PAGE_POOL - -+config KERNEL_MPTCP -+ bool "Multi-Path TCP support" -+ default y if !SMALL_FLASH -+ help -+ Select this option to enable support for Multi-Path TCP. -+ Increases the compressed kernel size by ~214kB (as of Linux 6.6). -+ -+config KERNEL_MPTCP_IPV6 -+ bool "IPv6 support for Multipath TCP" -+ depends on KERNEL_MPTCP -+ default KERNEL_MPTCP -+ - # - # NFS related symbols - # --- -2.42.0 - diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index cd1421f70..e536dd298 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -1496,6 +1496,21 @@ endef $(eval $(call KernelPackage,inet-diag)) +define KernelPackage/inet-mptcp-diag + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=INET diag support for MultiPath TCP + DEPENDS:=@KERNEL_MPTCP +kmod-inet-diag + KCONFIG:=CONFIG_INET_MPTCP_DIAG + FILES:=$(LINUX_DIR)/net/mptcp/mptcp_diag.ko + AUTOLOAD:=$(call AutoProbe,mptcp_diag) +endef +define KernelPackage/inet-mptcp-diag/description +Support for INET (MultiPath TCP) socket monitoring interface used by +native Linux tools such as ss. +endef +$(eval $(call KernelPackage,inet-mptcp-diag)) + + define KernelPackage/xdp-sockets-diag SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=PF_XDP sockets monitoring interface support for ss utility diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 9c6fa2d57..75640e625 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -58,7 +58,7 @@ if [ "$version" = "snapshots-24.10" ]; then fi # kernel: enable Multi-Path TCP -curl -s https://$mirror/openwrt/patch/$generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch | patch -p1 +[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/$generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch | patch -p1 # mold if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then From 4966d4b457b6bd61e43a1c246bd6db1d490407d1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 27 Oct 2024 06:23:02 +0800 Subject: [PATCH 098/425] luci: luci-app-natmap: add default STUN server lists Signed-off-by: sbwml --- ...natmap-add-default-STUN-server-lists.patch | 44 +++++++++++++++++++ openwrt/scripts/02-prepare_package.sh | 5 +++ 2 files changed, 49 insertions(+) create mode 100644 openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch diff --git a/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch b/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch new file mode 100644 index 000000000..54a8c8ab1 --- /dev/null +++ b/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch @@ -0,0 +1,44 @@ +From 9c27ce31bb6e561af47e2b6c1f47f1cbd96bdabd Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 27 Oct 2024 06:14:22 +0800 +Subject: [PATCH] luci-app-natmap: add default STUN server lists + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/natmap.js | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js b/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js +index e837fbf..14451bf 100644 +--- a/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js ++++ b/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js +@@ -80,12 +80,26 @@ return view.extend({ + o.modalonly = true; + + o = s.option(form.Value, 'stun_server', _('STUN server')); ++ o.value('stun.voipia.net'); ++ o.value('stun.m-online.net'); ++ o.value('stun.siptrunk.com'); ++ o.value('stun.hot-chilli.net'); ++ o.value('stun.fitauto.ru'); ++ o.value('stun.cooluc.com'); ++ o.default = 'stun.voipia.net'; + o.datatype = 'host'; + o.modalonly = true; + o.optional = false; + o.rmempty = false; + + o = s.option(form.Value, 'http_server', _('HTTP server'), _('For TCP mode')); ++ o.value('stun.voipia.net'); ++ o.value('stun.m-online.net'); ++ o.value('stun.siptrunk.com'); ++ o.value('stun.hot-chilli.net'); ++ o.value('stun.fitauto.ru'); ++ o.value('stun.cooluc.com'); ++ o.default = 'stun.voipia.net'; + o.datatype = 'host'; + o.modalonly = true; + o.rmempty = false; +-- +2.42.0 + diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 3c4b67972..70f1d94db 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -62,6 +62,11 @@ sed -i '/procd_open_instance/i\\t\[ "$enable" -ne 1 \] \&\& return 1\n' feeds/pa curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-${openwrt_version}.patch | patch -p1 curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-${openwrt_version}.patch | patch -p1 +# natmap +pushd feeds/luci + curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch | patch -p1 +popd + # samba4 - bump version rm -rf feeds/packages/net/samba4 git clone https://$github/sbwml/feeds_packages_net_samba4 feeds/packages/net/samba4 From 65d76201afff36dd7a06b638704e065d8d5e770e Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 28 Oct 2024 22:21:13 +0800 Subject: [PATCH 099/425] linux-6.12: bump to 6.12-rc5 Signed-off-by: sbwml --- .../btf/990-btf-silence-btf-module-warning-messages.patch | 2 +- ...-i915-Use-preempt_disable-enable_rt-where-recomme.patch | 3 ++- ...-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch | 7 ++++--- ...-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch | 3 ++- ...004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch | 5 +++-- ...-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch | 3 ++- .../012-0006-drm-i915-Drop-the-irqs_disabled-check.patch | 3 ++- ...drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch | 3 ++- .../012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch | 3 ++- ...011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch | 2 +- tags/kernel-6.12 | 4 ++-- 11 files changed, 23 insertions(+), 15 deletions(-) diff --git a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch index 4e09795cb..7eced3763 100644 --- a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch +++ b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch @@ -10,7 +10,7 @@ Signed-off-by: sbwml --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c -@@ -7878,8 +7878,6 @@ static int btf_module_notify(struct noti +@@ -7884,8 +7884,6 @@ static int btf_module_notify(struct noti pr_warn("failed to validate module [%s] BTF: %ld\n", mod->name, PTR_ERR(btf)); err = PTR_ERR(btf); diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch index a4f91e31c..7deb3505c 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch @@ -1,3 +1,4 @@ +From 7d1d8942f209cdef6e23e192de25b4cde70c7843 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 27 Feb 2016 08:09:11 +0100 Subject: [PATCH 1/8] drm/i915: Use preempt_disable/enable_rt() where @@ -28,7 +29,7 @@ Signed-off-by: Mike Galbraith Signed-off-by: Thomas Gleixner Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/display/intel_vblank.c | 43 +++++++++++++++++++++------- + drivers/gpu/drm/i915/display/intel_vblank.c | 43 ++++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) --- a/drivers/gpu/drm/i915/display/intel_vblank.c diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch index 5d14624b5..a0e8ab1b6 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch @@ -1,3 +1,4 @@ +From ae7629b5cddf2ab8b3400f1a71be97036577fcd1 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 27 Feb 2016 09:01:42 +0100 Subject: [PATCH 2/8] drm/i915: Don't disable interrupts on PREEMPT_RT during @@ -31,9 +32,9 @@ Don't disable interrupts on PREEMPT_RT during atomic updates. Signed-off-by: Mike Galbraith Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/display/intel_crtc.c | 9 ++++++--- - drivers/gpu/drm/i915/display/intel_cursor.c | 9 ++++++--- - drivers/gpu/drm/i915/display/intel_vblank.c | 6 ++++-- + drivers/gpu/drm/i915/display/intel_crtc.c | 9 ++++++--- + drivers/gpu/drm/i915/display/intel_cursor.c | 9 ++++++--- + drivers/gpu/drm/i915/display/intel_vblank.c | 6 ++++-- 3 files changed, 16 insertions(+), 8 deletions(-) --- a/drivers/gpu/drm/i915/display/intel_crtc.c diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch index 445ed66cf..484ceb34f 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch @@ -1,3 +1,4 @@ +From 34a01264ed3fab72c699f6fa8c999bb4ed907931 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 25 Oct 2021 15:05:18 +0200 Subject: [PATCH 3/8] drm/i915: Don't check for atomic context on PREEMPT_RT @@ -15,7 +16,7 @@ Reviewed-by: Tvrtko Ursulin Link: https://lore.kernel.org/all/20211006164628.s2mtsdd2jdbfyf7g@linutronix.de/ Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/i915_utils.h | 9 +++++++-- + drivers/gpu/drm/i915/i915_utils.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) --- a/drivers/gpu/drm/i915/i915_utils.h diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch index 1e38b5820..af99667c4 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch @@ -1,3 +1,4 @@ +From 7e6152f775a4a6f3e2b36898056252a639b60ec7 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 6 Dec 2018 09:52:20 +0100 Subject: [PATCH 4/8] drm/i915: Disable tracing points on PREEMPT_RT @@ -27,8 +28,8 @@ Reported-by: Luca Abeni Cc: Steven Rostedt Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/display/intel_display_trace.h | 4 ++++ - drivers/gpu/drm/i915/i915_trace.h | 4 ++++ + drivers/gpu/drm/i915/display/intel_display_trace.h | 4 ++++ + drivers/gpu/drm/i915/i915_trace.h | 4 ++++ 2 files changed, 8 insertions(+) --- a/drivers/gpu/drm/i915/display/intel_display_trace.h diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch index 8cd2a3295..e9de6cb32 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch @@ -1,3 +1,4 @@ +From 7b539177855a717a3ca6d18c67ca2370aff203cc Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 8 Sep 2021 19:03:41 +0200 Subject: [PATCH 5/8] drm/i915/gt: Use spin_lock_irq() instead of @@ -22,7 +23,7 @@ Reported-by: Clark Williams Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Maarten Lankhorst --- - drivers/gpu/drm/i915/gt/intel_execlists_submission.c | 17 +++++------------ + .../drm/i915/gt/intel_execlists_submission.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch index 0c2018e67..69f96cf2b 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch @@ -1,3 +1,4 @@ +From 9c2e94663607f6db53df8f5a347a71e10ffa4dc3 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Oct 2021 20:01:03 +0200 Subject: [PATCH 6/8] drm/i915: Drop the irqs_disabled() check @@ -16,7 +17,7 @@ Reported-by: Maarten Lankhorst Acked-by: Tvrtko Ursulin Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/i915_request.c | 2 -- + drivers/gpu/drm/i915/i915_request.c | 2 -- 1 file changed, 2 deletions(-) --- a/drivers/gpu/drm/i915/i915_request.c diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch index 8c3217614..bed8a14b9 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch @@ -1,3 +1,4 @@ +From 192d322a13f7fa4419cbedbd315ed42c7462e4e9 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 3 Oct 2023 21:37:21 +0200 Subject: [PATCH 7/8] drm/i915/guc: Consider also RCU depth in busy loop. @@ -13,7 +14,7 @@ Reported-by: "John B. Wyatt IV" Reviewed-by: Rodrigo Vivi Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/gt/uc/intel_guc.h | 2 +- + drivers/gpu/drm/i915/gt/uc/intel_guc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch index 0ab01fe1e..271cbd4c0 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch @@ -1,3 +1,4 @@ +From d387c5c9e6666a0d14dafdb51675d583ab55e7d8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 21 Feb 2022 17:59:14 +0100 Subject: [PATCH 8/8] Revert "drm/i915: Depend on !PREEMPT_RT." @@ -8,7 +9,7 @@ driver. Acked-by: Tvrtko Ursulin Signed-off-by: Sebastian Andrzej Siewior --- - drivers/gpu/drm/i915/Kconfig | 1 - + drivers/gpu/drm/i915/Kconfig | 1 - 1 file changed, 1 deletion(-) --- a/drivers/gpu/drm/i915/Kconfig diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch index 3bef4a7fe..9db498fa6 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -24,7 +24,7 @@ Signed-off-by: Stephan Mueller #include #include #include -@@ -3606,6 +3607,8 @@ ttwu_stat(struct task_struct *p, int cpu +@@ -3611,6 +3612,8 @@ ttwu_stat(struct task_struct *p, int cpu { struct rq *rq; diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 00fd26391..ad85ee363 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -rc4 -LINUX_KERNEL_HASH-6.12-rc4 = 41356c3cac4b55170506629cab54f3a0ab5a57c0fd1f0e976dbbe66a0a74cc87 +LINUX_VERSION-6.12 = -rc5 +LINUX_KERNEL_HASH-6.12-rc5 = 02f4d008929d8d62af2a1cd585b4dc58c0c7a427855515b7832ecb34f6f385b1 From 3cc227afe34618ddc472659fa191edcd23d2d92d Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 28 Oct 2024 23:45:51 +0800 Subject: [PATCH 100/425] luci: update patch Signed-off-by: sbwml --- ...2-luci-mod-status-displays-actual-process-memory-usage.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch index 776455541..2698cb0fa 100644 --- a/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch +++ b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch @@ -18,7 +18,7 @@ index 0a885c0..d3302ff 100644 var fields = [ - _('Total Available'), (mem.available) ? mem.available : (mem.total && mem.free && mem.buffered) ? mem.free + mem.buffered : null, mem.total, - _('Used'), (mem.total && mem.free) ? (mem.total - mem.free) : null, mem.total, -+ _('Processes'), (mem.total && mem.free && mem.cached) ? (mem.total - mem.free - mem.cached) : null, mem.total, ++ _('Used'), (mem.total && mem.free && mem.cached) ? (mem.total - mem.free - mem.cached) : null, mem.total, + _('Total Available'), (mem.total && mem.free && mem.cached) ? (mem.free + mem.cached) : null, mem.total, ]; From ac51e15b3ce1eda0e2561c8a9ff9b70d2778874e Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 29 Oct 2024 21:57:41 +0800 Subject: [PATCH 101/425] luci-nginx: drop temp fix Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index d8b5d6705..19e89f6c4 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -2,8 +2,6 @@ ######################### temp fix ########################### if [ "$version" = "snapshots-24.10" ]; then - # luci-nginx - sed -i 's/luci-app-opkg/luci-app-package-manager/g' feeds/luci/collections/luci-nginx/Makefile # apk-tools curl -s https://init2.cooluc.com/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch fi From 3a508fb058ff23ec530a8aa1128528fbb6d8a640 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 1 Nov 2024 08:54:52 +0800 Subject: [PATCH 102/425] dev: openwrt-24.10 Signed-off-by: sbwml --- openwrt/23-config-common | 1 + openwrt/build.sh | 3 +-- openwrt/scripts/05-fix-source.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 93072b086..2e8e4ba6a 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -257,6 +257,7 @@ CONFIG_PACKAGE_qrencode=y CONFIG_PACKAGE_rename=y CONFIG_PACKAGE_resize2fs=y CONFIG_PACKAGE_rsync=y +CONFIG_PACKAGE_samba4-admin=y CONFIG_PACKAGE_screen=y CONFIG_PACKAGE_sed=y CONFIG_PACKAGE_sshpass=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 590ea4520..976575ea3 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -86,7 +86,7 @@ fi # Source branch if [ "$1" = "dev" ]; then - export branch=master + export branch=openwrt-24.10 export version=snapshots-24.10 export openwrt_version=openwrt-24.10 elif [ "$1" = "rc2" ]; then @@ -200,7 +200,6 @@ git clone https://$github/immortalwrt/packages master/immortalwrt_packages --dep if [ -d openwrt ]; then cd openwrt [ "$1" = "rc2" ] && echo "$CURRENT_DATE" > version.date - [ "$1" = "dev" ] && sed -i 's/$(VERSION_NUMBER),SNAPSHOT/$(VERSION_NUMBER),24.10-SNAPSHOT/g' include/version.mk curl -Os https://$mirror/openwrt/patch/key.tar.gz && tar zxf key.tar.gz && rm -f key.tar.gz else echo -e "${RED_COLOR}Failed to download source code${RES}" diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 19e89f6c4..17866cd12 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -3,7 +3,7 @@ ######################### temp fix ########################### if [ "$version" = "snapshots-24.10" ]; then # apk-tools - curl -s https://init2.cooluc.com/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch + curl -s https://$mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch fi ######################### temp fix ########################### From 55f6c82f637bd25bb5cd4106cd84faaef4516d0e Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 1 Nov 2024 09:24:03 +0800 Subject: [PATCH 103/425] ci: snapshot-24.10 Signed-off-by: sbwml --- .github/workflows/build-release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 7bea7471c..5326e7394 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -77,9 +77,9 @@ jobs: bash <(curl -sS https://raw.githubusercontent.com/${{ github.repository }}/master/openwrt/build.sh) ${{ env.build_version }} ${{ github.event.inputs.device }} cd openwrt if [ "${{ github.event.inputs.version }}" = release ]; then - tags=$(git describe --abbrev=0 --tags) + tags=OpenWrt-$(git describe --abbrev=0 --tags) else - tags=snapshot-$(git log -n 1 --date=format:"%Y%m%d" --format="%cd")-$(git log --pretty=format:"%h" -1) + tags=snapshot-24.10-$(git log -n 1 --date=format:"%Y%m%d" --format="%cd")-$(git log --pretty=format:"%h" -1) fi echo "latest_release=$tags" >>$GITHUB_ENV @@ -133,7 +133,7 @@ jobs: continue-on-error: true uses: ncipollo/release-action@v1 with: - name: OpenWrt-${{ env.latest_release }} + name: ${{ env.latest_release }} allowUpdates: true tag: ${{ env.latest_release }} commit: master From fc4f6fa63d329afb403daee3bfc082d861080ead Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 1 Nov 2024 10:16:29 +0800 Subject: [PATCH 104/425] openwrt-24.10: odhcpd RFC-9096 Signed-off-by: sbwml --- ...d-RFC-9096-compliance-openwrt-23.05.patch} | 0 ...pd-RFC-9096-compliance-openwrt-24.10.patch | 320 ++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 12 +- 3 files changed, 325 insertions(+), 7 deletions(-) rename openwrt/patch/odhcpd/{001-odhcpd-RFC-9096-compliance.patch => 001-odhcpd-RFC-9096-compliance-openwrt-23.05.patch} (100%) create mode 100644 openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch diff --git a/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance.patch b/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-23.05.patch similarity index 100% rename from openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance.patch rename to openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-23.05.patch diff --git a/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch b/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch new file mode 100644 index 000000000..d6281669f --- /dev/null +++ b/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch @@ -0,0 +1,320 @@ +From 726ca5340823e2d5f3b5e7b6ad83e52ba3be14a9 Mon Sep 17 00:00:00 2001 +From: Aviana Cruz +Date: Sat, 16 Sep 2023 15:04:12 +0000 +Subject: [PATCH] odhcpd: improve RFC 9096 compliance + +and allow configuring upper limit for preferred and valid lifetime. + +Signed-off-by: Aviana Cruz +--- + README | 12 ++++++------ + src/config.c | 35 +++++++++++++++++++++------------- + src/dhcpv6-ia.c | 50 ++++++++++++++++++++++++++++++------------------- + src/odhcpd.h | 8 ++++++-- + src/router.c | 17 ++++++++--------- + 5 files changed, 73 insertions(+), 49 deletions(-) + +--- a/README ++++ b/README +@@ -116,7 +116,9 @@ domain list Sear + leasetime string 12h DHCPv4 address leasetime + start integer 100 DHCPv4 pool start + limit integer 150 DHCPv4 pool size +-preferred_lifetime string 7d Value for the preferred lifetime ++max_preferred_lifetime string 45m Upper limit for the preferred lifetime ++ for a prefix ++max_valid_lifetime string 90m Upper limit for the valid lifetime + for a prefix + ra_default integer 0 Override default route + 0: default, 1: ignore no public address, 2: ignore all +@@ -131,11 +133,9 @@ ra_maxinterval integer 600 Maximum ti + sending unsolicited RA + ra_mininterval integer 200 Minimum time allowed between + sending unsolicited RA +-ra_lifetime integer 1800 Value to be placed in Router +- Lifetime field of RA +-ra_useleasetime bool 0 Use configured leasetime as +- limit for the preferred and +- valid lifetime of a prefix ++ra_lifetime integer 2700 Value to be placed in Router ++ Lifetime field of RA. Not recommended to be ++ more than 2700 (RFC9096). + ra_reachabletime integer 0 Reachable Time in milliseconds to be + advertised in RA messages + ra_retranstime integer 0 Retransmit Time in milliseconds to be +--- a/src/config.c ++++ b/src/config.c +@@ -79,7 +79,6 @@ enum { + IFACE_ATTR_RA_MININTERVAL, + IFACE_ATTR_RA_MAXINTERVAL, + IFACE_ATTR_RA_LIFETIME, +- IFACE_ATTR_RA_USELEASETIME, + IFACE_ATTR_RA_REACHABLETIME, + IFACE_ATTR_RA_RETRANSTIME, + IFACE_ATTR_RA_HOPLIMIT, +@@ -91,7 +90,8 @@ enum { + IFACE_ATTR_NDPROXY_ROUTING, + IFACE_ATTR_NDPROXY_SLAVE, + IFACE_ATTR_PREFIX_FILTER, +- IFACE_ATTR_PREFERRED_LIFETIME, ++ IFACE_ATTR_MAX_PREFERRED_LIFETIME, ++ IFACE_ATTR_MAX_VALID_LIFETIME, + IFACE_ATTR_NTP, + IFACE_ATTR_MAX + }; +@@ -134,7 +134,6 @@ static const struct blobmsg_policy iface + [IFACE_ATTR_RA_MININTERVAL] = { .name = "ra_mininterval", .type = BLOBMSG_TYPE_INT32 }, + [IFACE_ATTR_RA_MAXINTERVAL] = { .name = "ra_maxinterval", .type = BLOBMSG_TYPE_INT32 }, + [IFACE_ATTR_RA_LIFETIME] = { .name = "ra_lifetime", .type = BLOBMSG_TYPE_INT32 }, +- [IFACE_ATTR_RA_USELEASETIME] = { .name = "ra_useleasetime", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_RA_REACHABLETIME] = { .name = "ra_reachabletime", .type = BLOBMSG_TYPE_INT32 }, + [IFACE_ATTR_RA_RETRANSTIME] = { .name = "ra_retranstime", .type = BLOBMSG_TYPE_INT32 }, + [IFACE_ATTR_RA_HOPLIMIT] = { .name = "ra_hoplimit", .type = BLOBMSG_TYPE_INT32 }, +@@ -144,7 +143,8 @@ static const struct blobmsg_policy iface + [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING }, +- [IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING }, ++ [IFACE_ATTR_MAX_PREFERRED_LIFETIME] = { .name = "max_preferred_lifetime", .type = BLOBMSG_TYPE_STRING }, ++ [IFACE_ATTR_MAX_VALID_LIFETIME] = { .name = "max_valid_lifetime", .type = BLOBMSG_TYPE_STRING }, + [IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY }, + }; + +@@ -215,7 +215,8 @@ static void set_interface_defaults(struc + iface->ndp = MODE_DISABLED; + iface->learn_routes = 1; + iface->dhcp_leasetime = 43200; +- iface->preferred_lifetime = 604800; /* rfc4861#section-6.2.1: AdvPreferredLifetime 7 days */ ++ iface->max_preferred_lifetime = ND_PREFERRED_LIMIT; ++ iface->max_valid_lifetime = ND_VALID_LIMIT; + iface->dhcpv4_start.s_addr = htonl(START_DEFAULT); + iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1); + iface->dhcpv6_assignall = true; +@@ -647,15 +648,26 @@ int config_parse_interface(void *data, s + + } + +- if ((c = tb[IFACE_ATTR_PREFERRED_LIFETIME])) { ++ if ((c = tb[IFACE_ATTR_MAX_PREFERRED_LIFETIME])) { + double time = parse_leasetime(c); + +- if (time >= 0) +- iface->preferred_lifetime = time; +- else ++ if (time >= 0) { ++ iface->max_preferred_lifetime = time; ++ } else { + syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", +- iface_attrs[IFACE_ATTR_PREFERRED_LIFETIME].name, iface->name); ++ iface_attrs[IFACE_ATTR_MAX_PREFERRED_LIFETIME].name, iface->name); ++ } ++ } ++ ++ if ((c = tb[IFACE_ATTR_MAX_VALID_LIFETIME])) { ++ double time = parse_leasetime(c); + ++ if (time >= 0) { ++ iface->max_valid_lifetime = time; ++ } else { ++ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", ++ iface_attrs[IFACE_ATTR_MAX_VALID_LIFETIME].name, iface->name); ++ } + } + + if ((c = tb[IFACE_ATTR_START])) { +@@ -979,9 +991,6 @@ int config_parse_interface(void *data, s + if ((c = tb[IFACE_ATTR_RA_LIFETIME])) + iface->ra_lifetime = blobmsg_get_u32(c); + +- if ((c = tb[IFACE_ATTR_RA_USELEASETIME])) +- iface->ra_useleasetime = blobmsg_get_bool(c); +- + if ((c = tb[IFACE_ATTR_RA_DNS])) + iface->ra_dns = blobmsg_get_bool(c); + +--- a/src/dhcpv6-ia.c ++++ b/src/dhcpv6-ia.c +@@ -120,7 +120,7 @@ static inline bool valid_prefix_length(c + + static inline bool valid_addr(const struct odhcpd_ipaddr *addr, time_t now) + { +- return (addr->prefix <= 96 && addr->preferred_lt > (uint32_t)now); ++ return (addr->prefix <= 96 && addr->valid_lt > (uint32_t)now && addr->preferred_lt > (uint32_t)now); + } + + static size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen) +@@ -1037,17 +1037,27 @@ static size_t build_ia(uint8_t *buf, siz + } + + if (a) { +- uint32_t leasetime, preferred_lt; ++ uint32_t leasetime; + + if (a->leasetime) { + leasetime = a->leasetime; +- preferred_lt = a->leasetime; + } else { + leasetime = iface->dhcp_leasetime; +- preferred_lt = iface->preferred_lifetime; + } + +- uint32_t valid_lt = leasetime; ++ uint32_t floor_preferred_lifetime, floor_valid_lifetime; /* For calculating T1 / T2 */ ++ ++ if (iface->max_preferred_lifetime && iface->max_preferred_lifetime < leasetime) { ++ floor_preferred_lifetime = iface->max_preferred_lifetime; ++ } else { ++ floor_preferred_lifetime = leasetime; ++ } ++ ++ if (iface->max_valid_lifetime && iface->max_valid_lifetime < leasetime) { ++ floor_valid_lifetime = iface->max_valid_lifetime; ++ } else { ++ floor_valid_lifetime = leasetime; ++ } + + struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6; + size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len; +@@ -1071,15 +1081,20 @@ static size_t build_ia(uint8_t *buf, siz + prefix_preferred_lt = addrs[i].preferred_lt; + prefix_valid_lt = addrs[i].valid_lt; + +- if (prefix_preferred_lt != UINT32_MAX) ++ if (prefix_preferred_lt != UINT32_MAX) { + prefix_preferred_lt -= now; + +- if (prefix_preferred_lt > preferred_lt) +- prefix_preferred_lt = preferred_lt; ++ if (iface->max_preferred_lifetime && prefix_preferred_lt > iface->max_preferred_lifetime) ++ prefix_preferred_lt = iface->max_preferred_lifetime; ++ } + +- if (prefix_valid_lt != UINT32_MAX) ++ if (prefix_valid_lt != UINT32_MAX) { + prefix_valid_lt -= now; + ++ if (iface->max_valid_lifetime && prefix_valid_lt > iface->max_valid_lifetime) ++ prefix_valid_lt = iface->max_valid_lifetime; ++ } ++ + if (prefix_valid_lt > leasetime) + prefix_valid_lt = leasetime; + +@@ -1133,24 +1148,24 @@ static size_t build_ia(uint8_t *buf, siz + + /* Calculate T1 / T2 based on non-deprecated addresses */ + if (prefix_preferred_lt > 0) { +- if (prefix_preferred_lt < preferred_lt) +- preferred_lt = prefix_preferred_lt; ++ if (floor_preferred_lifetime > prefix_preferred_lt) ++ floor_preferred_lifetime = prefix_preferred_lt; + +- if (prefix_valid_lt < valid_lt) +- valid_lt = prefix_valid_lt; ++ if (floor_valid_lifetime > prefix_valid_lt) ++ floor_valid_lifetime = prefix_valid_lt; + } + } + + if (!INFINITE_VALID(a->valid_until)) + /* UINT32_MAX is RFC defined as infinite lease-time */ +- a->valid_until = (valid_lt == UINT32_MAX) ? 0 : valid_lt + now; ++ a->valid_until = (floor_valid_lifetime == UINT32_MAX) ? 0 : floor_valid_lifetime + now; + + if (!INFINITE_VALID(a->preferred_until)) + /* UINT32_MAX is RFC defined as infinite lease-time */ +- a->preferred_until = (preferred_lt == UINT32_MAX) ? 0 : preferred_lt + now; ++ a->preferred_until = (floor_preferred_lifetime == UINT32_MAX) ? 0 : floor_preferred_lifetime + now; + +- o_ia.t1 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 5 / 10); +- o_ia.t2 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 8 / 10); ++ o_ia.t1 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 5 / 10); ++ o_ia.t2 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 8 / 10); + + if (!o_ia.t1) + o_ia.t1 = htonl(1); +--- a/src/odhcpd.h ++++ b/src/odhcpd.h +@@ -37,6 +37,10 @@ + // RFC 8781 defines PREF64 option + #define ND_OPT_PREF64 38 + ++// RFC9096 defines recommended option lifetimes configuration values ++#define ND_PREFERRED_LIMIT 2700 ++#define ND_VALID_LIMIT 5400 ++ + #define INFINITE_VALID(x) ((x) == 0) + + #define _unused __attribute__((unused)) +@@ -302,7 +306,6 @@ struct interface { + bool ra_slaac; + bool ra_not_onlink; + bool ra_advrouter; +- bool ra_useleasetime; + bool ra_dns; + uint8_t pref64_length; + struct in6_addr pref64_addr; +@@ -319,7 +322,8 @@ struct interface { + uint32_t ra_retranstime; + uint32_t ra_hoplimit; + int ra_mtu; +- uint32_t preferred_lifetime; ++ uint32_t max_preferred_lifetime; ++ uint32_t max_valid_lifetime; + + // DHCP + uint32_t dhcp_leasetime; +--- a/src/router.c ++++ b/src/router.c +@@ -376,7 +376,7 @@ static int calc_adv_interval(struct inte + + static uint32_t calc_ra_lifetime(struct interface *iface, uint32_t maxival) + { +- uint32_t lifetime = 3*maxival; ++ uint32_t lifetime = maxival * 3; + + if (iface->ra_lifetime >= 0) { + lifetime = iface->ra_lifetime; +@@ -600,17 +600,16 @@ static int send_router_advert(struct int + if (addr->preferred_lt > (uint32_t)now) { + preferred_lt = TIME_LEFT(addr->preferred_lt, now); + +- if (preferred_lt > iface->preferred_lifetime) { +- /* set to possibly user mandated preferred_lt */ +- preferred_lt = iface->preferred_lifetime; ++ if (iface->max_preferred_lifetime && preferred_lt > iface->max_preferred_lifetime) { ++ preferred_lt = iface->max_preferred_lifetime; + } + } + + if (addr->valid_lt > (uint32_t)now) { + valid_lt = TIME_LEFT(addr->valid_lt, now); + +- if (iface->ra_useleasetime && valid_lt > iface->dhcp_leasetime) +- valid_lt = iface->dhcp_leasetime; ++ if (iface->max_valid_lifetime && valid_lt > iface->max_valid_lifetime) ++ valid_lt = iface->max_valid_lifetime; + } + + if (preferred_lt > valid_lt) { +@@ -663,9 +662,9 @@ static int send_router_advert(struct int + + if (default_route) { + syslog(LOG_WARNING, "A default route is present but there is no public prefix " +- "on %s thus we announce no default route by overriding ra_lifetime to 0!", iface->name); ++ "on %s thus we announce no default route by setting ra_lifetime to 0!", iface->name); + } else { +- syslog(LOG_WARNING, "No default route present, overriding ra_lifetime to 0!"); ++ syslog(LOG_WARNING, "No default route present, setting ra_lifetime to 0!"); + } + } + +@@ -730,7 +729,7 @@ static int send_router_advert(struct int + + if (iface->pref64_length) { + /* RFC 8781 § 4.1 rounding up lifetime to multiple of 8 */ +- uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : UINT16_MAX; ++ uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : (UINT16_MAX - 7); + uint8_t prefix_length_code; + uint32_t mask_a1, mask_a2; + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 75640e625..3d1f1ba65 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -452,13 +452,11 @@ if [ "$version" = "rc2" ]; then fi # odhcpd RFC-9096 -if [ "$version" = "rc2" ]; then - mkdir -p package/network/services/odhcpd/patches - curl -s https://$mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch - pushd feeds/luci - curl -s https://$mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 - popd -fi +mkdir -p package/network/services/odhcpd/patches +curl -s https://$mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-$openwrt_version.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch +pushd feeds/luci + curl -s https://$mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 +popd # urngd - 2020-01-21 rm -rf package/system/urngd From 3a2d9818217d9e152d57bccc038e74e7734a4a10 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 Nov 2024 09:30:35 +0800 Subject: [PATCH 105/425] archive 2024-11-01 Signed-off-by: sbwml --- openwrt/patch/luci/dhcp/README.md | 1 - openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js | 1138 ----------------- openwrt/scripts/00-prepare_base.sh | 2 +- 3 files changed, 1 insertion(+), 1140 deletions(-) delete mode 100644 openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js diff --git a/openwrt/patch/luci/dhcp/README.md b/openwrt/patch/luci/dhcp/README.md index 90d8a5152..0a838365e 100644 --- a/openwrt/patch/luci/dhcp/README.md +++ b/openwrt/patch/luci/dhcp/README.md @@ -1,4 +1,3 @@ ### LuCI DHCP COMMIT: openwrt-23.05: https://github.com/openwrt/luci/commit/1f36628bc60f6e1f33667b025917eebec19d3162 -openwrt-24.10: https://github.com/openwrt/luci/commit/8c8073729fc0220444dce7bacca97f9c6f8a8305 diff --git a/openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js b/openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js deleted file mode 100644 index 484c766f0..000000000 --- a/openwrt/patch/luci/dhcp/openwrt-24.10-dhcp.js +++ /dev/null @@ -1,1138 +0,0 @@ -'use strict'; -'require view'; -'require dom'; -'require poll'; -'require rpc'; -'require uci'; -'require form'; -'require network'; -'require validation'; -'require tools.widgets as widgets'; - -var callHostHints, callDUIDHints, callDHCPLeases, CBILeaseStatus, CBILease6Status; - -callHostHints = rpc.declare({ - object: 'luci-rpc', - method: 'getHostHints', - expect: { '': {} } -}); - -callDUIDHints = rpc.declare({ - object: 'luci-rpc', - method: 'getDUIDHints', - expect: { '': {} } -}); - -callDHCPLeases = rpc.declare({ - object: 'luci-rpc', - method: 'getDHCPLeases', - expect: { '': {} } -}); - -CBILeaseStatus = form.DummyValue.extend({ - renderWidget: function(section_id, option_id, cfgvalue) { - return E([ - E('h4', _('Active DHCP Leases')), - E('table', { 'id': 'lease_status_table', 'class': 'table' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th' }, _('Hostname')), - E('th', { 'class': 'th' }, _('IPv4 address')), - E('th', { 'class': 'th' }, _('MAC address')), - E('th', { 'class': 'th' }, _('Lease time remaining')) - ]), - E('tr', { 'class': 'tr placeholder' }, [ - E('td', { 'class': 'td' }, E('em', _('Collecting data...'))) - ]) - ]) - ]); - } -}); - -CBILease6Status = form.DummyValue.extend({ - renderWidget: function(section_id, option_id, cfgvalue) { - return E([ - E('h4', _('Active DHCPv6 Leases')), - E('table', { 'id': 'lease6_status_table', 'class': 'table' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th' }, _('Host')), - E('th', { 'class': 'th' }, _('IPv6 address')), - E('th', { 'class': 'th' }, _('DUID')), - E('th', { 'class': 'th' }, _('Lease time remaining')) - ]), - E('tr', { 'class': 'tr placeholder' }, [ - E('td', { 'class': 'td' }, E('em', _('Collecting data...'))) - ]) - ]) - ]); - } -}); - -function calculateNetwork(addr, mask) { - addr = validation.parseIPv4(String(addr)); - - if (!isNaN(mask)) - mask = validation.parseIPv4(network.prefixToMask(+mask)); - else - mask = validation.parseIPv4(String(mask)); - - if (addr == null || mask == null) - return null; - - return [ - [ - addr[0] & (mask[0] >>> 0 & 255), - addr[1] & (mask[1] >>> 0 & 255), - addr[2] & (mask[2] >>> 0 & 255), - addr[3] & (mask[3] >>> 0 & 255) - ].join('.'), - mask.join('.') - ]; -} - -function generateDnsmasqInstanceEntry(data) { - const nameValueMap = new Map(Object.entries(data)); - let formatString = nameValueMap.get('.index') + ' (' + _('Name') + (nameValueMap.get('.anonymous') ? ': dnsmasq[' + nameValueMap.get('.index') + ']': ': ' + nameValueMap.get('.name')); - - if (data.domain) { - formatString += ', ' + _('Domain') + ': ' + data.domain; - } - if (data.local) { - formatString += ', ' + _('Local') + ': ' + data.local; - } - formatString += ')'; - - return [nameValueMap.get('.name'), formatString]; -} - -function getDHCPPools() { - return uci.load('dhcp').then(function() { - let sections = uci.sections('dhcp', 'dhcp'), - tasks = [], pools = []; - - for (var i = 0; i < sections.length; i++) { - if (sections[i].ignore == '1' || !sections[i].interface) - continue; - - tasks.push(network.getNetwork(sections[i].interface).then(L.bind(function(section_id, net) { - var cidr = net ? (net.getIPAddrs()[0] || '').split('/') : null; - - if (cidr && cidr.length == 2) { - var net_mask = calculateNetwork(cidr[0], cidr[1]); - - pools.push({ - section_id: section_id, - network: net_mask[0], - netmask: net_mask[1] - }); - } - }, null, sections[i]['.name']))); - } - - return Promise.all(tasks).then(function() { - return pools; - }); - }); -} - -function validateHostname(sid, s) { - if (s == null || s == '') - return true; - - if (s.length > 256) - return _('Expecting: %s').format(_('valid hostname')); - - var labels = s.replace(/^\*?\.?|\.$/g, '').split(/\./); - - for (var i = 0; i < labels.length; i++) - if (!labels[i].match(/^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i)) - return _('Expecting: %s').format(_('valid hostname')); - - return true; -} - -function validateAddressList(sid, s) { - if (s == null || s == '') - return true; - - var m = s.match(/^\/(.+)\/$/), - names = m ? m[1].split(/\//) : [ s ]; - - for (var i = 0; i < names.length; i++) { - var res = validateHostname(sid, names[i]); - - if (res !== true) - return res; - } - - return true; -} - -function validateServerSpec(sid, s) { - if (s == null || s == '') - return true; - - var m = s.match(/^(\/.*\/)?(.*)$/); - if (!m) - return _('Expecting: %s').format(_('valid hostname')); - - if (m[1] != '//' && m[1] != '/#/') { - var res = validateAddressList(sid, m[1]); - if (res !== true) - return res; - } - - if (m[2] == '' || m[2] == '#') - return true; - - // ipaddr%scopeid#srvport@source@interface#srcport - - m = m[2].match(/^([0-9a-f:.]+)(?:%[^#@]+)?(?:#(\d+))?(?:@([0-9a-f:.]+)(?:@[^#]+)?(?:#(\d+))?)?$/); - - if (!m) - return _('Expecting: %s').format(_('valid IP address')); - - if (validation.parseIPv4(m[1])) { - if (m[3] != null && !validation.parseIPv4(m[3])) - return _('Expecting: %s').format(_('valid IPv4 address')); - } - else if (validation.parseIPv6(m[1])) { - if (m[3] != null && !validation.parseIPv6(m[3])) - return _('Expecting: %s').format(_('valid IPv6 address')); - } - else { - return _('Expecting: %s').format(_('valid IP address')); - } - - if ((m[2] != null && +m[2] > 65535) || (m[4] != null && +m[4] > 65535)) - return _('Expecting: %s').format(_('valid port value')); - - return true; -} - -function expandAndFormatMAC(macs) { - let result = []; - - macs.forEach(mac => { - if (isValidMAC(mac)) { - const expandedMac = mac.split(':').map(part => { - return (part.length === 1 && part !== '*') ? '0' + part : part; - }).join(':').toUpperCase(); - result.push(expandedMac); - } - }); - - return result.length ? result : null; -} - -function isValidMAC(sid, s) { - if (!s) - return true; - - let macaddrs = L.toArray(s); - - for (var i = 0; i < macaddrs.length; i++) - if (!macaddrs[i].match(/^(([0-9a-f]{1,2}|\*)[:-]){5}([0-9a-f]{1,2}|\*)$/i)) - return _('Expecting a valid MAC address, optionally including wildcards') + _('; invalid MAC: ') + macaddrs[i]; - - return true; -} - -function validateMACAddr(pools, sid, s) { - if (s == null || s == '') - return true; - - var leases = uci.sections('dhcp', 'host'), - this_macs = L.toArray(s).map(function(m) { return m.toUpperCase() }); - - for (var i = 0; i < pools.length; i++) { - var this_net_mask = calculateNetwork(this.section.formvalue(sid, 'ip'), pools[i].netmask); - - if (!this_net_mask) - continue; - - for (var j = 0; j < leases.length; j++) { - if (leases[j]['.name'] == sid || !leases[j].ip) - continue; - - var lease_net_mask = calculateNetwork(leases[j].ip, pools[i].netmask); - - if (!lease_net_mask || this_net_mask[0] != lease_net_mask[0]) - continue; - - var lease_macs = L.toArray(leases[j].mac).map(function(m) { return m.toUpperCase() }); - - for (var k = 0; k < lease_macs.length; k++) - for (var l = 0; l < this_macs.length; l++) - if (lease_macs[k] == this_macs[l]) - return _('The MAC address %h is already used by another static lease in the same DHCP pool').format(this_macs[l]); - } - } - - return isValidMAC(sid, s); -} - -return view.extend({ - load: function() { - return Promise.all([ - callHostHints(), - callDUIDHints(), - getDHCPPools(), - network.getNetworks() - ]); - }, - - render: function(hosts_duids_pools) { - var has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'), - hosts = hosts_duids_pools[0], - duids = hosts_duids_pools[1], - pools = hosts_duids_pools[2], - networks = hosts_duids_pools[3], - m, s, o, ss, so; - - let noi18nstrings = { - etc_hosts: '/etc/hosts', - etc_ethers: '/etc/ethers', - localhost_v6: '::1', - loopback_slash_8_v4: '127.0.0.0/8', - not_found: 'Not found', - nxdomain: 'NXDOMAIN', - rfc_1918_link: 'RFC1918', - rfc_4193_link: 'RFC4193', - rfc_4291_link: 'RFC4291', - rfc_6303_link: 'RFC6303', - reverse_arpa: '*.IN-ADDR.ARPA,*.IP6.ARPA', - servers_file_entry01: 'server=1.2.3.4', - servers_file_entry02: 'server=/domain/1.2.3.4', - - }; - - function customi18n(template, values) { - if (!values) - values = noi18nstrings; - return template.replace(/\{(\w+)\}/g, (match, key) => values[key] || match); - }; - - m = new form.Map('dhcp', _('DHCP and DNS'), - _('Dnsmasq is a lightweight DHCP server and DNS forwarder.')); - - s = m.section(form.TypedSection, 'dnsmasq'); - s.anonymous = true; - s.addremove = false; - - s.tab('general', _('General Settings')); - s.tab('advanced', _('Advanced Settings')); - s.tab('leases', _('Static Leases')); - s.tab('files', _('Resolv and Hosts Files')); - s.tab('hosts', _('Hostnames')); - s.tab('ipsets', _('IP Sets')); - s.tab('relay', _('Relay')); - s.tab('srvhosts', _('SRV')); - s.tab('mxhosts', _('MX')); - s.tab('cnamehosts', _('CNAME')); - s.tab('pxe_tftp', _('PXE/TFTP Settings')); - - s.taboption('general', form.Flag, 'domainneeded', - _('Domain required'), - _('Never forward DNS queries which lack dots or domain parts.') + '
' + - customi18n(_('Names not in {etc_hosts} are answered {not_found}.') ) - ); - s.taboption('general', form.Flag, 'authoritative', - _('Authoritative'), - _('This is the only DHCP server in the local network.')); - - o = s.taboption('general', form.Value, 'local', - _('Resolve these locally'), - _('Never forward these matching domains or subdomains; resolve from DHCP or hosts files only.')); - o.placeholder = '/internal.example.com/private.example.com/example.org'; - - s.taboption('general', form.Value, 'domain', - _('Local domain'), - _('Local domain suffix appended to DHCP names and hosts file entries.')); - - o = s.taboption('general', form.Flag, 'logqueries', - _('Log queries'), - _('Write received DNS queries to syslog.') + ' ' + _('Dump cache on SIGUSR1, include requesting IP.')); - o.optional = true; - - o = s.taboption('general', form.DynamicList, 'server', - _('DNS forwardings'), - _('Forward specific domain queries to specific upstream servers.')); - o.optional = true; - o.placeholder = '/*.example.org/10.1.2.3'; - o.validate = validateServerSpec; - - o = s.taboption('general', form.DynamicList, 'address', - _('Addresses'), - _('Resolve specified FQDNs to an IP.') + '
' + - customi18n(_('Syntax: {code_syntax}.'), - {code_syntax: '/fqdn[/fqdn…]/[ipaddr]'}) + '
' + - customi18n(_('{example_nx} returns {nxdomain}.', - 'hint: /example.com/ returns NXDOMAIN.'), - {example_nx: '/example.com/', nxdomain: 'NXDOMAIN'}) + '
' + - customi18n(_('{any_domain} matches any domain (and returns {nxdomain}).', - 'hint: /#/ matches any domain (and returns NXDOMAIN).'), - {any_domain:'/#/', nxdomain: 'NXDOMAIN'}) + '
' + - customi18n( - _('{example_null} returns {null_addr} addresses ({null_ipv4}, {null_ipv6}) for {example_com} and its subdomains.', - 'hint: /example.com/# returns NULL addresses (0.0.0.0, ::) for example.com and its subdomains.'), - { example_null: '/example.com/#', - null_addr: 'NULL', - null_ipv4: '0.0.0.0', - null_ipv6: '::', - example_com: 'example.com', - } - ) - ); - o.optional = true; - o.placeholder = '/router.local/router.lan/192.168.0.1'; - - o = s.taboption('general', form.DynamicList, 'ipset', - _('IP sets'), - _('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.')); - o.optional = true; - o.placeholder = '/example.org/ipset,ipset6'; - - o = s.taboption('general', form.Flag, 'rebind_protection', - _('Rebind protection'), - customi18n(_('Discard upstream responses containing {rfc_1918_link} addresses.') ) + '
' + - customi18n(_('Discard also upstream responses containing {rfc_4193_link}, Link-Local and private IPv4-Mapped {rfc_4291_link} IPv6 Addresses.') ) - ); - o.rmempty = false; - - o = s.taboption('general', form.Flag, 'rebind_localhost', - _('Allow localhost'), - customi18n( - _('Exempt {loopback_slash_8_v4} and {localhost_v6} from rebinding checks, e.g. for RBL services.') - ) - ); - o.depends('rebind_protection', '1'); - - o = s.taboption('general', form.DynamicList, 'rebind_domain', - _('Domain whitelist'), - customi18n(_('List of domains to allow {rfc_1918_link} responses for.') ) - ); - o.depends('rebind_protection', '1'); - o.optional = true; - o.placeholder = 'ihost.netflix.com'; - o.validate = validateAddressList; - - o = s.taboption('general', form.Flag, 'localservice', - _('Local service only'), - _('Accept DNS queries only from hosts whose address is on a local subnet.')); - o.optional = false; - o.rmempty = false; - - o = s.taboption('general', form.Flag, 'nonwildcard', - _('Non-wildcard'), - _('Bind only to configured interface addresses, instead of the wildcard address.')); - o.default = o.enabled; - o.optional = false; - o.rmempty = true; - - o = s.taboption('general', widgets.NetworkSelect, 'interface', - _('Listen interfaces'), - _('Listen only on the specified interfaces, and loopback if not excluded explicitly.')); - o.multiple = true; - o.nocreate = true; - - o = s.taboption('general', widgets.NetworkSelect, 'notinterface', - _('Exclude interfaces'), - _('Do not listen on the specified interfaces.')); - o.loopback = true; - o.multiple = true; - o.nocreate = true; - - o = s.taboption('relay', form.SectionValue, '__relays__', form.TableSection, 'relay', null, - _('Relay DHCP requests elsewhere. OK: v4↔v4, v6↔v6. Not OK: v4↔v6, v6↔v4.') - + '
' + _('Note: you may also need a DHCP Proxy (currently unavailable) when specifying a non-standard Relay To port(addr#port).') - + '
' + _('You may add multiple unique Relay To on the same Listen addr.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'local_addr', _('Relay from')); - so.rmempty = false; - so.datatype = 'ipaddr'; - - for (var family = 4; family <= 6; family += 2) { - for (var i = 0; i < networks.length; i++) { - if (networks[i].getName() != 'loopback') { - var addrs = (family == 6) ? networks[i].getIP6Addrs() : networks[i].getIPAddrs(); - for (var j = 0; j < addrs.length; j++) { - var addr = addrs[j].split('/')[0]; - so.value(addr, E([], [ - addr, ' (', - widgets.NetworkSelect.prototype.renderIfaceBadge(networks[i]), - ')' - ])); - } - } - } - } - - so = ss.option(form.Value, 'server_addr', _('Relay to address')); - so.rmempty = false; - so.optional = false; - so.placeholder = '192.168.10.1#535'; - - so.validate = function(section, value) { - var m = this.section.formvalue(section, 'local_addr'), - n = this.section.formvalue(section, 'server_addr'), - p; - - if (!m || !n) { - return _('Both "Relay from" and "Relay to address" must be specified.'); - } - else { - p = n.split('#'); - if (p.length > 1 && !/^[0-9]+$/.test(p[1])) - return _('Expected port number.'); - else - n = p[0]; - - if ((validation.parseIPv6(m) && validation.parseIPv6(n)) || - validation.parseIPv4(m) && validation.parseIPv4(n)) - return true; - else - return _('Address families of "Relay from" and "Relay to address" must match.') - } - return true; - }; - - - so = ss.option(widgets.NetworkSelect, 'interface', _('Only accept replies via')); - so.optional = true; - so.rmempty = false; - so.placeholder = 'lan'; - - s.taboption('files', form.Flag, 'readethers', - customi18n(_('Use {etc_ethers}') ), - customi18n(_('Read {etc_ethers} to configure the DHCP server.') ) - ); - - s.taboption('files', form.Value, 'leasefile', - _('Lease file'), - _('File to store DHCP lease information.')); - - o = s.taboption('files', form.Flag, 'noresolv', - _('Ignore resolv file')); - o.optional = true; - - o = s.taboption('files', form.Value, 'resolvfile', - _('Resolv file'), - _('File with upstream resolvers.')); - o.depends('noresolv', '0'); - o.placeholder = '/tmp/resolv.conf.d/resolv.conf.auto'; - o.optional = true; - - o = s.taboption('files', form.Flag, 'nohosts', - customi18n(_('Ignore {etc_hosts}') ) - ); - o.optional = true; - - o = s.taboption('files', form.DynamicList, 'addnhosts', - _('Additional hosts files')); - o.optional = true; - o.placeholder = '/etc/dnsmasq.hosts'; - - o = s.taboption('advanced', form.Flag, 'quietdhcp', - _('Suppress logging'), - _('Suppress logging of the routine operation for the DHCP protocol.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'sequential_ip', - _('Allocate IPs sequentially'), - _('Allocate IP addresses sequentially, starting from the lowest available address.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'boguspriv', - _('Filter private'), - customi18n( - _('Reject reverse lookups to {rfc_6303_link} IP ranges ({reverse_arpa}) not in {etc_hosts}.') ) - ); - o.default = o.enabled; - - s.taboption('advanced', form.Flag, 'filterwin2k', - _('Filter SRV/SOA service discovery'), - _('Filters SRV/SOA service discovery, to avoid triggering dial-on-demand links.') + '
' + - _('May prevent VoIP or other services from working.')); - - o = s.taboption('advanced', form.Flag, 'filter_aaaa', - _('Filter IPv6 AAAA records'), - _('Remove IPv6 addresses from the results and only return IPv4 addresses.') + '
' + - _('Can be useful if ISP has IPv6 nameservers but does not provide IPv6 routing.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'filter_a', - _('Filter IPv4 A records'), - _('Remove IPv4 addresses from the results and only return IPv6 addresses.')); - o.optional = true; - - s.taboption('advanced', form.Flag, 'localise_queries', - _('Localise queries'), - customi18n(_('Limit response records (from {etc_hosts}) to those that fall within the subnet of the querying interface.') ) + '
' + - _('This prevents unreachable IPs in subnets not accessible to you.') + '
' + - _('Note: IPv4 only.')); - - if (L.hasSystemFeature('dnsmasq', 'dnssec')) { - o = s.taboption('advanced', form.Flag, 'dnssec', - _('DNSSEC'), - _('Validate DNS replies and cache DNSSEC data, requires upstream to support DNSSEC.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'dnsseccheckunsigned', - _('DNSSEC check unsigned'), - _('Verify unsigned domain responses really come from unsigned domains.')); - o.default = o.enabled; - o.optional = true; - } - - s.taboption('advanced', form.Flag, 'expandhosts', - _('Expand hosts'), - _('Add local domain suffix to names served from hosts files.')); - - s.taboption('advanced', form.Flag, 'nonegcache', - _('No negative cache'), - _('Do not cache negative replies, e.g. for non-existent domains.')); - - o = s.taboption('advanced', form.Value, 'serversfile', - _('Additional servers file'), - customi18n(_('File listing upstream resolvers, optionally domain-specific, e.g. {servers_file_entry01}, {servers_file_entry02}.') ) - ); - o.placeholder = '/etc/dnsmasq.servers'; - - o = s.taboption('advanced', form.Flag, 'strictorder', - _('Strict order'), - _('Upstream resolvers will be queried in the order of the resolv file.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'allservers', - _('All servers'), - _('Query all available upstream resolvers.')); - o.optional = true; - - o = s.taboption('advanced', form.DynamicList, 'bogusnxdomain', - customi18n(_('IPs to override with {nxdomain}') ), - customi18n(_('Transform replies which contain the specified addresses or subnets into {nxdomain} responses.') ) - ); - o.optional = true; - o.placeholder = '64.94.110.11'; - - o = s.taboption('advanced', form.Value, 'port', - _('DNS server port'), - _('Listening port for inbound DNS queries.')); - o.optional = true; - o.datatype = 'port'; - o.placeholder = 53; - - o = s.taboption('advanced', form.Value, 'queryport', - _('DNS query port'), - _('Fixed source port for outbound DNS queries.')); - o.optional = true; - o.datatype = 'port'; - o.placeholder = _('any'); - - o = s.taboption('advanced', form.Value, 'dhcpleasemax', - _('Max. DHCP leases'), - _('Maximum allowed number of active DHCP leases.')); - o.optional = true; - o.datatype = 'uinteger'; - o.placeholder = _('unlimited'); - - o = s.taboption('advanced', form.Value, 'ednspacket_max', - _('Max. EDNS0 packet size'), - _('Maximum allowed size of EDNS0 UDP packets.')); - o.optional = true; - o.datatype = 'uinteger'; - o.placeholder = 1280; - - o = s.taboption('advanced', form.Value, 'dnsforwardmax', - _('Max. concurrent queries'), - _('Maximum allowed number of concurrent DNS queries.')); - o.optional = true; - o.datatype = 'uinteger'; - o.placeholder = 150; - - o = s.taboption('advanced', form.Value, 'cachesize', - _('Size of DNS query cache'), - _('Number of cached DNS entries, 10000 is maximum, 0 is no caching.')); - o.optional = true; - o.datatype = 'range(0,10000)'; - o.placeholder = 1000; - - o = s.taboption('advanced', form.Value, 'addmac', - _('Add requestor MAC'), - _('Add the MAC address of the requestor to DNS queries which are forwarded upstream.') + ' ' + '
' + - _('%s uses the default MAC address format encoding').format('enabled') + ' ' + '
' + - _('%s uses an alternative encoding of the MAC as base64').format('base64') + ' ' + '
' + - _('%s uses a human-readable encoding of hex-and-colons').format('text')); - o.optional = true; - o.value('', _('off')); - o.value('1', _('enabled (default)')); - o.value('base64'); - o.value('text'); - s.taboption('advanced', form.Flag, 'stripmac', - _('Remove MAC address before forwarding query'), - _('Remove any MAC address information already in downstream queries before forwarding upstream.')); - o = s.taboption('advanced', form.Value, 'addsubnet', - _('Add subnet address to forwards'), - _('Add a subnet address to the DNS queries which are forwarded upstream, leaving this value empty disables the feature.') + ' ' + - _('If an address is specified in the flag, it will be used, otherwise, the address of the requestor will be used.') + ' ' + - _('The amount of the address forwarded depends on the prefix length parameter: 32 (128 for IPv6) forwards the whole address, zero forwards none of it but still marks the request so that no upstream nameserver will add client address information either.') + ' ' + '
' + - _('The default (%s) is zero for both IPv4 and IPv6.').format('0,0') + ' ' + '
' + - _('%s adds the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.').format('24,96') + ' ' + '
' + - _('%s adds 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.').format('1.2.3.4/24') + ' ' + '
' + - _('%s adds 1.2.3.0/24 for both IPv4 and IPv6 requestors.').format('1.2.3.4/24,1.2.3.4/24')); - o.optional = true; - s.taboption('advanced', form.Flag, 'stripsubnet', - _('Remove subnet address before forwarding query'), - _('Remove any subnet address already present in a downstream query before forwarding it upstream.')); - - o = s.taboption('pxe_tftp', form.Flag, 'enable_tftp', - _('Enable TFTP server'), - _('Enable the built-in single-instance TFTP server.')); - o.optional = true; - - o = s.taboption('pxe_tftp', form.Value, 'tftp_root', - _('TFTP server root'), - _('Root directory for files served via TFTP. Enable TFTP server and TFTP server root turn on the TFTP server and serve files from TFTP server root.')); - o.depends('enable_tftp', '1'); - o.optional = true; - o.placeholder = '/'; - - o = s.taboption('pxe_tftp', form.Value, 'dhcp_boot', - _('Network boot image'), - _('Filename of the boot image advertised to clients.')); - o.depends('enable_tftp', '1'); - o.optional = true; - o.placeholder = 'pxelinux.0'; - - /* PXE - https://openwrt.org/docs/guide-user/base-system/dhcp#booting_options */ - o = s.taboption('pxe_tftp', form.SectionValue, '__pxe__', form.GridSection, 'boot', null, - _('Special PXE boot options for Dnsmasq.')); - ss = o.subsection; - ss.addremove = true; - ss.anonymous = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'filename', - _('Filename'), - _('Host requests this filename from the boot server.')); - so.optional = false; - so.placeholder = 'pxelinux.0'; - - so = ss.option(form.Value, 'servername', - _('Server name'), - _('The hostname of the boot server')); - so.optional = false; - so.placeholder = 'myNAS'; - - so = ss.option(form.Value, 'serveraddress', - _('Server address'), - _('The IP address of the boot server')); - so.optional = false; - so.placeholder = '192.168.1.2'; - - so = ss.option(form.DynamicList, 'dhcp_option', - _('DHCP Options'), - _('Options for the Network-ID. (Note: needs also Network-ID.) E.g. "42,192.168.1.4" for NTP server, "3,192.168.4.4" for default route. 0.0.0.0 means "the address of the system running dnsmasq".')); - so.optional = true; - so.placeholder = '42,192.168.1.4'; - - so = ss.option(widgets.DeviceSelect, 'networkid', - _('Network-ID'), - _('Apply DHCP Options to this net. (Empty = all clients).')); - so.optional = true; - so.noaliases = true; - - so = ss.option(form.Flag, 'force', - _('Force'), - _('Always send DHCP Options. Sometimes needed, with e.g. PXELinux.')); - so.optional = true; - - so = ss.option(form.Value, 'instance', - _('Instance'), - _('Dnsmasq instance to which this boot section is bound. If unspecified, the section is valid for all dnsmasq instances.')); - so.optional = true; - - Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); - so.value(name, display_str); - }); - - o = s.taboption('srvhosts', form.SectionValue, '__srvhosts__', form.TableSection, 'srvhost', null, - _('Bind service records to a domain name: specify the location of services. See RFC2782.').format('https://datatracker.ietf.org/doc/html/rfc2782') - + '
' + _('_service: _sip, _ldap, _imap, _stun, _xmpp-client, … . (Note: while _http is possible, no browsers support SRV records.)') - + '
' + _('_proto: _tcp, _udp, _sctp, _quic, … .') - + '
' + _('You may add multiple records for the same Target.') - + '
' + _('Larger weights (of the same prio) are given a proportionately higher probability of being selected.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - - so = ss.option(form.Value, 'srv', _('SRV'), _('Syntax:') + ' ' + '_service._proto.example.com.'); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = '_sip._tcp.example.com.'; - - so = ss.option(form.Value, 'target', _('Target'), _('CNAME or fqdn')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'sip.example.com.'; - - so = ss.option(form.Value, 'port', _('Port')); - so.rmempty = false; - so.datatype = 'port'; - so.placeholder = '5060'; - - so = ss.option(form.Value, 'class', _('Priority'), _('Ordinal: lower comes first.')); - so.rmempty = true; - so.datatype = 'range(0,65535)'; - so.placeholder = '10'; - - so = ss.option(form.Value, 'weight', _('Weight')); - so.rmempty = true; - so.datatype = 'range(0,65535)'; - so.placeholder = '50'; - - o = s.taboption('mxhosts', form.SectionValue, '__mxhosts__', form.TableSection, 'mxhost', null, - _('Bind service records to a domain name: specify the location of services.') - + '
' + _('You may add multiple records for the same domain.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'domain', _('Domain')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'example.com.'; - - so = ss.option(form.Value, 'relay', _('Relay')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'relay.example.com.'; - - so = ss.option(form.Value, 'pref', _('Priority'), _('Ordinal: lower comes first.')); - so.rmempty = true; - so.datatype = 'range(0,65535)'; - so.placeholder = '0'; - - o = s.taboption('cnamehosts', form.SectionValue, '__cname__', form.TableSection, 'cname', null, - _('Set an alias for a hostname.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'cname', _('Domain')); - so.rmempty = false; - so.validate = validateHostname; - so.placeholder = 'www.example.com.'; - - so = ss.option(form.Value, 'target', _('Target')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'example.com.'; - - o = s.taboption('hosts', form.SectionValue, '__hosts__', form.GridSection, 'domain', null, - _('Hostnames are used to bind a domain name to an IP address. This setting is redundant for hostnames already configured with static leases, but it can be useful to rebind an FQDN.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - - so = ss.option(form.Value, 'name', _('Hostname')); - so.rmempty = false; - so.datatype = 'hostname'; - - so = ss.option(form.Value, 'ip', _('IP address')); - so.rmempty = false; - so.datatype = 'ipaddr'; - - var ipaddrs = {}; - - Object.keys(hosts).forEach(function(mac) { - var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4); - - for (var i = 0; i < addrs.length; i++) - ipaddrs[addrs[i]] = hosts[mac].name || mac; - }); - - L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { - so.value(ipv4, '%s (%s)'.format(ipv4, ipaddrs[ipv4])); - }); - - o = s.taboption('ipsets', form.SectionValue, '__ipsets__', form.GridSection, 'ipset', null, - _('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.') + '
' + - _('The netfilter components below are only regarded when running fw4.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - ss.modaltitle = _('Edit IP set'); - - so = ss.option(form.DynamicList, 'name', _('Name of the set')); - so.rmempty = false; - so.editable = true; - so.datatype = 'string'; - - so = ss.option(form.DynamicList, 'domain', _('FQDN')); - so.rmempty = false; - so.editable = true; - so.datatype = 'hostname'; - - so = ss.option(form.Value, 'table', _('Netfilter table name'), _('Defaults to fw4.')); - so.editable = true; - so.placeholder = 'fw4'; - so.rmempty = true; - - so = ss.option(form.ListValue, 'table_family', _('Table IP family'), _('Defaults to IPv4+6.') + ' ' + _('Can be hinted by adding 4 or 6 to the name.') + '
' + - _('Adding an IPv6 to an IPv4 set and vice-versa silently fails.')); - so.editable = true; - so.rmempty = true; - so.value('inet', _('IPv4+6')); - so.value('ip', _('IPv4')); - so.value('ip6', _('IPv6')); - - o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null, - _('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '

' + - _('Use the Add Button to add a new lease entry. The MAC address identifies the host, the IPv4 address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.') + '

' + - _('The tag construct filters which host directives are used; more than one tag can be provided, in this case the request must match all of them. Tagged directives are used in preference to untagged ones. Note that one of mac, duid or hostname still needs to be specified (can be a wildcard).')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.nodescriptions = true; - ss.max_cols = 8; - ss.modaltitle = _('Edit static lease'); - - so = ss.option(form.Value, 'name', - _('Hostname'), - _('Optional hostname to assign')); - so.validate = validateHostname; - so.rmempty = true; - so.write = function(section, value) { - uci.set('dhcp', section, 'name', value); - uci.set('dhcp', section, 'dns', '1'); - }; - so.remove = function(section) { - uci.unset('dhcp', section, 'name'); - uci.unset('dhcp', section, 'dns'); - }; - - //this can be a .DynamicList or a .Value with a widget and dnsmasq handles multimac OK. - so = ss.option(form.DynamicList, 'mac', - _('MAC address(es)'), - _('The hardware address(es) of this entry/host.') + '

' + - _('In DHCPv4, it is possible to include more than one mac address. This allows an IP address to be associated with multiple macaddrs, and dnsmasq abandons a DHCP lease to one of the macaddrs when another asks for a lease. It only works reliably if only one of the macaddrs is active at any time.')); - //As a special case, in DHCPv4, it is possible to include more than one hardware address. eg: --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2 This allows an IP address to be associated with multiple hardware addresses, and gives dnsmasq permission to abandon a DHCP lease to one of the hardware addresses when another one asks for a lease - so.rmempty = true; - so.cfgvalue = function(section) { - var macs = uci.get('dhcp', section, 'mac'); - if(!Array.isArray(macs)){ - return expandAndFormatMAC(L.toArray(macs)); - } else { - return expandAndFormatMAC(macs); - } - }; - //removed jows renderwidget function which hindered multi-mac entry - so.validate = validateMACAddr.bind(so, pools); - Object.keys(hosts).forEach(function(mac) { - var hint = hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0]; - so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); - }); - - so = ss.option(form.Value, 'ip', _('IPv4 address'), _('The IP address to be used for this host, or ignore to ignore any DHCP request from this host.')); - so.value('ignore', _('Ignore')); - so.datatype = 'or(ip4addr,"ignore")'; - so.validate = function(section, value) { - var m = this.section.formvalue(section, 'mac'), - n = this.section.formvalue(section, 'name'); - - if ((m && !m.length > 0) && !n) - return _('One of hostname or MAC address must be specified!'); - - if (!value || value == 'ignore') - return true; - - var leases = uci.sections('dhcp', 'host'); - - for (var i = 0; i < leases.length; i++) - if (leases[i]['.name'] != section && leases[i].ip == value) - return _('The IP address %h is already used by another static lease').format(value); - - for (var i = 0; i < pools.length; i++) { - var net_mask = calculateNetwork(value, pools[i].netmask); - - if (net_mask && net_mask[0] == pools[i].network) - return true; - } - - return _('The IP address is outside of any DHCP pool address range'); - }; - - L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { - so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4); - }); - - so = ss.option(form.Value, 'leasetime', - _('Lease time'), - _('Host-specific lease time, e.g. 5m, 3h, 7d.')); - so.rmempty = true; - so.value('5m', _('5m (5 minutes)')); - so.value('3h', _('3h (3 hours)')); - so.value('12h', _('12h (12 hours - default)')); - so.value('7d', _('7d (7 days)')); - so.value('infinite', _('infinite (lease does not expire)')); - - so = ss.option(form.Value, 'duid', - _('DUID'), - _('The DHCPv6-DUID (DHCP unique identifier) of this host.')); - so.datatype = 'and(rangelength(20,36),hexstring)'; - Object.keys(duids).forEach(function(duid) { - so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?')); - }); - - so = ss.option(form.Value, 'hostid', - _('IPv6-Suffix (hex)'), - _('The IPv6 interface identifier (address suffix) as hexadecimal number (max. 16 chars).')); - so.datatype = 'and(rangelength(0,16),hexstring)'; - - so = ss.option(form.DynamicList, 'tag', - _('Tag'), - _('Assign new, freeform tags to this entry.')); - - so = ss.option(form.DynamicList, 'match_tag', - _('Match Tag'), - _('When a host matches an entry then the special tag %s is set. Use %s to match all known hosts.').format('known', 'known') + '

' + - _('Ignore requests from unknown machines using %s.').format('!known') + '

' + - _('If a host matches an entry which cannot be used because it specifies an address on a different subnet, the tag %s is set.').format('known-othernet')); - so.value('known', _('known')); - so.value('!known', _('!known (not known)')); - so.value('known-othernet', _('known-othernet (on different subnet)')); - so.optional = true; - - so = ss.option(form.Value, 'instance', - _('Instance'), - _('Dnsmasq instance to which this DHCP host section is bound. If unspecified, the section is valid for all dnsmasq instances.')); - so.optional = true; - - Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); - so.value(name, display_str); - }); - - - so = ss.option(form.Flag, 'broadcast', - _('Broadcast'), - _('Force broadcast DHCP response.')); - - so = ss.option(form.Flag, 'dns', - _('Forward/reverse DNS'), - _('Add static forward and reverse DNS entries for this host.')); - - o = s.taboption('leases', CBILeaseStatus, '__status__'); - - if (has_dhcpv6) - o = s.taboption('leases', CBILease6Status, '__status6__'); - - return m.render().then(function(mapEl) { - poll.add(function() { - return callDHCPLeases().then(function(leaseinfo) { - var leases = Array.isArray(leaseinfo.dhcp_leases) ? leaseinfo.dhcp_leases : [], - leases6 = Array.isArray(leaseinfo.dhcp6_leases) ? leaseinfo.dhcp6_leases : []; - - cbi_update_table(mapEl.querySelector('#lease_status_table'), - leases.map(function(lease) { - var exp; - - if (lease.expires === false) - exp = E('em', _('unlimited')); - else if (lease.expires <= 0) - exp = E('em', _('expired')); - else - exp = '%t'.format(lease.expires); - - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? hint.name : null, - host = null; - - if (name && lease.hostname && lease.hostname != name) - host = '%s (%s)'.format(lease.hostname, name); - else if (lease.hostname) - host = lease.hostname; - - return [ - host || '-', - lease.ipaddr, - lease.macaddr, - exp - ]; - }), - E('em', _('There are no active leases'))); - - if (has_dhcpv6) { - cbi_update_table(mapEl.querySelector('#lease6_status_table'), - leases6.map(function(lease) { - var exp; - - if (lease.expires === false) - exp = E('em', _('unlimited')); - else if (lease.expires <= 0) - exp = E('em', _('expired')); - else - exp = '%t'.format(lease.expires); - - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? (hint.name || L.toArray(hint.ipaddrs || hint.ipv4)[0] || L.toArray(hint.ip6addrs || hint.ipv6)[0]) : null, - host = null; - - if (name && lease.hostname && lease.hostname != name && lease.ip6addr != name) - host = '%s (%s)'.format(lease.hostname, name); - else if (lease.hostname) - host = lease.hostname; - else if (name) - host = name; - - return [ - host || '-', - lease.ip6addrs ? lease.ip6addrs.join('
') : lease.ip6addr, - lease.duid, - exp - ]; - }), - E('em', _('There are no active leases'))); - } - }); - }); - - return mapEl; - }); - } -}); diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 3d1f1ba65..8b3c993a1 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -440,7 +440,7 @@ sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/l [ "$version" = "rc2" ] && rm -f feeds/luci/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/29_ports.js # luci - rollback dhcp.js -curl -s https://$mirror/openwrt/patch/luci/dhcp/${openwrt_version}-dhcp.js > feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js +[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js > feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js # luci - disable wireless WPA3 [ "$platform" = "bcm53xx" ] && sed -i -e '/if (has_ap_sae || has_sta_sae) {/{N;N;N;N;d;}' feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js From 5265f61e843ab03503da4be0086a9079b9f4bf98 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 Nov 2024 19:22:43 +0800 Subject: [PATCH 106/425] luci-mod-system: mounts: add docker directory mount point Signed-off-by: sbwml --- ...mounts-add-docker-directory-mount-po.patch | 25 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 1 + 2 files changed, 26 insertions(+) create mode 100644 openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch diff --git a/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch b/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch new file mode 100644 index 000000000..cd6be2cb9 --- /dev/null +++ b/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch @@ -0,0 +1,25 @@ +From b5423aca7403dc8b5662bc3e13bf22115fb6b2eb Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sat, 2 Nov 2024 19:13:53 +0800 +Subject: [PATCH] luci-mod-system: mounts: add docker directory mount point + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/system/mounts.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js +index 269b4a9..72f20c2 100644 +--- a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js ++++ b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js +@@ -293,6 +293,7 @@ return view.extend({ + o = s.taboption('general', form.Value, 'target', _('Mount point'), _('Specifies the directory the device is attached to')); + o.value('/', _('Use as root filesystem (/)')); + o.value('/overlay', _('Use as external overlay (/overlay)')); ++ o.value('/opt', _('Use as docker root directory (/opt)')); + o.rmempty = false; + + o = s.taboption('general', form.DummyValue, '__notice', _('Root preparation')); +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 8b3c993a1..d5b2a4dcc 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -431,6 +431,7 @@ pushd feeds/luci curl -s https://$mirror/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch | patch -p1 curl -s https://$mirror/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch | patch -p1 curl -s https://$mirror/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch | patch -p1 popd # Luci diagnostics.js From 39bbdee62b0d42eb41b2f122065ba09adae4851c Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 4 Nov 2024 15:56:56 +0800 Subject: [PATCH 107/425] linux-6.12: bump to 6.12-rc6 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index ad85ee363..dbc9b8f15 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -rc5 -LINUX_KERNEL_HASH-6.12-rc5 = 02f4d008929d8d62af2a1cd585b4dc58c0c7a427855515b7832ecb34f6f385b1 +LINUX_VERSION-6.12 = -rc6 +LINUX_KERNEL_HASH-6.12-rc6 = 7932703bbf3859932f615c21de4c5ae56d99dc85525bc2361d543216cff7e4ca From 4e25bdd686fdb5f155c14aac5067133cb7cac806 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 4 Nov 2024 22:38:59 +0800 Subject: [PATCH 108/425] add `luci-app-filemanager` Signed-off-by: sbwml --- openwrt/23-config-common | 2 +- openwrt/23-config-minimal-common | 1 + openwrt/23-config-musl-r8500 | 1 + openwrt/23-config-musl-r8500-minimal | 1 + openwrt/scripts/02-prepare_package.sh | 4 +++- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 2e8e4ba6a..7c11d844b 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -108,7 +108,7 @@ CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y -CONFIG_PACKAGE_luci-app-filebrowser=y +CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-frpc=y CONFIG_PACKAGE_luci-app-gowebdav=y CONFIG_PACKAGE_luci-app-mentohust=y diff --git a/openwrt/23-config-minimal-common b/openwrt/23-config-minimal-common index 11e85efea..3ee62ac42 100644 --- a/openwrt/23-config-minimal-common +++ b/openwrt/23-config-minimal-common @@ -86,6 +86,7 @@ CONFIG_PACKAGE_luci-app-autoreboot=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y +CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-oaf=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y diff --git a/openwrt/23-config-musl-r8500 b/openwrt/23-config-musl-r8500 index db7670690..fdbc6d152 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/23-config-musl-r8500 @@ -107,6 +107,7 @@ CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y +CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-frpc=y CONFIG_PACKAGE_luci-app-mentohust=y CONFIG_PACKAGE_luci-app-mosdns=y diff --git a/openwrt/23-config-musl-r8500-minimal b/openwrt/23-config-musl-r8500-minimal index f3e460e6a..160999ba9 100644 --- a/openwrt/23-config-musl-r8500-minimal +++ b/openwrt/23-config-musl-r8500-minimal @@ -97,6 +97,7 @@ CONFIG_NGINX_STREAM_REAL_IP=y ### APPS CONFIG_PACKAGE_luci-app-autoreboot=y CONFIG_PACKAGE_luci-app-ddns=y +CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 70f1d94db..0278c4f4b 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -11,6 +11,9 @@ git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages # default settings git clone https://$github/sbwml/default-settings package/new/default-settings +# luci-app-filemanager +git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager + # ddns - fix boot sed -i '/boot()/,+2d' feeds/packages/net/ddns-scripts/files/etc/init.d/ddns @@ -151,7 +154,6 @@ sed -i 's/services/network/g' feeds/luci/applications/luci-app-nlbwmon/htdocs/lu git clone https://github.com/sbwml/luci-app-mentohust package/new/mentohust # custom packages -rm -rf feeds/packages/utils/coremark feeds/luci/applications/luci-app-filebrowser git clone https://$github/sbwml/openwrt_pkgs package/new/custom --depth=1 # coremark - prebuilt with gcc15 if [ "$platform" = "rk3568" ]; then From e494b63c82ba609f2a8d92f62e101a8a07a3eaed Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 5 Nov 2024 13:08:31 +0800 Subject: [PATCH 109/425] openwrt: add reserve source Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 7 +++++++ openwrt/scripts/02-prepare_package.sh | 1 + 2 files changed, 8 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index d5b2a4dcc..1d02d4bdf 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -12,6 +12,13 @@ fi ######## OpenWrt Patches ######## +# source +if [ "$version" = "rc2" ]; then + sed -i '/mirror2.openwrt.org/a\push @mirrors, '\''https://source.cooluc.com'\'';' scripts/download.pl +else + sed -i '/@OPENWRT/a\\t\t"https://source.cooluc.com",' scripts/projectsmirrors.json +fi + [ "$version" = "rc2" ] && generic=generic || generic=generic-24.10 # tools: add llvm/clang toolchain diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 0278c4f4b..9e6faa543 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -154,6 +154,7 @@ sed -i 's/services/network/g' feeds/luci/applications/luci-app-nlbwmon/htdocs/lu git clone https://github.com/sbwml/luci-app-mentohust package/new/mentohust # custom packages +rm -rf feeds/packages/utils/coremark git clone https://$github/sbwml/openwrt_pkgs package/new/custom --depth=1 # coremark - prebuilt with gcc15 if [ "$platform" = "rk3568" ]; then From 920ac2a584df75eac805128006f8620fa27f7d43 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 6 Nov 2024 04:37:41 +0800 Subject: [PATCH 110/425] openwrt-24.10: add luci-app-webdav (based on nginx) Signed-off-by: sbwml --- openwrt/23-config-common | 2 +- openwrt/23-config-minimal-common | 1 + openwrt/23-config-musl-r8500 | 1 + openwrt/23-config-musl-r8500-minimal | 1 + openwrt/scripts/02-prepare_package.sh | 3 +++ 5 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openwrt/23-config-common b/openwrt/23-config-common index 7c11d844b..8252b097d 100644 --- a/openwrt/23-config-common +++ b/openwrt/23-config-common @@ -110,7 +110,6 @@ CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-frpc=y -CONFIG_PACKAGE_luci-app-gowebdav=y CONFIG_PACKAGE_luci-app-mentohust=y CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y @@ -128,6 +127,7 @@ CONFIG_PACKAGE_luci-app-upnp=y CONFIG_PACKAGE_luci-app-usb-printer=y CONFIG_PACKAGE_luci-app-vlmcsd=y CONFIG_PACKAGE_luci-app-watchcat=y +CONFIG_PACKAGE_luci-app-webdav=y CONFIG_PACKAGE_luci-app-wolplus=y CONFIG_PACKAGE_luci-app-zerotier=y CONFIG_PACKAGE_ariang-nginx=y diff --git a/openwrt/23-config-minimal-common b/openwrt/23-config-minimal-common index 3ee62ac42..26d23e7d9 100644 --- a/openwrt/23-config-minimal-common +++ b/openwrt/23-config-minimal-common @@ -91,6 +91,7 @@ CONFIG_PACKAGE_luci-app-oaf=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y +CONFIG_PACKAGE_luci-app-webdav=y ### DDNS Scripts CONFIG_PACKAGE_ddns-scripts=y diff --git a/openwrt/23-config-musl-r8500 b/openwrt/23-config-musl-r8500 index fdbc6d152..aca69530a 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/23-config-musl-r8500 @@ -122,6 +122,7 @@ CONFIG_PACKAGE_luci-app-upnp=y CONFIG_PACKAGE_luci-app-usb-printer=y CONFIG_PACKAGE_luci-app-vlmcsd=y CONFIG_PACKAGE_luci-app-watchcat=y +CONFIG_PACKAGE_luci-app-webdav=y CONFIG_PACKAGE_luci-app-wolplus=y CONFIG_PACKAGE_luci-app-zerotier=y diff --git a/openwrt/23-config-musl-r8500-minimal b/openwrt/23-config-musl-r8500-minimal index 160999ba9..daa08c429 100644 --- a/openwrt/23-config-musl-r8500-minimal +++ b/openwrt/23-config-musl-r8500-minimal @@ -101,6 +101,7 @@ CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y +CONFIG_PACKAGE_luci-app-webdav=y ### DDNS Scripts CONFIG_PACKAGE_ddns-scripts=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 9e6faa543..92fd8cd57 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -14,6 +14,9 @@ git clone https://$github/sbwml/default-settings package/new/default-settings # luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager +# luci-app-webdav +[ "$version" = "snapshots-24.10" ] && git clone https://$github/sbwml/luci-app-webdav package/new/luci-app-webdav + # ddns - fix boot sed -i '/boot()/,+2d' feeds/packages/net/ddns-scripts/files/etc/init.d/ddns From 5b5d6a5b7fe9a20ac6d52304e914be76c4bb1528 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 7 Nov 2024 02:33:20 +0800 Subject: [PATCH 111/425] toolchain: GCC 15-20241103 Snapshot Signed-off-by: sbwml --- openwrt/build.sh | 1 - ...toolchain-gcc-add-support-for-GCC-15.patch | 754 +++++++++++++++++- ...toolchain-gcc-add-support-for-GCC-15.patch | 4 +- 3 files changed, 746 insertions(+), 13 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 976575ea3..f5e6f1eb5 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -373,7 +373,6 @@ if [ "$1" = "rc2" ]; then curl -s https://$mirror/openwrt/generic/config-gcc11 >> .config fi else - cp -a toolchain/gcc/patches-14.x toolchain/gcc/patches-15.x curl -s https://$mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 fi [ "$USE_GCC13" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc13 >> .config diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch index 70fb33cad..eaab7537f 100644 --- a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -1,14 +1,48 @@ -From b903fc6e637efd50ffba4269e019a44301e44bad Mon Sep 17 00:00:00 2001 +From 1ed5c775935304f67aff4aa83c85d17c4f31afc4 Mon Sep 17 00:00:00 2001 From: sbwml -Date: Fri, 4 Oct 2024 11:07:07 +0800 -Subject: [PATCH] toolchain: gcc: add support for GCC 15 +Date: Thu, 7 Nov 2024 01:13:32 +0800 +Subject: [PATCH] gcc: add support for GCC 15 Signed-off-by: sbwml --- - toolchain/gcc/Config.in | 3 +++ - toolchain/gcc/Config.version | 5 +++++ - toolchain/gcc/common.mk | 10 +++++++++- - 3 files changed, 17 insertions(+), 1 deletion(-) + toolchain/gcc/Config.in | 3 + + toolchain/gcc/Config.version | 5 + + toolchain/gcc/common.mk | 10 +- + .../patches-15.x/002-case_insensitive.patch | 24 +++ + ...t-choke-when-building-32bit-on-64bit.patch | 13 ++ + .../gcc/patches-15.x/010-documentation.patch | 35 +++++ + .../gcc/patches-15.x/230-musl_libssp.patch | 13 ++ + .../300-mips_Os_cpu_rtx_cost_model.patch | 21 +++ + .../810-arm-softfloat-libgcc.patch | 33 ++++ + .../gcc/patches-15.x/820-libgcc_pic.patch | 44 ++++++ + .../840-armv4_pass_fix-v4bx_to_ld.patch | 28 ++++ + .../patches-15.x/850-use_shared_libgcc.patch | 54 +++++++ + .../patches-15.x/851-libgcc_no_compat.patch | 22 +++ + .../patches-15.x/870-ppc_no_crtsavres.patch | 11 ++ + .../gcc/patches-15.x/881-no_tm_section.patch | 11 ++ + .../gcc/patches-15.x/900-bad-mips16-crt.patch | 9 ++ + .../gcc/patches-15.x/910-mbsd_multi.patch | 146 ++++++++++++++++++ + .../920-specs_nonfatal_getenv.patch | 22 +++ + ...mpilation-when-making-cross-compiler.patch | 67 ++++++++ + .../970-macos_arm64-building-fix.patch | 45 ++++++ + 20 files changed, 615 insertions(+), 1 deletion(-) + create mode 100644 toolchain/gcc/patches-15.x/002-case_insensitive.patch + create mode 100644 toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch + create mode 100644 toolchain/gcc/patches-15.x/010-documentation.patch + create mode 100644 toolchain/gcc/patches-15.x/230-musl_libssp.patch + create mode 100644 toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch + create mode 100644 toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch + create mode 100644 toolchain/gcc/patches-15.x/820-libgcc_pic.patch + create mode 100644 toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch + create mode 100644 toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch + create mode 100644 toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch + create mode 100644 toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch + create mode 100644 toolchain/gcc/patches-15.x/881-no_tm_section.patch + create mode 100644 toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch + create mode 100644 toolchain/gcc/patches-15.x/910-mbsd_multi.patch + create mode 100644 toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch + create mode 100644 toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch + create mode 100644 toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in index b306040..3ab16a8 100644 @@ -47,7 +81,7 @@ index 49bb368..be06df2 100644 config GCC_USE_DEFAULT_VERSION diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index 0ccf55b..e1b760d 100644 +index 0ccf55b..50e924f 100644 --- a/toolchain/gcc/common.mk +++ b/toolchain/gcc/common.mk @@ -26,7 +26,11 @@ PKG_VERSION:=$(firstword $(subst +, ,$(GCC_VERSION))) @@ -56,7 +90,7 @@ index 0ccf55b..e1b760d 100644 -PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_SOURCE_URL:=https://us.cooluc.com/gcc ++ PKG_SOURCE_URL:=https://us.cooluc.com/gcc/20241103 +else + PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) +endif @@ -68,12 +102,712 @@ index 0ccf55b..e1b760d 100644 endif +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=3683fe2ee97d41007fb5fc2f9eb1d4701715ee440920b5765e8c772e088e1021 ++ PKG_HASH:=da4db21566241844d14b5b2caad4e2cfccbcbe656f10c0b929eea68dfe807ca3 +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x BUGURL=http://bugs.openwrt.org/ +diff --git a/toolchain/gcc/patches-15.x/002-case_insensitive.patch b/toolchain/gcc/patches-15.x/002-case_insensitive.patch +new file mode 100644 +index 0000000..409497e +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/002-case_insensitive.patch +@@ -0,0 +1,24 @@ ++commit 81cc26c706b2bc8c8c1eb1a322e5c5157900836e ++Author: Felix Fietkau ++Date: Sun Oct 19 21:45:51 2014 +0000 ++ ++ gcc: do not assume that the Mac OS X filesystem is case insensitive ++ ++ Signed-off-by: Felix Fietkau ++ ++ SVN-Revision: 42973 ++ ++--- a/include/filenames.h +++++ b/include/filenames.h ++@@ -44,11 +44,6 @@ extern "C" { ++ # define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c) ++ # define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f) ++ #else /* not DOSish */ ++-# if defined(__APPLE__) ++-# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM ++-# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 ++-# endif ++-# endif /* __APPLE__ */ ++ # define HAS_DRIVE_SPEC(f) (0) ++ # define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c) ++ # define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f) +diff --git a/toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch b/toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch +new file mode 100644 +index 0000000..c41f35e +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch +@@ -0,0 +1,13 @@ ++--- a/gcc/real.h +++++ b/gcc/real.h ++@@ -77,8 +77,10 @@ struct GTY(()) real_value { ++ + (REAL_VALUE_TYPE_SIZE%HOST_BITS_PER_WIDE_INT ? 1 : 0)) /* round up */ ++ ++ /* Verify the guess. */ +++#ifndef __LP64__ ++ extern char test_real_width ++ [sizeof (REAL_VALUE_TYPE) <= REAL_WIDTH * sizeof (HOST_WIDE_INT) ? 1 : -1]; +++#endif ++ ++ /* Calculate the format for CONST_DOUBLE. We need as many slots as ++ are necessary to overlay a REAL_VALUE_TYPE on them. This could be +diff --git a/toolchain/gcc/patches-15.x/010-documentation.patch b/toolchain/gcc/patches-15.x/010-documentation.patch +new file mode 100644 +index 0000000..42b816d +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/010-documentation.patch +@@ -0,0 +1,35 @@ ++commit 098bd91f5eae625c7d2ee621e10930fc4434e5e2 ++Author: Luka Perkov ++Date: Tue Feb 26 16:16:33 2013 +0000 ++ ++ gcc: don't build documentation ++ ++ This closes #13039. ++ ++ Signed-off-by: Luka Perkov ++ ++ SVN-Revision: 35807 ++ ++--- a/gcc/Makefile.in +++++ b/gcc/Makefile.in ++@@ -3566,18 +3566,10 @@ doc/gcc.info: $(TEXI_GCC_FILES) ++ doc/gccint.info: $(TEXI_GCCINT_FILES) ++ doc/cppinternals.info: $(TEXI_CPPINT_FILES) ++ ++-doc/%.info: %.texi ++- if [ x$(BUILD_INFO) = xinfo ]; then \ ++- $(MAKEINFO) $(MAKEINFOFLAGS) -I . -I $(gcc_docdir) \ ++- -I $(gcc_docdir)/include -o $@ $<; \ ++- fi +++doc/%.info: ++ ++ # Duplicate entry to handle renaming of gccinstall.info ++-doc/gccinstall.info: $(TEXI_GCCINSTALL_FILES) ++- if [ x$(BUILD_INFO) = xinfo ]; then \ ++- $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \ ++- -I $(gcc_docdir)/include -o $@ $<; \ ++- fi +++doc/gccinstall.info: ++ ++ doc/cpp.dvi: $(TEXI_CPP_FILES) ++ doc/gcc.dvi: $(TEXI_GCC_FILES) +diff --git a/toolchain/gcc/patches-15.x/230-musl_libssp.patch b/toolchain/gcc/patches-15.x/230-musl_libssp.patch +new file mode 100644 +index 0000000..f8dc944 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/230-musl_libssp.patch +@@ -0,0 +1,13 @@ ++--- a/gcc/gcc.cc +++++ b/gcc/gcc.cc ++@@ -989,7 +989,9 @@ proper position among the other output f ++ #endif ++ ++ #ifndef LINK_SSP_SPEC ++-#ifdef TARGET_LIBC_PROVIDES_SSP +++#if DEFAULT_LIBC == LIBC_MUSL +++#define LINK_SSP_SPEC "-lssp_nonshared" +++#elif defined(TARGET_LIBC_PROVIDES_SSP) ++ #define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \ ++ "|fstack-protector-strong|fstack-protector-explicit:}" ++ #else +diff --git a/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch b/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch +new file mode 100644 +index 0000000..4e32b75 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch +@@ -0,0 +1,21 @@ ++commit ecf7671b769fe96f7b5134be442089f8bdba55d2 ++Author: Felix Fietkau ++Date: Thu Aug 4 20:29:45 2016 +0200 ++ ++gcc: add a patch to generate better code with Os on mips ++ ++Also happens to reduce compressed code size a bit ++ ++Signed-off-by: Felix Fietkau ++ ++--- a/gcc/config/mips/mips.cc +++++ b/gcc/config/mips/mips.cc ++@@ -20576,7 +20576,7 @@ mips_option_override (void) ++ flag_pcc_struct_return = 0; ++ ++ /* Decide which rtx_costs structure to use. */ ++- if (optimize_size) +++ if (0 && optimize_size) ++ mips_cost = &mips_rtx_cost_optimize_size; ++ else ++ mips_cost = &mips_rtx_cost_data[mips_tune]; +diff --git a/toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch b/toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch +new file mode 100644 +index 0000000..5c9d86a +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch +@@ -0,0 +1,33 @@ ++commit 8570c4be394cff7282f332f97da2ff569a927ddb ++Author: Imre Kaloz ++Date: Wed Feb 2 20:06:12 2011 +0000 ++ ++ fixup arm soft-float symbols ++ ++ SVN-Revision: 25325 ++ ++--- a/libgcc/config/arm/t-linux +++++ b/libgcc/config/arm/t-linux ++@@ -1,6 +1,10 @@ ++ LIB1ASMSRC = arm/lib1funcs.S ++ LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \ ++- _ctzsi2 _arm_addsubdf3 _arm_addsubsf3 +++ _ctzsi2 _arm_addsubdf3 _arm_addsubsf3 \ +++ _arm_negdf2 _arm_muldivdf3 _arm_cmpdf2 _arm_unorddf2 \ +++ _arm_fixdfsi _arm_fixunsdfsi _arm_truncdfsf2 \ +++ _arm_negsf2 _arm_muldivsf3 _arm_cmpsf2 _arm_unordsf2 \ +++ _arm_fixsfsi _arm_fixunssfsi ++ ++ # Just for these, we omit the frame pointer since it makes such a big ++ # difference. ++--- a/gcc/config/arm/linux-elf.h +++++ b/gcc/config/arm/linux-elf.h ++@@ -58,8 +58,6 @@ ++ %{shared:-lc} \ ++ %{!shared:%{profile:-lc_p}%{!profile:-lc}}" ++ ++-#define LIBGCC_SPEC "%{mfloat-abi=soft*:-lfloat} -lgcc" ++- ++ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2" ++ ++ #define LINUX_TARGET_LINK_SPEC "%{h*} \ +diff --git a/toolchain/gcc/patches-15.x/820-libgcc_pic.patch b/toolchain/gcc/patches-15.x/820-libgcc_pic.patch +new file mode 100644 +index 0000000..33ae0a9 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/820-libgcc_pic.patch +@@ -0,0 +1,44 @@ ++commit c96312958c0621e72c9b32da5bc224ffe2161384 ++Author: Felix Fietkau ++Date: Mon Oct 19 23:26:09 2009 +0000 ++ ++ gcc: create a proper libgcc_pic.a static library for relinking (4.3.3+ for now, backport will follow) ++ ++ SVN-Revision: 18086 ++ ++--- a/libgcc/Makefile.in +++++ b/libgcc/Makefile.in ++@@ -944,11 +944,12 @@ $(libgcov-driver-objects): %$(objext): $ ++ ++ # Static libraries. ++ libgcc.a: $(libgcc-objects) +++libgcc_pic.a: $(libgcc-s-objects) ++ libgcov.a: $(libgcov-objects) ++ libunwind.a: $(libunwind-objects) ++ libgcc_eh.a: $(libgcc-eh-objects) ++ ++-libgcc.a libgcov.a libunwind.a libgcc_eh.a: +++libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a: ++ -rm -f $@ ++ ++ objects="$(objects)"; \ ++@@ -972,7 +973,7 @@ all: libunwind.a ++ endif ++ ++ ifeq ($(enable_shared),yes) ++-all: libgcc_eh.a libgcc_s$(SHLIB_EXT) +++all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT) ++ ifneq ($(LIBUNWIND),) ++ all: libunwind$(SHLIB_EXT) ++ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_EXT) ++@@ -1178,6 +1179,10 @@ install-shared: ++ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a ++ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a ++ +++ $(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/ +++ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a +++ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a +++ ++ $(subst @multilib_dir@,$(MULTIDIR),$(subst \ ++ @shlib_base_name@,libgcc_s,$(subst \ ++ @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL)))) +diff --git a/toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch b/toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch +new file mode 100644 +index 0000000..e3cb616 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch +@@ -0,0 +1,28 @@ ++commit 7edc8ca5456d9743dd0075eb3cc5b04f4f24c8cc ++Author: Imre Kaloz ++Date: Wed Feb 2 19:34:36 2011 +0000 ++ ++ add armv4 fixup patches ++ ++ SVN-Revision: 25322 ++ ++ ++--- a/gcc/config/arm/linux-eabi.h +++++ b/gcc/config/arm/linux-eabi.h ++@@ -91,10 +91,15 @@ ++ #define MUSL_DYNAMIC_LINKER \ ++ "/lib/ld-musl-arm" MUSL_DYNAMIC_LINKER_E "%{mfloat-abi=hard:hf}%{mfdpic:-fdpic}.so.1" ++ +++/* For armv4 we pass --fix-v4bx to linker to support EABI */ +++#undef TARGET_FIX_V4BX_SPEC +++#define TARGET_FIX_V4BX_SPEC " %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*"\ +++ "|march=armv4|mcpu=fa526|mcpu=fa626:--fix-v4bx}" +++ ++ /* At this point, bpabi.h will have clobbered LINK_SPEC. We want to ++ use the GNU/Linux version, not the generic BPABI version. */ ++ #undef LINK_SPEC ++-#define LINK_SPEC EABI_LINK_SPEC \ +++#define LINK_SPEC EABI_LINK_SPEC TARGET_FIX_V4BX_SPEC \ ++ LINUX_OR_ANDROID_LD (LINUX_TARGET_LINK_SPEC, \ ++ LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC) ++ +diff --git a/toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch b/toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch +new file mode 100644 +index 0000000..210c790 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch +@@ -0,0 +1,54 @@ ++commit dcfc40358b5a3cae7320c17f8d1cebd5ad5540cd ++Author: Felix Fietkau ++Date: Sun Feb 12 20:25:47 2012 +0000 ++ ++ gcc 4.6: port over the missing patch 850-use_shared_libgcc.patch to prevent libgcc crap from leaking into every single binary ++ ++ SVN-Revision: 30486 ++--- a/gcc/config/arm/linux-eabi.h +++++ b/gcc/config/arm/linux-eabi.h ++@@ -132,10 +132,6 @@ ++ "%{Ofast|ffast-math|funsafe-math-optimizations:%{!shared:crtfastmath.o%s}} " \ ++ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_ENDFILE_SPEC, ANDROID_ENDFILE_SPEC) ++ ++-/* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we ++- do not use -lfloat. */ ++-#undef LIBGCC_SPEC ++- ++ /* Clear the instruction cache from `beg' to `end'. This is ++ implemented in lib1funcs.S, so ensure an error if this definition ++ is used. */ ++--- a/gcc/config/linux.h +++++ b/gcc/config/linux.h ++@@ -58,6 +58,10 @@ see the files COPYING3 and COPYING.RUNTI ++ builtin_assert ("system=posix"); \ ++ } while (0) ++ +++#ifndef LIBGCC_SPEC +++#define LIBGCC_SPEC "%{static|static-libgcc:-lgcc}%{!static:%{!static-libgcc:-lgcc_s}}" +++#endif +++ ++ /* Determine which dynamic linker to use depending on whether GLIBC or ++ uClibc or Bionic or musl is the default C library and whether ++ -muclibc or -mglibc or -mbionic or -mmusl has been passed to change ++--- a/libgcc/mkmap-symver.awk +++++ b/libgcc/mkmap-symver.awk ++@@ -136,5 +136,5 @@ function output(lib) { ++ else if (inherit[lib]) ++ printf("} %s;\n", inherit[lib]); ++ else ++- printf ("\n local:\n\t*;\n};\n"); +++ printf ("\n\t*;\n};\n"); ++ } ++--- a/gcc/config/rs6000/linux.h +++++ b/gcc/config/rs6000/linux.h ++@@ -70,6 +70,9 @@ ++ #undef CPP_OS_DEFAULT_SPEC ++ #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" ++ +++#undef LIBGCC_SPEC +++#define LIBGCC_SPEC "%{!static:%{!static-libgcc:-lgcc_s}} -lgcc" +++ ++ #undef LINK_SHLIB_SPEC ++ #define LINK_SHLIB_SPEC "%{shared:-shared} %{!shared: %{static:-static}} \ ++ %{static-pie:-static -pie --no-dynamic-linker -z text}" +diff --git a/toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch b/toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch +new file mode 100644 +index 0000000..d710e40 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch +@@ -0,0 +1,22 @@ ++commit 64661de100da1ec1061ef3e5e400285dce115e6b ++Author: Felix Fietkau ++Date: Sun May 10 13:16:35 2015 +0000 ++ ++ gcc: add some size optimization patches ++ ++ Signed-off-by: Felix Fietkau ++ ++ SVN-Revision: 45664 ++ ++--- a/libgcc/config/t-libunwind +++++ b/libgcc/config/t-libunwind ++@@ -2,8 +2,7 @@ ++ ++ HOST_LIBGCC2_CFLAGS += -DUSE_GAS_SYMVER ++ ++-LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \ ++- $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c +++LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c ++ LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c ++ ++ # Override the default value from t-slibgcc-elf-ver and mention -lunwind +diff --git a/toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch b/toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch +new file mode 100644 +index 0000000..0dca688 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch +@@ -0,0 +1,11 @@ ++--- a/gcc/config/rs6000/rs6000-logue.cc +++++ b/gcc/config/rs6000/rs6000-logue.cc ++@@ -344,7 +344,7 @@ rs6000_savres_strategy (rs6000_stack_t * ++ /* Define cutoff for using out-of-line functions to save registers. */ ++ if (DEFAULT_ABI == ABI_V4 || TARGET_ELF) ++ { ++- if (!optimize_size) +++ if (1) ++ { ++ strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS; ++ strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS; +diff --git a/toolchain/gcc/patches-15.x/881-no_tm_section.patch b/toolchain/gcc/patches-15.x/881-no_tm_section.patch +new file mode 100644 +index 0000000..2029910 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/881-no_tm_section.patch +@@ -0,0 +1,11 @@ ++--- a/libgcc/crtstuff.c +++++ b/libgcc/crtstuff.c ++@@ -152,7 +152,7 @@ call_ ## FUNC (void) \ ++ #endif ++ ++ #if !defined(USE_TM_CLONE_REGISTRY) && defined(OBJECT_FORMAT_ELF) ++-# define USE_TM_CLONE_REGISTRY 1 +++# define USE_TM_CLONE_REGISTRY 0 ++ #elif !defined(USE_TM_CLONE_REGISTRY) ++ # define USE_TM_CLONE_REGISTRY 0 ++ #endif +diff --git a/toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch b/toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch +new file mode 100644 +index 0000000..b355545 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch +@@ -0,0 +1,9 @@ ++--- a/libgcc/config/mips/t-mips16 +++++ b/libgcc/config/mips/t-mips16 ++@@ -42,3 +42,6 @@ SYNC_CFLAGS = -mno-mips16 ++ ++ # Version these symbols if building libgcc.so. ++ SHLIB_MAPFILES += $(srcdir)/config/mips/libgcc-mips16.ver +++ +++CRTSTUFF_T_CFLAGS += -mno-mips16 +++CRTSTUFF_T_CFLAGS_S += -mno-mips16 +diff --git a/toolchain/gcc/patches-15.x/910-mbsd_multi.patch b/toolchain/gcc/patches-15.x/910-mbsd_multi.patch +new file mode 100644 +index 0000000..07afb52 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/910-mbsd_multi.patch +@@ -0,0 +1,146 @@ ++commit 99368862e44740ff4fd33760893f04e14f9dbdf1 ++Author: Felix Fietkau ++Date: Tue Jul 31 00:52:27 2007 +0000 ++ ++ Port the mbsd_multi patch from freewrt, which adds -fhonour-copts. This will emit warnings in packages that don't use our target cflags properly ++ ++ SVN-Revision: 8256 ++ ++ This patch brings over a feature from MirBSD: ++ * -fhonour-copts ++ If this option is not given, it's warned (depending ++ on environment variables). This is to catch errors ++ of misbuilt packages which override CFLAGS themselves. ++ ++ This patch was authored by Thorsten Glaser ++ with copyright assignment to the FSF in effect. ++ ++--- a/gcc/c-family/c-opts.cc +++++ b/gcc/c-family/c-opts.cc ++@@ -110,6 +110,9 @@ static size_t include_cursor; ++ /* Whether any standard preincluded header has been preincluded. */ ++ static bool done_preinclude; ++ +++/* Check if a port honours COPTS. */ +++static int honour_copts = 0; +++ ++ static void handle_OPT_d (const char *); ++ static void set_std_cxx98 (int); ++ static void set_std_cxx11 (int); ++@@ -503,6 +506,12 @@ c_common_handle_option (size_t scode, co ++ flag_no_builtin = !value; ++ break; ++ +++ case OPT_fhonour_copts: +++ if (c_language == clk_c) { +++ honour_copts++; +++ } +++ break; +++ ++ case OPT_fconstant_string_class_: ++ constant_string_class_name = arg; ++ break; ++@@ -1332,6 +1341,47 @@ c_common_init (void) ++ return false; ++ } ++ +++ if (c_language == clk_c) { +++ char *ev = getenv ("GCC_HONOUR_COPTS"); +++ int evv; +++ if (ev == NULL) +++ evv = -1; +++ else if ((*ev == '0') || (*ev == '\0')) +++ evv = 0; +++ else if (*ev == '1') +++ evv = 1; +++ else if (*ev == '2') +++ evv = 2; +++ else if (*ev == 's') +++ evv = -1; +++ else { +++ warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1"); +++ evv = 1; /* maybe depend this on something like MIRBSD_NATIVE? */ +++ } +++ if (evv == 1) { +++ if (honour_copts == 0) { +++ error ("someone does not honour COPTS at all in lenient mode"); +++ return false; +++ } else if (honour_copts != 1) { +++ warning (0, "someone does not honour COPTS correctly, passed %d times", +++ honour_copts); +++ } +++ } else if (evv == 2) { +++ if (honour_copts == 0) { +++ error ("someone does not honour COPTS at all in strict mode"); +++ return false; +++ } else if (honour_copts != 1) { +++ error ("someone does not honour COPTS correctly, passed %d times", +++ honour_copts); +++ return false; +++ } +++ } else if (evv == 0) { +++ if (honour_copts != 1) +++ inform (UNKNOWN_LOCATION, "someone does not honour COPTS correctly, passed %d times", +++ honour_copts); +++ } +++ } +++ ++ return true; ++ } ++ ++--- a/gcc/c-family/c.opt +++++ b/gcc/c-family/c.opt ++@@ -1987,6 +1987,9 @@ C++ ObjC++ Optimization Alias(fexception ++ fhonor-std ++ C++ ObjC++ WarnRemoved ++ +++fhonour-copts +++C ObjC C++ ObjC++ RejectNegative +++ ++ fhosted ++ C ObjC ++ Assume normal C execution environment. ++--- a/gcc/common.opt +++++ b/gcc/common.opt ++@@ -1908,6 +1908,9 @@ Enum(hardcfr_check_noreturn_calls) Strin ++ EnumValue ++ Enum(hardcfr_check_noreturn_calls) String(always) Value(HCFRNR_ALWAYS) ++ +++fhonour-copts +++Common RejectNegative +++ ++ ; Nonzero means ignore `#ident' directives. 0 means handle them. ++ ; Generate position-independent code for executables if possible ++ ; On SVR4 targets, it also controls whether or not to emit a ++--- a/gcc/doc/invoke.texi +++++ b/gcc/doc/invoke.texi ++@@ -10690,6 +10690,17 @@ This option is only supported for C and ++ ++ This warning is upgraded to an error by @option{-pedantic-errors}. ++ +++@item -fhonour-copts +++@opindex fhonour-copts +++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not +++given at least once, and warn if it is given more than once. +++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not +++given exactly once. +++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option +++is not given exactly once. +++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}. +++This flag and environment variable only affect the C language. +++ ++ @opindex Wstack-protector ++ @opindex Wno-stack-protector ++ @item -Wstack-protector ++--- a/gcc/opts.cc +++++ b/gcc/opts.cc ++@@ -2848,6 +2848,9 @@ common_handle_option (struct gcc_options ++ add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg); ++ break; ++ +++ case OPT_fhonour_copts: +++ break; +++ ++ case OPT_Werror: ++ dc->set_warning_as_error_requested (value); ++ break; +diff --git a/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch +new file mode 100644 +index 0000000..5c9849f +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch +@@ -0,0 +1,22 @@ ++Author: Jo-Philipp Wich ++Date: Sat Apr 21 03:02:39 2012 +0000 ++ ++ gcc: add patch to make the getenv() spec function nonfatal if requested environment variable is unset ++ ++ SVN-Revision: 31390 ++ ++--- a/gcc/gcc.cc +++++ b/gcc/gcc.cc ++@@ -10339,8 +10339,10 @@ getenv_spec_function (int argc, const ch ++ } ++ ++ if (!value) ++- fatal_error (input_location, ++- "environment variable %qs not defined", varname); +++ { +++ warning (input_location, "environment variable %qs not defined", varname); +++ value = ""; +++ } ++ ++ /* We have to escape every character of the environment variable so ++ they are not interpreted as active spec characters. A +diff --git a/toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch b/toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch +new file mode 100644 +index 0000000..b1d7576 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch +@@ -0,0 +1,67 @@ ++From dda6b050cd74a352670787a294596a9c56c21327 Mon Sep 17 00:00:00 2001 ++From: Yousong Zhou ++Date: Fri, 4 May 2018 18:20:53 +0800 ++Subject: [PATCH] gotools: fix compilation when making cross compiler ++ ++libgo is "the runtime support library for the Go programming language. ++This library is intended for use with the Go frontend." ++ ++gccgo will link target files with libgo.so which depends on libgcc_s.so.1, but ++the linker will complain that it cannot find it. That's because shared libgcc ++is not present in the install directory yet. libgo.so was made without problem ++because gcc will emit -lgcc_s when compiled with -shared option. When gotools ++were being made, it was supplied with -static-libgcc thus no link option was ++provided. Check LIBGO in gcc/go/gcc-spec.c for how gccgo make a builtin spec ++for linking with libgo.so ++ ++- GccgoCrossCompilation, https://github.com/golang/go/wiki/GccgoCrossCompilation ++- Cross-building instructions, http://www.eglibc.org/archives/patches/msg00078.html ++ ++When 3-pass GCC compilation is used, shared libgcc runtime libraries will be ++available after gcc pass2 completed and will meet the gotools link requirement ++at gcc pass3 ++--- ++ gotools/Makefile.am | 4 +++- ++ gotools/Makefile.in | 4 +++- ++ 2 files changed, 6 insertions(+), 2 deletions(-) ++ ++--- a/gotools/Makefile.am +++++ b/gotools/Makefile.am ++@@ -26,6 +26,7 @@ PWD_COMMAND = $${PWDCMD-pwd} ++ STAMP = echo timestamp > ++ ++ libgodir = ../$(target_noncanonical)/libgo +++libgccdir = ../$(target_noncanonical)/libgcc ++ LIBGODEP = $(libgodir)/libgo.la ++ ++ LIBGOTOOL = $(libgodir)/libgotool.a ++@@ -41,7 +42,8 @@ GOCFLAGS = $(CFLAGS_FOR_TARGET) ++ GOCOMPILE = $(GOCOMPILER) $(GOCFLAGS) ++ ++ AM_GOCFLAGS = -I $(libgodir) ++-AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs +++AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs \ +++ -L $(libgccdir) -L $(libgccdir)/.libs -lgcc_s ++ GOLINK = $(GOCOMPILER) $(GOCFLAGS) $(AM_GOCFLAGS) $(LDFLAGS) $(AM_LDFLAGS) -o $@ ++ ++ libgosrcdir = $(srcdir)/../libgo/go ++--- a/gotools/Makefile.in +++++ b/gotools/Makefile.in ++@@ -337,6 +337,7 @@ mkinstalldirs = $(SHELL) $(toplevel_srcd ++ PWD_COMMAND = $${PWDCMD-pwd} ++ STAMP = echo timestamp > ++ libgodir = ../$(target_noncanonical)/libgo +++libgccdir = ../$(target_noncanonical)/libgcc ++ LIBGODEP = $(libgodir)/libgo.la ++ LIBGOTOOL = $(libgodir)/libgotool.a ++ @NATIVE_FALSE@GOCOMPILER = $(GOC) ++@@ -346,7 +347,8 @@ LIBGOTOOL = $(libgodir)/libgotool.a ++ GOCFLAGS = $(CFLAGS_FOR_TARGET) ++ GOCOMPILE = $(GOCOMPILER) $(GOCFLAGS) ++ AM_GOCFLAGS = -I $(libgodir) ++-AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs +++AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs \ +++ -L $(libgccdir) -L $(libgccdir)/.libs -lgcc_s ++ GOLINK = $(GOCOMPILER) $(GOCFLAGS) $(AM_GOCFLAGS) $(LDFLAGS) $(AM_LDFLAGS) -o $@ ++ libgosrcdir = $(srcdir)/../libgo/go ++ cmdsrcdir = $(libgosrcdir)/cmd +diff --git a/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch b/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch +new file mode 100644 +index 0000000..a4060d9 +--- /dev/null ++++ b/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch +@@ -0,0 +1,45 @@ ++commit 9c6e71079b46ad5433165feaa2001450f2017b56 ++Author: Przemysław Buczkowski ++Date: Mon Aug 16 13:16:21 2021 +0100 ++ ++ GCC: Patch for Apple Silicon compatibility ++ ++ This patch fixes a linker error occuring when compiling ++ the cross-compiler on macOS and ARM64 architecture. ++ ++ Adapted from: ++ https://github.com/richfelker/musl-cross-make/issues/116#issuecomment-823612404 ++ ++ Change-Id: Ia3ee98a163bbb62689f42e2da83a5ef36beb0913 ++ Reviewed-on: https://review.haiku-os.org/c/buildtools/+/4329 ++ Reviewed-by: John Scipione ++ Reviewed-by: Adrien Destugues ++ ++--- a/gcc/config/aarch64/aarch64.h +++++ b/gcc/config/aarch64/aarch64.h ++@@ -1412,7 +1412,7 @@ extern enum aarch64_code_model aarch64_c ++ ++ /* Extra specs when building a native AArch64-hosted compiler. ++ Option rewriting rules based on host system. */ ++-#if defined(__aarch64__) +++#if defined(__aarch64__) && ! defined(__APPLE__) ++ extern const char *host_detect_local_cpu (int argc, const char **argv); ++ #define HAVE_LOCAL_CPU_DETECT ++ # define EXTRA_SPEC_FUNCTIONS \ ++--- a/gcc/config/host-darwin.cc +++++ b/gcc/config/host-darwin.cc ++@@ -23,6 +23,8 @@ ++ #include "options.h" ++ #include "diagnostic-core.h" ++ #include "config/host-darwin.h" +++#include "hosthooks.h" +++#include "hosthooks-def.h" ++ #include ++ ++ /* For Darwin (macOS only) platforms, without ASLR (PIE) enabled on the ++@@ -181,3 +183,5 @@ darwin_gt_pch_use_address (void *&addr, ++ ++ return 1; ++ } +++ +++const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; -- 2.43.5 diff --git a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch index f465118ef..2e0bdcc6b 100644 --- a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -55,7 +55,7 @@ index a1a5108..feae36a 100644 -PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_SOURCE_URL:=https://us.cooluc.com/gcc ++ PKG_SOURCE_URL:=https://us.cooluc.com/gcc/20241103 +else + PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) +endif @@ -67,7 +67,7 @@ index a1a5108..feae36a 100644 endif +ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=3683fe2ee97d41007fb5fc2f9eb1d4701715ee440920b5765e8c772e088e1021 ++ PKG_HASH:=da4db21566241844d14b5b2caad4e2cfccbcbe656f10c0b929eea68dfe807ca3 +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x From eaffad42affacc728db2a3dce3378220236f56f9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 7 Nov 2024 06:30:47 +0800 Subject: [PATCH 112/425] locking openwrt-23.05 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index d1e92001c..3153db53f 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -11,7 +11,7 @@ fi # rockchip - target - r4s/r5s only rm -rf target/linux/rockchip -git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b linux-6.6 +git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-23.05 # x86_64 - target 6.6 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.6 > target/linux/x86/64/config-6.6 @@ -39,7 +39,7 @@ git clone https://nanopi:nanopi@$gitea/sbwml/brcmfmac-firmware-4366b-pcie packag # armsr/armv8 rm -rf target/linux/armsr -git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr +git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b openwrt-23.05 # kernel - 6.x curl -s https://$mirror/tags/kernel-6.6 > include/kernel-6.6 @@ -54,13 +54,13 @@ rm -rf target/linux/generic local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-$kernel_version) release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-$kernel_version | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then - git clone https://$github/sbwml/target_linux_generic -b main target/linux/generic --depth=1 + git clone https://$github/sbwml/target_linux_generic -b openwrt-23.05 target/linux/generic --depth=1 else if [ "$(whoami)" = "runner" ]; then git_name=private - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b main target/linux/generic --depth=1 + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-23.05 target/linux/generic --depth=1 elif [ "$(whoami)" = "sbwml" ]; then - git clone https://$gitea/sbwml/target_linux_generic -b main target/linux/generic --depth=1 + git clone https://$gitea/sbwml/target_linux_generic -b openwrt-23.05 target/linux/generic --depth=1 fi fi From e990a0fe72851496c66073751e586e49e0a79603 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 7 Nov 2024 09:31:05 +0800 Subject: [PATCH 113/425] remove openwrt-23.05 & linux-6.6 Signed-off-by: sbwml --- .github/workflows/build-release.yml | 4 +- .../{23-config-common => 24-config-common} | 3 - ...inimal-common => 24-config-minimal-common} | 3 - ...armsr-armv8 => 24-config-musl-armsr-armv8} | 0 ...{23-config-musl-r4s => 24-config-musl-r4s} | 0 ...{23-config-musl-r5s => 24-config-musl-r5s} | 0 ...config-musl-r8500 => 24-config-musl-r8500} | 3 - ...0-minimal => 24-config-musl-r8500-minimal} | 3 - ...{23-config-musl-x86 => 24-config-musl-x86} | 0 openwrt/build.sh | 100 +- openwrt/generic/config-gcc11 | 5 - openwrt/generic/config-gcc14 | 1 - openwrt/generic/config-gcc15 | 1 - ...ginx-util-fix-compilation-with-GCC13.patch | 40 - .../0002-nginx-util-move-to-pcre2.patch | 166 - openwrt/nginx/openwrt-23.05-uci.conf.template | 54 - ...10-uci.conf.template => uci.conf.template} | 0 ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 0 ...-app-firewall-add-shortcut-fe-option.patch | 0 ...uci-app-firewall-add-ipv6-nat-option.patch | 0 ...firewall-add-custom-nft-rule-support.patch | 0 ...firewall-add-natflow-offload-support.patch | 0 ...l-enable-hardware-offload-only-on-de.patch | 0 ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 34 - ...-app-firewall-add-shortcut-fe-option.patch | 65 - ...uci-app-firewall-add-ipv6-nat-option.patch | 30 - ...firewall-add-custom-nft-rule-support.patch | 82 - ...firewall-add-natflow-offload-support.patch | 55 - .../200-use-ntfs3-instead-of-ntfs.patch | 47 - .../fstools/201-fstools-set-ntfs3-utf8.patch | 27 - ...-for-non-MTD-rootfs_data-new-version.patch | 141 - ...port-extroot-for-non-MTD-rootfs_data.patch | 139 - openwrt/patch/fstools/Makefile | 141 - ...-tiny-add-support-for-XFS-superblock.patch | 324 -- .../glibc/0003-block-add-xfsck-support.patch | 33 - .../0001-tools-add-llvm-clang-toolchain.patch | 2 +- .../0002-tools-add-upx-tools.patch | 2 +- ...3-rootfs-add-upx-compression-support.patch | 6 +- ...ermissions-for-UCI-configuration-fil.patch | 6 +- ...rt-for-local-kmod-installation-sourc.patch | 6 +- ...Add-support-for-llvm-clang-compiler.patch} | 6 +- ...add-MODULE_ALLOW_BTF_MISMATCH-option.patch | 26 - ...ernel-add-out-of-tree-kernel-config.patch} | 8 +- ...rnel-add-miss-config-for-linux-6.11.patch} | 8 +- ...ath-Add-libquadmath-to-the-toolchain.patch | 25 - ...m-variable-to-cross-compilation-fil.patch} | 4 +- ...-legacy-cgroup-v1-memory-controller.patch} | 6 +- ...EEMPT_RT-support-for-aarch64-x86_64.patch} | 8 +- .../203-tools-mold-update-to-2.34.1.patch | 33 - .../linux-6.12-target-linux-generic.patch | 239 + .../0001-tools-add-llvm-clang-toolchain.patch | 89 - .../generic/0002-tools-add-upx-tools.patch | 63 - ...3-rootfs-add-upx-compression-support.patch | 38 - ...ermissions-for-UCI-configuration-fil.patch | 25 - ...rt-for-local-kmod-installation-sourc.patch | 50 - ...add-MODULE_ALLOW_BTF_MISMATCH-option.patch | 41 - ...-Add-support-for-llvm-clang-compiler.patch | 102 - ...ath-Add-libquadmath-to-the-toolchain.patch | 92 - ...kernel-add-out-of-tree-kernel-config.patch | 115 - ...ernel-add-miss-config-for-linux-6.11.patch | 25 - ...rm-variable-to-cross-compilation-fil.patch | 36 - ...lti-Path-TCP-for-SMALL_FLASH-targets.patch | 39 - .../200-toolchain-gcc-update-to-13.2.patch | 2206 --------- ...toolchain-gcc-add-support-for-GCC-14.patch | 64 - ...toolchain-gcc-add-support-for-GCC-15.patch | 78 - .../patch/generic/gcc-14/910-mbsd_multi.patch | 146 - .../gcc-15/970-macos_arm64-building-fix.patch | 45 - ...t-to-use-the-mold-linker-for-package.patch | 32 - ...wide-opt-out-of-tree-wide-mold-usage.patch | 81 - ...lchain-add-mold-as-additional-linker.patch | 58 - .../0004-tools-add-mold-a-modern-linker.patch | 71 - ...TRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch | 63 - ...b-to-use-the-mold-linker-for-package.patch | 71 - ...les-prepare-to-use-different-linkers.patch | 49 - .../0008-tools-mold-update-to-2.34.1.patch | 33 - ...el-name-in-proc-cpuinfo-for-64bit-ta.patch | 32 - .../901-v6.8-cache-enforce-cache-groups.patch | 76 - ...anize-netns_ipv4-fast-path-variables.patch | 192 - ...anize-net_device-fast-path-variables.patch | 309 -- ...rganize-tcp_sock-fast-path-variables.patch | 495 -- ...ing_ratio-to-tcp_sock_read_txrx-grou.patch | 48 - ...den-app-limited-rate-sample-detectio.patch | 52 - ...hrink-delivered_mstamp-first_tx_msta.patch | 74 - ...napshot-packets-in-flight-at-transmi.patch | 109 - ...ount-packets-lost-over-TCP-rate-samp.patch | 70 - ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 38 - ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 57 - ...djust-skb-tx.in_flight-upon-merge-in.patch | 59 - ...djust-skb-tx.in_flight-upon-split-in.patch | 97 - ...ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 73 - ...alize-TSO-sizing-in-TCP-CC-module-AP.patch | 118 - ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 72 - ...ecord-app-limited-status-of-TLP-repa.patch | 45 - ...nform-CC-module-of-losses-repaired-b.patch | 45 - ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 73 - ...r-route-feature-RTAX_FEATURE_ECN_LOW.patch | 109 - ...pdate-TCP-bbr-congestion-control-mod.patch | 2823 ----------- ...nsure-ECN-enabled-BBR-flows-set-ECT-.patch | 59 - ...OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 38 - ...-silence-btf-module-warning-messages.patch | 21 - ...LRNG-Entropy-Source-and-DRNG-Manager.patch | 4336 ----------------- ...cate-one-DRNG-instance-per-NUMA-node.patch | 194 - .../011-LRNG-0003-LRNG-proc-interface.patch | 135 - ...004-LRNG-add-switchable-DRNG-support.patch | 363 -- ...LRNG-add-common-generic-hash-support.patch | 221 - ...-externalize-DRBG-functions-for-LRNG.patch | 114 - ...07-LRNG-add-SP800-90A-DRBG-extension.patch | 327 -- ...add-kernel-crypto-API-PRNG-extension.patch | 305 -- ...-LRNG-add-atomic-DRNG-implementation.patch | 159 - ...mmon-timer-based-entropy-source-code.patch | 197 - ...11-LRNG-add-interrupt-entropy-source.patch | 1218 ----- ...-scheduler-add-entropy-sampling-hook.patch | 35 - ...G-add-scheduler-based-entropy-source.patch | 914 ---- ...add-SP800-90B-compliant-health-tests.patch | 731 --- ...-add-random.c-entropy-source-support.patch | 207 - ...11-LRNG-0016-LRNG-CPU-entropy-source.patch | 401 -- ...RNG-add-Jitter-RNG-fast-noise-source.patch | 571 --- ...to-enable-runtime-entropy-rate-confi.patch | 60 - ...terface-for-gathering-of-raw-entropy.patch | 1533 ------ ...-add-power-on-and-runtime-self-tests.patch | 523 -- ...0021-LRNG-sysctls-and-proc-interface.patch | 174 - ...add-drop-in-replacement-random-4-API.patch | 938 ---- ...LRNG-add-kernel-crypto-API-interface.patch | 199 - ...RNG-add-dev-lrng-device-file-support.patch | 88 - ...-LRNG-add-hwrand-framework-interface.patch | 125 - ...ter-export-udp_get_timeouts-function.patch | 38 - ...k-events-support-multiple-registrant.patch | 352 -- ...-linux-kernel-to-support-shortcut-fe.patch | 219 - .../net/982-add-bcm-fullcone-support.patch | 235 - ...83-add-bcm-fullcone-nft_masq-support.patch | 114 - openwrt/patch/kernel-6.6/net/README.md | 15 - ...ci-app-frpc-hide-token-openwrt-23.05.patch | 11 - ...tch => 001-luci-app-frpc-hide-token.patch} | 0 ...p-frpc-add-enable-flag-openwrt-24.10.patch | 16 - ...> 002-luci-app-frpc-add-enable-flag.patch} | 0 openwrt/patch/luci/dhcp/README.md | 3 - openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js | 1110 ----- ...and-GCM-with-ARMv8-Crypto-Extensions.patch | 390 -- openwrt/patch/mbedtls-23.05/mbedtls.patch | 34 - ...pd-RFC-9096-compliance-openwrt-23.05.patch | 320 -- ...work-add-option-for-ipv6-max-plt-vlt.patch | 2 +- ..._unsigned_1024-to-btf-encoding-issue.patch | 11 - openwrt/patch/openwrt-6.x/gcc-14/README.md | 1 - .../900-fix-incompatible-pointer-type.patch | 23 - ...-fix-calloc-argument-list-gcc-14-fix.patch | 24 - ...-inclusion-of-Clang-header-by-GCC-14.patch | 36 - .../1000-fix-implicit-declaration-error.patch | 22 - ...00-fix-implicit-function-declaration.patch | 15 - ...pointer-to-integer-of-different-size.patch | 23 - .../900-Fix-transposed-calloc-arguments.patch | 29 - ...evices-add-MediaTek-MT7922-device-id.patch | 25 - .../iwinfo/0004-add-rtl8812au-devices.patch | 86 - openwrt/patch/openwrt-6.x/x86/64/config-6.6 | 663 --- openwrt/patch/openwrt-6.x/x86/config-6.6 | 475 -- .../patches-6.6/100-fix_cs5535_clockevt.patch | 13 - .../103-pcengines_apu6_platform.patch | 275 -- .../6.6/001-Fix-build-for-Linux-6.3-rc1.patch | 84 - .../6.6/002-fix-build-for-linux-6.7-rc1.patch | 33 - .../dmx_usb_module/900-fix-linux-6.6.patch | 13 - .../gpio-button-hotplug/fix-linux-6.12.patch | 6 +- .../gpio-button-hotplug/fix-linux-6.6.patch | 14 - .../fix-build-for-linux-6.6.patch | 13 - openwrt/patch/packages-patches/jool/Makefile | 13 +- .../patch/packages-patches/jool/Makefile.24 | 150 - ...ink-rework-C45-to-work-with-net-next.patch | 88 - ...t-pre-post_doit-CBs-to-new-signature.patch | 56 - .../ovpn-dco/900-fix-linux-6.6.patch | 15 - .../100-fix-build-with-linux-6.12.patch | 50 - .../900-fix-linux-6.6.patch | 16 - openwrt/patch/target-modify_for_armsr.patch | 8 +- .../patch/target-modify_for_rockchip.patch | 8 +- openwrt/patch/target-modify_for_x86_64.patch | 4 +- .../util-linux/201-util-linux_ntfs3.patch | 22 - openwrt/scripts/00-prepare_base.sh | 193 +- openwrt/scripts/01-prepare_base-mainline.sh | 224 +- openwrt/scripts/02-prepare_package.sh | 39 +- openwrt/scripts/04-fix_kmod.sh | 75 +- openwrt/scripts/05-fix-source.sh | 62 +- tags/kernel-6.6 | 2 - tags/kernel-tag.sh | 6 +- tags/openwrt-tag.sh | 2 +- tags/v23 | 1 - tags/v24 | 0 183 files changed, 474 insertions(+), 30153 deletions(-) rename openwrt/{23-config-common => 24-config-common} (99%) rename openwrt/{23-config-minimal-common => 24-config-minimal-common} (98%) rename openwrt/{23-config-musl-armsr-armv8 => 24-config-musl-armsr-armv8} (100%) rename openwrt/{23-config-musl-r4s => 24-config-musl-r4s} (100%) rename openwrt/{23-config-musl-r5s => 24-config-musl-r5s} (100%) rename openwrt/{23-config-musl-r8500 => 24-config-musl-r8500} (99%) rename openwrt/{23-config-musl-r8500-minimal => 24-config-musl-r8500-minimal} (98%) rename openwrt/{23-config-musl-x86 => 24-config-musl-x86} (100%) delete mode 100644 openwrt/generic/config-gcc11 delete mode 100644 openwrt/nginx/nginx-util/0001-nginx-util-fix-compilation-with-GCC13.patch delete mode 100644 openwrt/nginx/nginx-util/0002-nginx-util-move-to-pcre2.patch delete mode 100644 openwrt/nginx/openwrt-23.05-uci.conf.template rename openwrt/nginx/{openwrt-24.10-uci.conf.template => uci.conf.template} (100%) rename openwrt/patch/firewall4/{openwrt-24.10 => luci-24.10}/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch (100%) rename openwrt/patch/firewall4/{openwrt-24.10 => luci-24.10}/0002-luci-app-firewall-add-shortcut-fe-option.patch (100%) rename openwrt/patch/firewall4/{openwrt-24.10 => luci-24.10}/0003-luci-app-firewall-add-ipv6-nat-option.patch (100%) rename openwrt/patch/firewall4/{openwrt-24.10 => luci-24.10}/0004-luci-add-firewall-add-custom-nft-rule-support.patch (100%) rename openwrt/patch/firewall4/{openwrt-24.10 => luci-24.10}/0005-luci-app-firewall-add-natflow-offload-support.patch (100%) rename openwrt/patch/firewall4/{openwrt-24.10 => luci-24.10}/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch (100%) delete mode 100644 openwrt/patch/firewall4/openwrt-23.05/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch delete mode 100644 openwrt/patch/firewall4/openwrt-23.05/0002-luci-app-firewall-add-shortcut-fe-option.patch delete mode 100644 openwrt/patch/firewall4/openwrt-23.05/0003-luci-app-firewall-add-ipv6-nat-option.patch delete mode 100644 openwrt/patch/firewall4/openwrt-23.05/0004-luci-add-firewall-add-custom-nft-rule-support.patch delete mode 100644 openwrt/patch/firewall4/openwrt-23.05/0005-luci-app-firewall-add-natflow-offload-support.patch delete mode 100644 openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch delete mode 100644 openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch delete mode 100644 openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch delete mode 100644 openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch delete mode 100644 openwrt/patch/fstools/Makefile delete mode 100644 openwrt/patch/fstools/glibc/0001-libblkid-tiny-add-support-for-XFS-superblock.patch delete mode 100644 openwrt/patch/fstools/glibc/0003-block-add-xfsck-support.patch rename openwrt/patch/generic-24.10/{0007-kernel-Add-support-for-llvm-clang-compiler.patch => 0006-kernel-Add-support-for-llvm-clang-compiler.patch} (94%) delete mode 100644 openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch rename openwrt/patch/generic-24.10/{0009-build-kernel-add-out-of-tree-kernel-config.patch => 0007-build-kernel-add-out-of-tree-kernel-config.patch} (96%) rename openwrt/patch/generic-24.10/{0010-include-kernel-add-miss-config-for-linux-6.11.patch => 0008-include-kernel-add-miss-config-for-linux-6.11.patch} (78%) delete mode 100644 openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch rename openwrt/patch/generic-24.10/{0011-meson-add-platform-variable-to-cross-compilation-fil.patch => 0009-meson-add-platform-variable-to-cross-compilation-fil.patch} (89%) rename openwrt/patch/generic-24.10/{0012-kernel-add-legacy-cgroup-v1-memory-controller.patch => 0010-kernel-add-legacy-cgroup-v1-memory-controller.patch} (86%) rename openwrt/patch/generic-24.10/{0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch => 0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch} (87%) delete mode 100644 openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch create mode 100644 openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch delete mode 100644 openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch delete mode 100644 openwrt/patch/generic/0002-tools-add-upx-tools.patch delete mode 100644 openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch delete mode 100644 openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch delete mode 100644 openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch delete mode 100644 openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch delete mode 100644 openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch delete mode 100644 openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch delete mode 100644 openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch delete mode 100644 openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch delete mode 100644 openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch delete mode 100644 openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch delete mode 100644 openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch delete mode 100644 openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch delete mode 100644 openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch delete mode 100644 openwrt/patch/generic/gcc-14/910-mbsd_multi.patch delete mode 100644 openwrt/patch/generic/gcc-15/970-macos_arm64-building-fix.patch delete mode 100644 openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch delete mode 100644 openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch delete mode 100644 openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch delete mode 100644 openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch delete mode 100644 openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch delete mode 100644 openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch delete mode 100644 openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch delete mode 100644 openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch delete mode 100644 openwrt/patch/kernel-6.6/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch delete mode 100644 openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch delete mode 100644 openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch delete mode 100644 openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch delete mode 100644 openwrt/patch/kernel-6.6/backport/904-v6.8-tcp-reorganize-tcp_sock-fast-path-variables.patch delete mode 100644 openwrt/patch/kernel-6.6/backport/905-v6.8-tcp-move-tp-scaling_ratio-to-tcp_sock_read_txrx-grou.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch delete mode 100644 openwrt/patch/kernel-6.6/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch delete mode 100644 openwrt/patch/kernel-6.6/btf/990-btf-silence-btf-module-warning-messages.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0003-LRNG-proc-interface.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch delete mode 100644 openwrt/patch/kernel-6.6/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch delete mode 100644 openwrt/patch/kernel-6.6/net/601-netfilter-export-udp_get_timeouts-function.patch delete mode 100644 openwrt/patch/kernel-6.6/net/952-net-conntrack-events-support-multiple-registrant.patch delete mode 100644 openwrt/patch/kernel-6.6/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch delete mode 100644 openwrt/patch/kernel-6.6/net/982-add-bcm-fullcone-support.patch delete mode 100644 openwrt/patch/kernel-6.6/net/983-add-bcm-fullcone-nft_masq-support.patch delete mode 100644 openwrt/patch/kernel-6.6/net/README.md delete mode 100644 openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-23.05.patch rename openwrt/patch/luci/applications/luci-app-frpc/{001-luci-app-frpc-hide-token-openwrt-24.10.patch => 001-luci-app-frpc-hide-token.patch} (100%) delete mode 100644 openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch rename openwrt/patch/luci/applications/luci-app-frpc/{002-luci-app-frpc-add-enable-flag-openwrt-23.05.patch => 002-luci-app-frpc-add-enable-flag.patch} (100%) delete mode 100644 openwrt/patch/luci/dhcp/README.md delete mode 100644 openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js delete mode 100644 openwrt/patch/mbedtls-23.05/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch delete mode 100644 openwrt/patch/mbedtls-23.05/mbedtls.patch delete mode 100644 openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-23.05.patch delete mode 100644 openwrt/patch/openwrt-6.x/dwarves/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/README.md delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/grub2/900-fix-incompatible-pointer-type.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/openvswitch/0008-ovs-atomic-Fix-inclusion-of-Clang-header-by-GCC-14.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/perl/1000-fix-implicit-declaration-error.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/screen/900-fix-implicit-function-declaration.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/wsdd2/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-14/xdp-tools/900-Fix-transposed-calloc-arguments.patch delete mode 100644 openwrt/patch/openwrt-6.x/iwinfo/0001-devices-add-MediaTek-MT7922-device-id.patch delete mode 100644 openwrt/patch/openwrt-6.x/iwinfo/0004-add-rtl8812au-devices.patch delete mode 100644 openwrt/patch/openwrt-6.x/x86/64/config-6.6 delete mode 100644 openwrt/patch/openwrt-6.x/x86/config-6.6 delete mode 100644 openwrt/patch/openwrt-6.x/x86/patches-6.6/100-fix_cs5535_clockevt.patch delete mode 100644 openwrt/patch/openwrt-6.x/x86/patches-6.6/103-pcengines_apu6_platform.patch delete mode 100644 openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch delete mode 100644 openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch delete mode 100644 openwrt/patch/packages-patches/dmx_usb_module/900-fix-linux-6.6.patch delete mode 100644 openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch delete mode 100644 openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch delete mode 100644 openwrt/patch/packages-patches/jool/Makefile.24 delete mode 100644 openwrt/patch/packages-patches/mdio-netlink/001-mdio-netlink-rework-C45-to-work-with-net-next.patch delete mode 100644 openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch delete mode 100644 openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch delete mode 100644 openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch delete mode 100644 openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch delete mode 100644 openwrt/patch/util-linux/201-util-linux_ntfs3.patch delete mode 100644 tags/kernel-6.6 delete mode 100644 tags/v23 create mode 100644 tags/v24 diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 5326e7394..ab31cba49 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,10 +17,10 @@ on: version: description: 'Select the build version' required: true - default: 'release' + default: 'snapshot' type: choice options: - - 'release' + # - 'release' - 'snapshot' build_options: description: 'Build options (separate multiple options with spaces)' diff --git a/openwrt/23-config-common b/openwrt/24-config-common similarity index 99% rename from openwrt/23-config-common rename to openwrt/24-config-common index 8252b097d..a4e1711c4 100644 --- a/openwrt/23-config-common +++ b/openwrt/24-config-common @@ -78,9 +78,6 @@ CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_JSMIN is not set ### Nginx -# openwrt-23.05 -CONFIG_PACKAGE_nginx-all-module=y -# openwrt-24.10 CONFIG_PACKAGE_nginx-ssl=y CONFIG_PACKAGE_nginx-mod-brotli=y CONFIG_PACKAGE_nginx-mod-luci=y diff --git a/openwrt/23-config-minimal-common b/openwrt/24-config-minimal-common similarity index 98% rename from openwrt/23-config-minimal-common rename to openwrt/24-config-minimal-common index 26d23e7d9..20c1e3223 100644 --- a/openwrt/23-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -63,9 +63,6 @@ CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_JSMIN is not set ### Nginx -# openwrt-23.05 -CONFIG_PACKAGE_nginx-all-module=y -# openwrt-24.10 CONFIG_PACKAGE_nginx-ssl=y CONFIG_PACKAGE_nginx-mod-brotli=y CONFIG_PACKAGE_nginx-mod-luci=y diff --git a/openwrt/23-config-musl-armsr-armv8 b/openwrt/24-config-musl-armsr-armv8 similarity index 100% rename from openwrt/23-config-musl-armsr-armv8 rename to openwrt/24-config-musl-armsr-armv8 diff --git a/openwrt/23-config-musl-r4s b/openwrt/24-config-musl-r4s similarity index 100% rename from openwrt/23-config-musl-r4s rename to openwrt/24-config-musl-r4s diff --git a/openwrt/23-config-musl-r5s b/openwrt/24-config-musl-r5s similarity index 100% rename from openwrt/23-config-musl-r5s rename to openwrt/24-config-musl-r5s diff --git a/openwrt/23-config-musl-r8500 b/openwrt/24-config-musl-r8500 similarity index 99% rename from openwrt/23-config-musl-r8500 rename to openwrt/24-config-musl-r8500 index aca69530a..ad939bf69 100644 --- a/openwrt/23-config-musl-r8500 +++ b/openwrt/24-config-musl-r8500 @@ -79,9 +79,6 @@ CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_JSMIN is not set ### Nginx -# openwrt-23.05 -CONFIG_PACKAGE_nginx-all-module=y -# openwrt-24.10 CONFIG_PACKAGE_nginx-ssl=y CONFIG_PACKAGE_nginx-mod-brotli=y CONFIG_PACKAGE_nginx-mod-luci=y diff --git a/openwrt/23-config-musl-r8500-minimal b/openwrt/24-config-musl-r8500-minimal similarity index 98% rename from openwrt/23-config-musl-r8500-minimal rename to openwrt/24-config-musl-r8500-minimal index daa08c429..f6397bda1 100644 --- a/openwrt/23-config-musl-r8500-minimal +++ b/openwrt/24-config-musl-r8500-minimal @@ -76,9 +76,6 @@ CONFIG_PACKAGE_luci-nginx=y CONFIG_LUCI_LANG_zh_Hans=y ### Nginx -# openwrt-23.05 -CONFIG_PACKAGE_nginx-all-module=y -# openwrt-24.10 CONFIG_PACKAGE_nginx-ssl=y CONFIG_PACKAGE_nginx-mod-brotli=y CONFIG_PACKAGE_nginx-mod-luci=y diff --git a/openwrt/23-config-musl-x86 b/openwrt/24-config-musl-x86 similarity index 100% rename from openwrt/23-config-musl-x86 rename to openwrt/24-config-musl-x86 diff --git a/openwrt/build.sh b/openwrt/build.sh index f5e6f1eb5..31b048393 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -84,16 +84,16 @@ if [ -z "$1" ] || [ "$2" != "nanopi-r4s" -a "$2" != "nanopi-r5s" -a "$2" != "x86 exit 1 fi +[ "$1" = "rc2" ] && echo -e "\n${RED_COLOR}openwrt-24.10 release build is not available yet.${RES}\n" && exit 0 + # Source branch if [ "$1" = "dev" ]; then export branch=openwrt-24.10 - export version=snapshots-24.10 - export openwrt_version=openwrt-24.10 + export version=dev elif [ "$1" = "rc2" ]; then - latest_release="v$(curl -s https://$mirror/tags/v23)" + latest_release="v$(curl -s https://$mirror/tags/v24)" export branch=$latest_release export version=rc2 - export openwrt_version=openwrt-23.05 fi # lan @@ -106,22 +106,17 @@ fi [ "$2" = "netgear_r8500" ] && export platform="bcm53xx" toolchain_arch="arm_cortex-a9" [ "$2" = "x86_64" ] && export platform="x86_64" toolchain_arch="x86_64" -# gcc13 & 14 & 15 +# gcc14 & 15 if [ "$USE_GCC13" = y ]; then - export USE_GCC13=y gcc_version=13 - # use mold - [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y + export USE_GCC14=y gcc_version=13 elif [ "$USE_GCC14" = y ]; then export USE_GCC14=y gcc_version=14 - # use mold - [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y elif [ "$USE_GCC15" = y ]; then export USE_GCC15=y gcc_version=15 - # use mold - [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y else - export gcc_version=11 + export gcc_version=13 fi +[ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y # build.sh flags export \ @@ -131,9 +126,6 @@ export \ ENABLE_LRNG=$ENABLE_LRNG \ KERNEL_CLANG_LTO=$KERNEL_CLANG_LTO -# kernel version -[ "$version" = "snapshots-24.10" ] && export kernel_version=6.12 || export kernel_version=6.6 - # print version echo -e "\r\n${GREEN_COLOR}Building $branch${RES}\r\n" if [ "$platform" = "x86_64" ]; then @@ -151,13 +143,9 @@ else echo -e "${GREEN_COLOR}Model: nanopi-r4s${RES}" [ "$1" = "rc2" ] && model="nanopi-r4s" fi -get_kernel_version=$(curl -s https://$mirror/tags/kernel-$kernel_version) +get_kernel_version=$(curl -s https://$mirror/tags/kernel-6.12) kmod_hash=$(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}' | tail -1 | md5sum | awk '{print $1}') -if [ "$version" = "snapshots-24.10" ]; then - kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) -else - kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')-1-$(echo $kmod_hash)) -fi +kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" echo -e "${GREEN_COLOR}Date: $CURRENT_DATE${RES}\r\n" @@ -182,17 +170,6 @@ rm -rf openwrt master [ "$(whoami)" = "runner" ] && group "source code" git clone --depth=1 https://$github/openwrt/openwrt -b $branch -# openwrt master -if [ "$1" = "rc2" ]; then - git clone https://$github/openwrt/openwrt master/openwrt --depth=1 - git clone https://$github/openwrt/packages master/packages --depth=1 - git clone https://$github/openwrt/luci master/luci --depth=1 - git clone https://$github/openwrt/routing master/routing --depth=1 -fi - -# openwrt-23.05 -[ "$1" = "rc2" ] && git clone https://$github/openwrt/openwrt -b openwrt-23.05 master/openwrt-23.05 --depth=1 - # immortalwrt master git clone https://$github/immortalwrt/packages master/immortalwrt_packages --depth=1 [ "$(whoami)" = "runner" ] && endgroup @@ -273,37 +250,33 @@ bash 05-fix-source.sh [ -f "10-custom.sh" ] && bash 10-custom.sh [ "$(whoami)" = "runner" ] && endgroup -if [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ] && [ "$version" = "rc2" ]; then - rm -rf toolchain/binutils - cp -a ../master/openwrt/toolchain/binutils toolchain/binutils -fi - rm -f 0*-*.sh 10-custom.sh rm -rf ../master # Load devices Config if [ "$platform" = "x86_64" ]; then - curl -s https://$mirror/openwrt/23-config-musl-x86 > .config + curl -s https://$mirror/openwrt/24-config-musl-x86 > .config elif [ "$platform" = "bcm53xx" ]; then if [ "$MINIMAL_BUILD" = "y" ]; then - curl -s https://$mirror/openwrt/23-config-musl-r8500-minimal > .config + curl -s https://$mirror/openwrt/24-config-musl-r8500-minimal > .config else - curl -s https://$mirror/openwrt/23-config-musl-r8500 > .config + curl -s https://$mirror/openwrt/24-config-musl-r8500 > .config fi + sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config elif [ "$platform" = "rk3568" ]; then - curl -s https://$mirror/openwrt/23-config-musl-r5s > .config + curl -s https://$mirror/openwrt/24-config-musl-r5s > .config elif [ "$platform" = "armv8" ]; then - curl -s https://$mirror/openwrt/23-config-musl-armsr-armv8 > .config + curl -s https://$mirror/openwrt/24-config-musl-armsr-armv8 > .config else - curl -s https://$mirror/openwrt/23-config-musl-r4s > .config + curl -s https://$mirror/openwrt/24-config-musl-r4s > .config fi # config-common if [ "$MINIMAL_BUILD" = "y" ]; then - [ "$platform" != "bcm53xx" ] && curl -s https://$mirror/openwrt/23-config-minimal-common >> .config + [ "$platform" != "bcm53xx" ] && curl -s https://$mirror/openwrt/24-config-minimal-common >> .config echo 'VERSION_TYPE="minimal"' >> package/base-files/files/usr/lib/os-release else - [ "$platform" != "bcm53xx" ] && curl -s https://$mirror/openwrt/23-config-common >> .config + [ "$platform" != "bcm53xx" ] && curl -s https://$mirror/openwrt/24-config-common >> .config [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi @@ -357,24 +330,10 @@ if [ "$ENABLE_LOCAL_KMOD" = "y" ]; then echo "CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES=y" >> .config fi -# openwrt-23.05 gcc11/13/14/15 -[ "$(whoami)" = "runner" ] && group "patching toolchain" -if [ "$1" = "rc2" ]; then - if [ "$USE_GCC13" = "y" ] || [ "$USE_GCC14" = "y" ] || [ "$USE_GCC15" = "y" ]; then - curl -s https://$mirror/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 - # gcc14/15 init - cp -a toolchain/gcc/patches-13.x toolchain/gcc/patches-14.x - curl -s https://$mirror/openwrt/patch/generic/gcc-14/910-mbsd_multi.patch > toolchain/gcc/patches-14.x/910-mbsd_multi.patch - cp -a toolchain/gcc/patches-14.x toolchain/gcc/patches-15.x - curl -s https://$mirror/openwrt/patch/generic/gcc-15/970-macos_arm64-building-fix.patch > toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch - elif [ ! "$ENABLE_GLIBC" = "y" ]; then - curl -s https://$mirror/openwrt/generic/config-gcc11 >> .config - fi -else - curl -s https://$mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 -fi +# gcc15 patches +curl -s https://$mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 + +# gcc config [ "$USE_GCC13" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc13 >> .config [ "$USE_GCC14" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc14 >> .config [ "$USE_GCC15" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc15 >> .config @@ -383,11 +342,6 @@ fi # uhttpd [ "$ENABLE_UHTTPD" = "y" ] && sed -i '/nginx/d' .config && echo 'CONFIG_PACKAGE_ariang=y' >> .config -# snapshots-24.10 -[ "$version" = "snapshots-24.10" ] && [ "$platform" = "bcm53xx" ] && sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config -[ "$version" = "snapshots-24.10" ] && sed -i '1i\# Test kernel\nCONFIG_TESTING_KERNEL=y\n' .config -[ "$version" = "rc2" ] && sed -i '/CONFIG_TESTING_KERNEL/d' .config - # not all kmod [ "$NO_KMOD" = "y" ] && sed -i '/CONFIG_ALL_KMODS=y/d; /CONFIG_ALL_NONSHARED=y/d' .config @@ -473,7 +427,7 @@ if [ "$platform" = "x86_64" ]; then if [ "$1" = "rc2" ]; then mkdir -p ota if [ "$MINIMAL_BUILD" = "y" ]; then - OTA_URL="https://x86.cooluc.com/d/minimal/openwrt-23.05" + OTA_URL="https://x86.cooluc.com/d/minimal/openwrt-24.10" else OTA_URL="https://github.com/sbwml/builder/releases/download" fi @@ -541,7 +495,7 @@ elif [ "$platform" = "bcm53xx" ]; then if [ "$1" = "rc2" ]; then mkdir -p ota if [ "$MINIMAL_BUILD" = "y" ]; then - OTA_URL="https://r8500.cooluc.com/d/minimal/openwrt-23.05" + OTA_URL="https://r8500.cooluc.com/d/minimal/openwrt-24.10" else OTA_URL="https://github.com/sbwml/builder/releases/download" fi @@ -577,7 +531,7 @@ else OTA_URL="https://github.com/sbwml/builder/releases/download" VERSION=$(sed 's/v//g' version.txt) if [ "$model" = "nanopi-r4s" ]; then - [ "$MINIMAL_BUILD" = "y" ] && OTA_URL="https://r4s.cooluc.com/d/minimal/openwrt-23.05" + [ "$MINIMAL_BUILD" = "y" ] && OTA_URL="https://r4s.cooluc.com/d/minimal/openwrt-24.10" SHA256=$(sha256sum bin/targets/rockchip/armv8*/*-squashfs-sysupgrade.img.gz | awk '{print $1}') cat > ota/fw.json < ota/fw.json < -Date: Sat, 1 Jul 2023 16:44:54 -0700 -Subject: [PATCH 1/2] nginx-util: fix compilation with GCC13 - -Signed-off-by: Rosen Penev ---- - net/nginx-util/Makefile | 2 +- - net/nginx-util/src/ubus-cxx.hpp | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/net/nginx-util/Makefile b/net/nginx-util/Makefile -index 5d7070eb9..4a77e2f20 100644 ---- a/net/nginx-util/Makefile -+++ b/net/nginx-util/Makefile -@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk - - PKG_NAME:=nginx-util - PKG_VERSION:=1.6 --PKG_RELEASE:=18 -+PKG_RELEASE:=19 - PKG_MAINTAINER:=Peter Stadler - - include $(INCLUDE_DIR)/package.mk -diff --git a/net/nginx-util/src/ubus-cxx.hpp b/net/nginx-util/src/ubus-cxx.hpp -index 6c193cfc3..42d2d21aa 100644 ---- a/net/nginx-util/src/ubus-cxx.hpp -+++ b/net/nginx-util/src/ubus-cxx.hpp -@@ -159,7 +159,7 @@ class message { - both = keys; - } - both = concat(std::move(both), std::move(key_filter)...); -- return std::move(message{msg, std::move(both)}); -+ return message{msg, std::move(both)}; - } - - inline ~message() = default; --- -2.39.3 - diff --git a/openwrt/nginx/nginx-util/0002-nginx-util-move-to-pcre2.patch b/openwrt/nginx/nginx-util/0002-nginx-util-move-to-pcre2.patch deleted file mode 100644 index e3fb152b8..000000000 --- a/openwrt/nginx/nginx-util/0002-nginx-util-move-to-pcre2.patch +++ /dev/null @@ -1,166 +0,0 @@ -From e517ab7c73c93af83b62a317b943218908e04405 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Fri, 22 Sep 2023 18:15:01 +0200 -Subject: [PATCH 2/2] nginx-util: move to pcre2 - -Convert to pcre2 library as pcre is EOL. No functional change intended. - -Signed-off-by: Christian Marangi ---- - net/nginx-util/Makefile | 4 +-- - net/nginx-util/src/CMakeLists.txt | 4 +-- - net/nginx-util/src/regex-pcre.hpp | 42 ++++++++++++++++++++++--------- - 3 files changed, 34 insertions(+), 16 deletions(-) - -diff --git a/net/nginx-util/Makefile b/net/nginx-util/Makefile -index 4a77e2f20..b4f06aaae 100644 ---- a/net/nginx-util/Makefile -+++ b/net/nginx-util/Makefile -@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk - - PKG_NAME:=nginx-util - PKG_VERSION:=1.6 --PKG_RELEASE:=19 -+PKG_RELEASE:=20 - PKG_MAINTAINER:=Peter Stadler - - include $(INCLUDE_DIR)/package.mk -@@ -30,7 +30,7 @@ endef - define Package/nginx-ssl-util - $(Package/nginx-ssl-util/default) - TITLE+= (using PCRE) -- DEPENDS+= +libpcre -+ DEPENDS+= +libpcre2 - CONFLICTS:=nginx-ssl-util-nopcre, - endef - -diff --git a/net/nginx-util/src/CMakeLists.txt b/net/nginx-util/src/CMakeLists.txt -index 2adff1c71..e023f1eb6 100644 ---- a/net/nginx-util/src/CMakeLists.txt -+++ b/net/nginx-util/src/CMakeLists.txt -@@ -27,7 +27,7 @@ FIND_LIBRARY(ubus NAMES ubus) - INCLUDE_DIRECTORIES(${ubus_include_dir}) - - ADD_EXECUTABLE(nginx-ssl-util nginx-util.cpp) --TARGET_LINK_LIBRARIES(nginx-ssl-util ${uci} ${ubox} ${ubus} pthread ssl crypto pcre) -+TARGET_LINK_LIBRARIES(nginx-ssl-util ${uci} ${ubox} ${ubus} pthread ssl crypto pcre2-8) - INSTALL(TARGETS nginx-ssl-util RUNTIME DESTINATION bin) - - ADD_EXECUTABLE(nginx-ssl-util-nopcre nginx-util.cpp) -@@ -51,7 +51,7 @@ INSTALL(TARGETS px5g RUNTIME DESTINATION bin) - - ADD_EXECUTABLE(nginx-ssl-util-noubus nginx-util.cpp) - TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-noubus PUBLIC -DNO_UBUS) --TARGET_LINK_LIBRARIES(nginx-ssl-util-noubus ${uci} ${ubox} pthread ssl crypto pcre) -+TARGET_LINK_LIBRARIES(nginx-ssl-util-noubus ${uci} ${ubox} pthread ssl crypto pcre2-8) - INSTALL(TARGETS nginx-ssl-util-noubus RUNTIME DESTINATION bin) - - ADD_EXECUTABLE(nginx-ssl-util-nopcre-noubus nginx-util.cpp) -diff --git a/net/nginx-util/src/regex-pcre.hpp b/net/nginx-util/src/regex-pcre.hpp -index f63d5f90c..ab255542b 100644 ---- a/net/nginx-util/src/regex-pcre.hpp -+++ b/net/nginx-util/src/regex-pcre.hpp -@@ -1,7 +1,9 @@ - #ifndef __REGEXP_PCRE_HPP - #define __REGEXP_PCRE_HPP - --#include -+#define PCRE2_CODE_UNIT_WIDTH 8 -+ -+#include - #include - #include - #include -@@ -65,11 +67,9 @@ class regex { - private: - int errcode = 0; - -- const char* errptr = nullptr; -- -- int erroffset = 0; -+ PCRE2_SIZE erroffset = 0; - -- pcre* const re = nullptr; -+ pcre2_code* const re = nullptr; - - static const std::array errcode_pcre2regex; - -@@ -89,10 +89,18 @@ class regex { - explicit regex(const std::string& str) : regex(str.c_str()) {} - - explicit regex(const char* const str) -- : re{pcre_compile2(str, 0, &errcode, &errptr, &erroffset, nullptr)} -+ : re{pcre2_compile((PCRE2_SPTR)str, PCRE2_ZERO_TERMINATED, 0, &errcode, &erroffset, nullptr)} - { - if (re == nullptr) { -- std::string what = std::string("regex error: ") + errptr + '\n'; -+ std::vector buffer(256); -+ int errlen; -+ -+ errlen = pcre2_get_error_message(errcode, buffer.data(), buffer.size()); -+ if (errlen < 0) -+ throw regex_error(errcode_pcre2regex.at(errlen)); -+ -+ std::string what = std::string("regex error: ") + -+ std::string(buffer.data(), buffer.data() + errlen) + '\n'; - what += " '" + std::string{str} + "'\n"; - what += " " + std::string(erroffset, ' ') + '^'; - -@@ -103,11 +111,11 @@ class regex { - ~regex() - { - if (re != nullptr) { -- pcre_free(re); -+ pcre2_code_free(re); - } - } - -- inline auto operator()() const -> const pcre* -+ inline auto operator()() const -> const pcre2_code* - { - return re; - } -@@ -187,11 +195,19 @@ auto regex_search(std::string::const_iterator begin, - - inline auto regex_search(const std::string& subj, const regex& rgx) - { -+ pcre2_match_data *match_data; -+ - if (rgx() == nullptr) { - throw std::runtime_error("regex_search error: no regex given"); - } -+ -+ match_data = pcre2_match_data_create_from_pattern(rgx(), NULL); -+ - int n = -- pcre_exec(rgx(), nullptr, subj.c_str(), static_cast(subj.length()), 0, 0, nullptr, 0); -+ pcre2_match(rgx(), (PCRE2_SPTR)subj.c_str(), static_cast(subj.length()), 0, 0, match_data, nullptr); -+ -+ pcre2_match_data_free(match_data); -+ - return n >= 0; - } - -@@ -205,7 +221,7 @@ auto regex_search(const std::string::const_iterator begin, - } - - int sz = 0; -- pcre_fullinfo(rgx(), nullptr, PCRE_INFO_CAPTURECOUNT, &sz); -+ pcre2_pattern_info(rgx(), PCRE2_INFO_CAPTURECOUNT, &sz); - sz = 3 * (sz + 1); - - match.vec.reserve(sz); -@@ -216,7 +232,9 @@ auto regex_search(const std::string::const_iterator begin, - match.begin = begin; - match.end = end; - -- match.n = pcre_exec(rgx(), nullptr, subj, len, 0, 0, &match.vec[0], sz); -+ pcre2_match_data *match_data = pcre2_match_data_create(sz, NULL); -+ match.n = pcre2_match(rgx(), (PCRE2_SPTR)subj, len, 0, 0, match_data, NULL); -+ pcre2_match_data_free(match_data); - - if (match.n < 0) { - return false; --- -2.39.3 - diff --git a/openwrt/nginx/openwrt-23.05-uci.conf.template b/openwrt/nginx/openwrt-23.05-uci.conf.template deleted file mode 100644 index 7888c3dea..000000000 --- a/openwrt/nginx/openwrt-23.05-uci.conf.template +++ /dev/null @@ -1,54 +0,0 @@ -# Consider using UCI or creating files in /etc/nginx/conf.d/ for configuration. -# Parsing UCI configuration is skipped if uci set nginx.global.uci_enable=false -# For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx - -worker_processes 2; - -user root; - -events { - worker_connections 1024; -} - -http { - access_log off; - server_names_hash_bucket_size 128; - server_tokens build; - keepalive_timeout 300s; - log_format openwrt - '$request_method $scheme://$host$request_uri => $status' - ' (${body_bytes_sent}B in ${request_time}s) <- $http_referer'; - - include mime.types; - default_type application/octet-stream; - sendfile on; - - client_max_body_size 8192M; - large_client_header_buffers 4 32k; - - gzip on; - gzip_vary on; - gzip_proxied any; - brotli on; - brotli_comp_level 6; - brotli_static on; - brotli_types application/atom+xml application/javascript application/json application/rss+xml - application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype - application/x-font-ttf application/x-javascript application/xhtml+xml application/xml - font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon - image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; - zstd on; - zstd_comp_level 7; - zstd_min_length 1k; - zstd_static on; - zstd_types application/atom+xml application/javascript application/json application/rss+xml - application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype - application/x-font-ttf application/x-javascript application/xhtml+xml application/xml - font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon - image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; - - root /www; - - #UCI_HTTP_CONFIG - include conf.d/*.conf; -} diff --git a/openwrt/nginx/openwrt-24.10-uci.conf.template b/openwrt/nginx/uci.conf.template similarity index 100% rename from openwrt/nginx/openwrt-24.10-uci.conf.template rename to openwrt/nginx/uci.conf.template diff --git a/openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch similarity index 100% rename from openwrt/patch/firewall4/openwrt-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch rename to openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch diff --git a/openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch similarity index 100% rename from openwrt/patch/firewall4/openwrt-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch rename to openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch diff --git a/openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch similarity index 100% rename from openwrt/patch/firewall4/openwrt-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch rename to openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch diff --git a/openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch similarity index 100% rename from openwrt/patch/firewall4/openwrt-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch rename to openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch diff --git a/openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch similarity index 100% rename from openwrt/patch/firewall4/openwrt-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch rename to openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch diff --git a/openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch b/openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch similarity index 100% rename from openwrt/patch/firewall4/openwrt-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch rename to openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch diff --git a/openwrt/patch/firewall4/openwrt-23.05/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/openwrt-23.05/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch deleted file mode 100644 index 1bfa53370..000000000 --- a/openwrt/patch/firewall4/openwrt-23.05/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 9bb3e0985634cd5bf7551d5f21a0ebc081af2599 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 4 Sep 2024 12:22:05 +0800 -Subject: [PATCH 1/4] luci-app-firewall: add nft-fullcone and bcm-fullcone - option - -Signed-off-by: sbwml ---- - .../htdocs/luci-static/resources/view/firewall/zones.js | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 1de98c2045..ac720831ef 100644 ---- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -+++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -58,6 +58,15 @@ return view.extend({ - - o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets')); - -+ if (L.hasSystemFeature('fullcone')) { -+ o = s.option(form.Flag, 'fullcone', _('Enable FullCone NAT')); -+ -+ o = s.option(form.Flag, 'brcmfullcone', _('BCM FullCone NAT scheme'), -+ _('Use the Broadcom FullCone NAT scheme if enabled, and use the NFT FullCone scheme if the option is disabled.')); -+ o.modalonly = true; -+ o.depends('fullcone', '1'); -+ }; -+ - var p = [ - s.option(form.ListValue, 'input', _('Input')), - s.option(form.ListValue, 'output', _('Output')), --- -2.43.5 - diff --git a/openwrt/patch/firewall4/openwrt-23.05/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/openwrt-23.05/0002-luci-app-firewall-add-shortcut-fe-option.patch deleted file mode 100644 index 91e49bcbc..000000000 --- a/openwrt/patch/firewall4/openwrt-23.05/0002-luci-app-firewall-add-shortcut-fe-option.patch +++ /dev/null @@ -1,65 +0,0 @@ -From e62768ea9de7fcf554bce7ba8ed2e1f301863006 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 4 Sep 2024 12:34:17 +0800 -Subject: [PATCH 2/4] luci-app-firewall: add shortcut-fe option - -Signed-off-by: sbwml ---- - .../resources/view/firewall/zones.js | 34 +++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index ac720831ef..f7c64e4379 100644 ---- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -+++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -100,6 +100,21 @@ return view.extend({ - o.depends('flow_offloading', '1'); - } - -+ /* Shortcut-FE flow offload support */ -+ if (L.hasSystemFeature('shortcutfe')) { -+ o = s.option(form.Flag, 'shortcut_fe', -+ _('Shortcut-FE flow offloading'), -+ _('Shortcut-FE based offloading for routing/NAT')); -+ o.optional = true; -+ -+ o = s.option(form.ListValue, 'shortcut_fe_module', -+ _('Connection Manager'), -+ _('Set up the Shortcut-FE engine connection manager')); -+ o.value('shortcut-fe-cm', _('shortcut-fe-cm')); -+ o.value('fast-classifier', _('fast-classifier')); -+ o.default = 'shortcut-fe-cm'; -+ o.depends('shortcut_fe', '1'); -+ } - - s = m.section(form.GridSection, 'zone', _('Zones')); - s.addremove = true; -@@ -393,6 +408,25 @@ return view.extend({ - o.filter = out.filter; - o.cfgvalue = out.cfgvalue; - -+ setTimeout(function() { -+ const checkboxes = document.querySelectorAll('.cbi-checkbox input[type="checkbox"]'); -+ checkboxes.forEach((checkbox) => { -+ const widgetId = checkbox.getAttribute('data-widget-id'); -+ if ((widgetId.includes('flow_offloading') && !widgetId.includes('flow_offloading_hw')) || widgetId.includes('shortcut_fe')) { -+ checkbox.addEventListener('change', function() { -+ if (this.checked) { -+ checkboxes.forEach((cb) => { -+ if (cb !== this && (cb.getAttribute('data-widget-id').includes('flow_offloading') || -+ cb.getAttribute('data-widget-id').includes('shortcut_fe'))) { -+ cb.checked = false; -+ } -+ }); -+ } -+ }); -+ } -+ }); -+ }, 500); -+ - return m.render(); - } - }); --- -2.43.5 - diff --git a/openwrt/patch/firewall4/openwrt-23.05/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/openwrt-23.05/0003-luci-app-firewall-add-ipv6-nat-option.patch deleted file mode 100644 index d9263c6e9..000000000 --- a/openwrt/patch/firewall4/openwrt-23.05/0003-luci-app-firewall-add-ipv6-nat-option.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 6379d22fb3c4dba52078dfbf44c0f2b8315c0ccf Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 4 Sep 2024 12:35:13 +0800 -Subject: [PATCH 3/4] luci-app-firewall: add ipv6 nat option - -Signed-off-by: sbwml ---- - .../htdocs/luci-static/resources/view/firewall/zones.js | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index f7c64e4379..1bedd2ce52 100644 ---- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -+++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -67,6 +67,12 @@ return view.extend({ - o.depends('fullcone', '1'); - }; - -+ if (L.hasSystemFeature('ipv6')) { -+ o = s.option(form.Flag, 'nat6', -+ _('IPv6 NAT'), -+ _('Applicable to internet environments where the router is not assigned an IPv6 prefix, such as when using an upstream optical modem for dial-up.')); -+ }; -+ - var p = [ - s.option(form.ListValue, 'input', _('Input')), - s.option(form.ListValue, 'output', _('Output')), --- -2.43.5 - diff --git a/openwrt/patch/firewall4/openwrt-23.05/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/openwrt-23.05/0004-luci-add-firewall-add-custom-nft-rule-support.patch deleted file mode 100644 index b20e70ce0..000000000 --- a/openwrt/patch/firewall4/openwrt-23.05/0004-luci-add-firewall-add-custom-nft-rule-support.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 0a71614b1690e60048b2f5c5ff672a68f5fd7478 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 4 Sep 2024 12:36:11 +0800 -Subject: [PATCH 4/4] luci-add-firewall: add custom nft rule support - -Signed-off-by: sbwml ---- - .../htdocs/luci-static/resources/view/firewall/custom.js | 6 +++--- - .../root/usr/share/luci/menu.d/luci-app-firewall.json | 3 --- - .../root/usr/share/rpcd/acl.d/luci-app-firewall.json | 6 ++++-- - 3 files changed, 7 insertions(+), 8 deletions(-) - -diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js -index 1997a720c6..b3183d67d6 100644 ---- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js -+++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js -@@ -5,13 +5,13 @@ - - return view.extend({ - load: function() { -- return L.resolveDefault(fs.read('/etc/firewall.user'), ''); -+ return L.resolveDefault(fs.read('/etc/firewall4.user'), ''); - }, - - handleSave: function(ev) { - var value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n'; - -- return fs.write('/etc/firewall.user', value).then(function(rc) { -+ return fs.write('/etc/firewall4.user', value).then(function(rc) { - document.querySelector('textarea').value = value; - ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'); - fs.exec('/etc/init.d/firewall', ['restart']); -@@ -23,7 +23,7 @@ return view.extend({ - render: function(fwuser) { - return E([ - E('h2', _('Firewall - Custom Rules')), -- E('p', {}, _('Custom rules allow you to execute arbitrary iptables commands which are not otherwise covered by the firewall framework. The commands are executed after each firewall restart, right after the default ruleset has been loaded.')), -+ E('p', {}, _('Custom rules allow you to execute arbitrary nft commands which are not otherwise covered by the firewall framework. The rules are executed after each firewall restart, right after the default ruleset has been loaded.')), - E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 25 }, [ fwuser != null ? fwuser : '' ])) - ]); - }, -diff --git a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json -index f024dcfe25..8aea702c53 100644 ---- a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json -+++ b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json -@@ -64,9 +64,6 @@ - "action": { - "type": "view", - "path": "firewall/custom" -- }, -- "depends": { -- "fs": { "/usr/share/fw3/helpers.conf": "file" } - } - } - } -diff --git a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json -index 17d1fbab12..7e06de7022 100644 ---- a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json -+++ b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json -@@ -3,7 +3,8 @@ - "description": "Grant access to firewall configuration", - "read": { - "file": { -- "/etc/firewall.user": [ "read" ] -+ "/etc/firewall.user": [ "read" ], -+ "/etc/firewall4.user": [ "read" ] - }, - "ubus": { - "file": [ "read" ], -@@ -13,7 +14,8 @@ - }, - "write": { - "file": { -- "/etc/firewall.user": [ "write" ] -+ "/etc/firewall.user": [ "write" ], -+ "/etc/firewall4.user": [ "write" ] - }, - "ubus": { - "file": [ "write" ] --- -2.43.5 - diff --git a/openwrt/patch/firewall4/openwrt-23.05/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/openwrt-23.05/0005-luci-app-firewall-add-natflow-offload-support.patch deleted file mode 100644 index c1bda2323..000000000 --- a/openwrt/patch/firewall4/openwrt-23.05/0005-luci-app-firewall-add-natflow-offload-support.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 518eadc602c8e61621c8c1091585a134d978d596 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 8 Sep 2024 03:40:30 +0800 -Subject: [PATCH] luci-app-firewall: add natflow offload support - -Signed-off-by: sbwml ---- - .../resources/view/firewall/zones.js | 20 +++++++++++++++++-- - 1 file changed, 18 insertions(+), 2 deletions(-) - -diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 1bedd2c..522d001 100644 ---- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -+++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -122,6 +122,21 @@ return view.extend({ - o.depends('shortcut_fe', '1'); - } - -+ /* Natflow offload support */ -+ if (L.hasSystemFeature('natflow')) { -+ o = s.option(form.Flag, 'natflow', -+ _('Natflow offloading'), -+ _('Natflow based offloading for routing/NAT')); -+ o.optional = true; -+ -+ o = s.option(form.Value, 'natflow_delay_pkts', -+ _('Natflow delay packet'), -+ _('Set up the natflow delay packet')); -+ o.datatype = 'and(uinteger,min(0))'; -+ o.default = 0; -+ o.depends('natflow', '1'); -+ } -+ - s = m.section(form.GridSection, 'zone', _('Zones')); - s.addremove = true; - s.anonymous = true; -@@ -418,12 +433,13 @@ return view.extend({ - const checkboxes = document.querySelectorAll('.cbi-checkbox input[type="checkbox"]'); - checkboxes.forEach((checkbox) => { - const widgetId = checkbox.getAttribute('data-widget-id'); -- if ((widgetId.includes('flow_offloading') && !widgetId.includes('flow_offloading_hw')) || widgetId.includes('shortcut_fe')) { -+ if ((widgetId.includes('flow_offloading') && !widgetId.includes('flow_offloading_hw')) || widgetId.includes('shortcut_fe') || widgetId.includes('natflow')) { - checkbox.addEventListener('change', function() { - if (this.checked) { - checkboxes.forEach((cb) => { - if (cb !== this && (cb.getAttribute('data-widget-id').includes('flow_offloading') || -- cb.getAttribute('data-widget-id').includes('shortcut_fe'))) { -+ cb.getAttribute('data-widget-id').includes('shortcut_fe') || -+ cb.getAttribute('data-widget-id').includes('natflow'))) { - cb.checked = false; - } - }); --- -2.42.0 - diff --git a/openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch b/openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch deleted file mode 100644 index 94cad6031..000000000 --- a/openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch +++ /dev/null @@ -1,47 +0,0 @@ -diff --git a/block.c b/block.c -index f094216..ec05fb6 100644 ---- a/block.c -+++ b/block.c -@@ -721,7 +721,7 @@ static void check_filesystem(struct probe_info *pr) - ckfs = e2fsck; - } else if (!strncmp(pr->type, "btrfs", 5)) { - ckfs = btrfsck; -- } else if (!strncmp(pr->type, "ntfs", 4)) { -+ } else if (!strncmp(pr->type, "ntfs3", 4)) { - ckfs = ntfsck; - } else { - ULOG_ERR("check_filesystem: %s is not supported\n", pr->type); -@@ -741,7 +741,7 @@ static void check_filesystem(struct probe_info *pr) - } else if(!strncmp(pr->type, "btrfs", 5)) { - execl(ckfs, ckfs, "--repair", pr->dev, NULL); - exit(EXIT_FAILURE); -- } else if(!strncmp(pr->type, "ntfs", 4)) { -+ } else if(!strncmp(pr->type, "ntfs3", 4)) { - execl(ckfs, ckfs, "-b", pr->dev, NULL); - exit(EXIT_FAILURE); - } else { -@@ -1462,9 +1462,9 @@ static int mount_extroot(char *cfg) - if (strncmp(pr->type, "ext", 3) && - strncmp(pr->type, "f2fs", 4) && - strncmp(pr->type, "btrfs", 5) && -- strncmp(pr->type, "ntfs", 4) && -+ strncmp(pr->type, "ntfs3", 4) && - strncmp(pr->type, "ubifs", 5)) { -- ULOG_ERR("extroot: unsupported filesystem %s, try ext4, f2fs, btrfs, ntfs or ubifs\n", pr->type); -+ ULOG_ERR("extroot: unsupported filesystem %s, try ext4, f2fs, btrfs, ntfs3 or ubifs\n", pr->type); - return -1; - } - -diff --git a/libblkid-tiny/ntfs.c b/libblkid-tiny/ntfs.c -index 2426e70..bba6271 100644 ---- a/libblkid-tiny/ntfs.c -+++ b/libblkid-tiny/ntfs.c -@@ -214,7 +214,7 @@ static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag) - - const struct blkid_idinfo ntfs_idinfo = - { -- .name = "ntfs", -+ .name = "ntfs3", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ntfs, - .magics = diff --git a/openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch b/openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch deleted file mode 100644 index 43ab03340..000000000 --- a/openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/block.c b/block.c -index 3842ca7..2176f72 100644 ---- a/block.c -+++ b/block.c -@@ -945,8 +945,12 @@ static int handle_mount(const char *source, const char *target, - int err = -EINVAL; - size_t count; - int i; -+ char _data[128] = {0}; -+ if (strstr(fstype, "fat") || strstr(fstype, "ntfs3")) { -+ snprintf(_data, sizeof(_data), "%s", "iocharset=utf8,uid=65534,gid=65534"); -+ } - -- if (!strcmp(fstype, "ntfs")) { -+ if (!strcmp(fstype, "ntfs3")) { - filesystems = ntfs_fs; - count = ARRAY_SIZE(ntfs_fs); - } else { -@@ -958,7 +962,7 @@ static int handle_mount(const char *source, const char *target, - const char *fs = filesystems[i]; - - err = mount(source, target, fs, m ? m->flags : 0, -- (m && m->options) ? m->options : ""); -+ (m && m->options) ? m->options : _data); - if (!err || errno != ENODEV) - break; - } diff --git a/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch b/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch deleted file mode 100644 index 4491755d1..000000000 --- a/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch +++ /dev/null @@ -1,141 +0,0 @@ -From: Qi Liu - -In order to support extroot, block extroot command has to be able to -discover and properly mount the rootfs_data volume in order to discover -the extroot volume. Currently this process can only discover MTD devices. -This patch leverages libfstools in a similar way as mount_root to -discover, initialize, and mount rootfs_data volume. It would enable any -device with non-MTD rootfs_data volume to support extroot, including x86. - -Signed-off-by: Qi Liu ---- - CMakeLists.txt | 4 ++-- - block.c | 40 ++++++++++++++++++++++++++++++++++++++++ - libfstools/fstype.h | 13 +++++++++++++ - libfstools/libfstools.h | 12 +----------- - 4 files changed, 56 insertions(+), 13 deletions(-) - create mode 100644 libfstools/fstype.h - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 9a87979..c485913 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -78,9 +78,9 @@ INSTALL(TARGETS blockd RUNTIME DESTINATION sbin) - ADD_EXECUTABLE(block block.c probe.c probe-libblkid.c) - IF(DEFINED CMAKE_UBIFS_EXTROOT) - ADD_DEFINITIONS(-DUBIFS_EXTROOT) -- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json}) -+ TARGET_LINK_LIBRARIES(block fstools blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json}) - ELSE(DEFINED CMAKE_UBIFS_EXTROOT) -- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ${json}) -+ TARGET_LINK_LIBRARIES(block fstools blkid-tiny dl uci ubox ubus blobmsg_json ${json}) - ENDIF(DEFINED CMAKE_UBIFS_EXTROOT) - INSTALL(TARGETS block RUNTIME DESTINATION sbin) - -diff --git a/block.c b/block.c -index 2176f72..454a046 100644 ---- a/block.c -+++ b/block.c -@@ -44,6 +44,8 @@ - #include - #include - -+#include "libfstools/fstype.h" -+#include "libfstools/volume.h" - #include "probe.h" - - #define AUTOFS_MOUNT_PATH "/tmp/run/blockd/" -@@ -1700,6 +1702,44 @@ static int main_extroot(int argc, char **argv) - } - #endif - -+ /* Find volume using libfstools */ -+ struct volume *data = volume_find("rootfs_data"); -+ if (data) { -+ volume_init(data); -+ -+ switch (volume_identify(data)) { -+ case FS_EXT4: { -+ char cfg[] = "/tmp/ext4_cfg"; -+ -+ /* Mount volume and try extroot (using fstab from that vol) */ -+ mkdir_p(cfg, 0755); -+ if (!mount(data->blk, cfg, "ext4", MS_NOATIME, NULL)) { -+ err = mount_extroot(cfg); -+ umount2(cfg, MNT_DETACH); -+ } -+ if (err < 0) -+ rmdir("/tmp/overlay"); -+ rmdir(cfg); -+ return err; -+ } -+ -+ case FS_F2FS: { -+ char cfg[] = "/tmp/f2fs_cfg"; -+ -+ /* Mount volume and try extroot (using fstab from that vol) */ -+ mkdir_p(cfg, 0755); -+ if (!mount(data->blk, cfg, "f2fs", MS_NOATIME, NULL)) { -+ err = mount_extroot(cfg); -+ umount2(cfg, MNT_DETACH); -+ } -+ if (err < 0) -+ rmdir("/tmp/overlay"); -+ rmdir(cfg); -+ return err; -+ } -+ } -+ } -+ - /* As a last resort look for /etc/config/fstab on "rootfs" partition */ - return mount_extroot(NULL); - } -diff --git a/libfstools/fstype.h b/libfstools/fstype.h -new file mode 100644 -index 0000000..8ea0bbf ---- /dev/null -+++ b/libfstools/fstype.h -@@ -0,0 +1,13 @@ -+#ifndef _FS_TYPE_H__ -+#define _FS_TYPE_H__ -+enum { -+ FS_NONE, -+ FS_SNAPSHOT, -+ FS_JFFS2, -+ FS_DEADCODE, -+ FS_UBIFS, -+ FS_F2FS, -+ FS_EXT4, -+ FS_TARGZ, -+}; -+#endif -\ No newline at end of file -diff --git a/libfstools/libfstools.h b/libfstools/libfstools.h -index 340e2dc..c327314 100644 ---- a/libfstools/libfstools.h -+++ b/libfstools/libfstools.h -@@ -18,20 +18,10 @@ - #include - #include - #include -+#include "fstype.h" - - struct volume; - --enum { -- FS_NONE, -- FS_SNAPSHOT, -- FS_JFFS2, -- FS_DEADCODE, -- FS_UBIFS, -- FS_F2FS, -- FS_EXT4, -- FS_TARGZ, --}; -- - enum fs_state { - FS_STATE_UNKNOWN, - FS_STATE_PENDING, --- -2.34.1 - diff --git a/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch b/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch deleted file mode 100644 index 65d1a087c..000000000 --- a/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch +++ /dev/null @@ -1,139 +0,0 @@ -From: Qi Liu - -In order to support extroot, block extroot command has to be able to -discover and properly mount the rootfs_data volume in order to discover -the extroot volume. Currently this process can only discover MTD devices. -This patch leverages libfstools in a similar way as mount_root to -discover, initialize, and mount rootfs_data volume. It would enable any -device with non-MTD rootfs_data volume to support extroot, including x86. - -Signed-off-by: Qi Liu ---- - CMakeLists.txt | 4 ++-- - block.c | 40 ++++++++++++++++++++++++++++++++++++++++ - libfstools/fstype.h | 12 ++++++++++++ - libfstools/libfstools.h | 11 +---------- - 4 files changed, 55 insertions(+), 12 deletions(-) - create mode 100644 libfstools/fstype.h - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index a586577..4b6e3e7 100644 - ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -75,9 +75,9 @@ INSTALL(TARGETS blockd RUNTIME DESTINATION sbin) - ADD_EXECUTABLE(block block.c probe.c probe-libblkid.c) - IF(DEFINED CMAKE_UBIFS_EXTROOT) - ADD_DEFINITIONS(-DUBIFS_EXTROOT) -- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json}) -+ TARGET_LINK_LIBRARIES(block fstools blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json}) - ELSE(DEFINED CMAKE_UBIFS_EXTROOT) -- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ${json}) -+ TARGET_LINK_LIBRARIES(block fstools blkid-tiny dl uci ubox ubus blobmsg_json ${json}) - ENDIF(DEFINED CMAKE_UBIFS_EXTROOT) - INSTALL(TARGETS block RUNTIME DESTINATION sbin) - -diff --git a/block.c b/block.c -index 569bf56..66cce46 100644 ---- a/block.c -+++ b/block.c -@@ -45,6 +45,8 @@ - #include - #include - -+#include "libfstools/fstype.h" -+#include "libfstools/volume.h" - #include "probe.h" - - #define AUTOFS_MOUNT_PATH "/tmp/run/blockd/" -@@ -1590,6 +1592,44 @@ static int main_extroot(int argc, char **argv) - } - #endif - -+ /* Find volume using libfstools */ -+ struct volume *data = volume_find("rootfs_data"); -+ if (data) { -+ volume_init(data); -+ -+ switch (volume_identify(data)) { -+ case FS_EXT4: { -+ char cfg[] = "/tmp/ext4_cfg"; -+ -+ /* Mount volume and try extroot (using fstab from that vol) */ -+ mkdir_p(cfg, 0755); -+ if (!mount(data->blk, cfg, "ext4", MS_NOATIME, NULL)) { -+ err = mount_extroot(cfg); -+ umount2(cfg, MNT_DETACH); -+ } -+ if (err < 0) -+ rmdir("/tmp/overlay"); -+ rmdir(cfg); -+ return err; -+ } -+ -+ case FS_F2FS: { -+ char cfg[] = "/tmp/f2fs_cfg"; -+ -+ /* Mount volume and try extroot (using fstab from that vol) */ -+ mkdir_p(cfg, 0755); -+ if (!mount(data->blk, cfg, "f2fs", MS_NOATIME, NULL)) { -+ err = mount_extroot(cfg); -+ umount2(cfg, MNT_DETACH); -+ } -+ if (err < 0) -+ rmdir("/tmp/overlay"); -+ rmdir(cfg); -+ return err; -+ } -+ } -+ } -+ - /* As a last resort look for /etc/config/fstab on "rootfs" partition */ - return mount_extroot(NULL); - } -diff --git a/libfstools/fstype.h b/libfstools/fstype.h -new file mode 100644 -index 0000000..8882343 ---- /dev/null -+++ b/libfstools/fstype.h -@@ -0,0 +1,13 @@ -+#ifndef _FS_TYPE_H__ -+#define _FS_TYPE_H__ -+enum { -+ FS_NONE, -+ FS_SNAPSHOT, -+ FS_JFFS2, -+ FS_DEADCODE, -+ FS_UBIFS, -+ FS_F2FS, -+ FS_EXT4, -+ FS_TARGZ, -+}; -+#endif -\ No newline at end of file -diff --git a/libfstools/libfstools.h b/libfstools/libfstools.h -index f27307a..8d3362f 100644 ---- a/libfstools/libfstools.h -+++ b/libfstools/libfstools.h -@@ -18,20 +18,10 @@ - #include - #include - #include -+#include "fstype.h" - - struct volume; - --enum { -- FS_NONE, -- FS_SNAPSHOT, -- FS_JFFS2, -- FS_DEADCODE, -- FS_UBIFS, -- FS_F2FS, -- FS_EXT4, -- FS_TARGZ, --}; -- - enum fs_state { - FS_STATE_UNKNOWN, - FS_STATE_PENDING, diff --git a/openwrt/patch/fstools/Makefile b/openwrt/patch/fstools/Makefile deleted file mode 100644 index 3b76b5be1..000000000 --- a/openwrt/patch/fstools/Makefile +++ /dev/null @@ -1,141 +0,0 @@ -# -# Copyright (C) 2014-2015 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=fstools -PKG_RELEASE:=1 - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL=$(PROJECT_GIT)/project/fstools.git -PKG_MIRROR_HASH:=4ec370a1cdc9fa69131f1403b064d2e05d54ee865411917410d7540454265319 -PKG_SOURCE_DATE:=2023-02-28 -PKG_SOURCE_VERSION:=bfe882d5ff4eeebb8f57c8a0f9b9e767a57870d8 -CMAKE_INSTALL:=1 - -PKG_LICENSE:=GPL-2.0 -PKG_LICENSE_FILES:= - -PKG_BUILD_FLAGS:=no-mips16 -PKG_FLAGS:=nonshared - -PKG_BUILD_DEPENDS := util-linux -PKG_CONFIG_DEPENDS := CONFIG_NAND_SUPPORT CONFIG_FSTOOLS_UBIFS_EXTROOT - -PKG_MAINTAINER:=John Crispin - -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/cmake.mk - -CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_UBIFS_EXTROOT),-DCMAKE_UBIFS_EXTROOT=y) -CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_OVL_MOUNT_FULL_ACCESS_TIME),-DCMAKE_OVL_MOUNT_FULL_ACCESS_TIME=y) -CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_OVL_MOUNT_COMPRESS_ZLIB),-DCMAKE_OVL_MOUNT_COMPRESS_ZLIB=y) - -define Package/fstools - SECTION:=base - CATEGORY:=Base system - DEPENDS:=+ubox +NAND_SUPPORT:ubi-utils - TITLE:=OpenWrt filesystem tools - MENU:=1 -endef - -define Package/fstools/config - config FSTOOLS_UBIFS_EXTROOT - depends on PACKAGE_fstools - depends on NAND_SUPPORT - bool "Support extroot functionality with UBIFS" - default y - help - This option makes it possible to use extroot functionality if the root filesystem resides on an UBIFS partition - - config FSTOOLS_OVL_MOUNT_FULL_ACCESS_TIME - depends on PACKAGE_fstools - bool "Full access time accounting" - default n - help - This option enables the full access time accounting (warning: it will increase the flash writes). - - config FSTOOLS_OVL_MOUNT_COMPRESS_ZLIB - depends on PACKAGE_fstools - bool "Compress using zlib" - default n - help - This option enables the compression using zlib on the storage device. -endef - -define Package/snapshot-tool - SECTION:=base - CATEGORY:=Base system - TITLE:=rootfs snapshoting tool - DEPENDS:=+libubox +fstools -endef - -define Package/block-mount/conffiles -/etc/config/fstab -endef - -define Package/block-mount - SECTION:=base - CATEGORY:=Base system - TITLE:=Block device mounting and checking - DEPENDS:=+ubox +libubox +libuci +libblobmsg-json +libjson-c +fstools -endef - -define Package/blockd - SECTION:=base - CATEGORY:=Base system - TITLE:=Block device automounting - DEPENDS:=+block-mount +fstools +libubus +kmod-fs-autofs4 +libblobmsg-json +libjson-c -endef - -define Package/fstools/install - $(INSTALL_DIR) $(1)/sbin $(1)/lib - - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{mount_root,jffs2reset} $(1)/sbin/ - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libfstools.so $(1)/lib/ - $(LN) jffs2reset $(1)/sbin/jffs2mark -endef - -define Package/snapshot-tool/install - $(INSTALL_DIR) $(1)/sbin - - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/snapshot_tool $(1)/sbin/ - $(INSTALL_BIN) ./files/snapshot $(1)/sbin/ -endef - -define Package/block-mount/install - $(INSTALL_DIR) $(1)/sbin $(1)/lib $(1)/usr/sbin $(1)/etc/hotplug.d/block $(1)/etc/init.d/ $(1)/etc/uci-defaults/ - - $(INSTALL_BIN) ./files/fstab.init $(1)/etc/init.d/fstab - $(INSTALL_CONF) ./files/fstab.default $(1)/etc/uci-defaults/10-fstab - $(INSTALL_CONF) ./files/mount.hotplug $(1)/etc/hotplug.d/block/10-mount - $(INSTALL_CONF) ./files/media-change.hotplug $(1)/etc/hotplug.d/block/00-media-change - - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/block $(1)/sbin/ - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libblkid-tiny.so $(1)/lib/ - $(LN) ../../sbin/block $(1)/usr/sbin/swapon - $(LN) ../../sbin/block $(1)/usr/sbin/swapoff - -endef - -define Package/blockd/install - $(INSTALL_DIR) $(1)/sbin $(1)/etc/init.d/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/blockd $(1)/sbin/ - $(INSTALL_BIN) ./files/blockd.init $(1)/etc/init.d/blockd -endef - -define Build/InstallDev - $(INSTALL_DIR) $(1)/usr/include - $(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/ - $(INSTALL_DIR) $(1)/usr/lib/ - $(CP) $(PKG_INSTALL_DIR)/usr/lib/libubi-utils.a $(1)/usr/lib/ -endef - -$(eval $(call BuildPackage,fstools)) -$(eval $(call BuildPackage,snapshot-tool)) -$(eval $(call BuildPackage,block-mount)) -$(eval $(call BuildPackage,blockd)) diff --git a/openwrt/patch/fstools/glibc/0001-libblkid-tiny-add-support-for-XFS-superblock.patch b/openwrt/patch/fstools/glibc/0001-libblkid-tiny-add-support-for-XFS-superblock.patch deleted file mode 100644 index 2331ef654..000000000 --- a/openwrt/patch/fstools/glibc/0001-libblkid-tiny-add-support-for-XFS-superblock.patch +++ /dev/null @@ -1,324 +0,0 @@ -From 1aedbf4d07d8417f656a6363f5db6b4cae765721 Mon Sep 17 00:00:00 2001 -From: sbwml <984419930@qq.com> -Date: Sat, 28 Jan 2023 19:33:16 +0800 -Subject: [PATCH 1/3] libblkid-tiny: add support for XFS superblock - ---- - CMakeLists.txt | 1 + - libblkid-tiny/libblkid-tiny.c | 2 + - libblkid-tiny/xfs.c | 278 ++++++++++++++++++++++++++++++++++ - 3 files changed, 281 insertions(+) - create mode 100644 libblkid-tiny/xfs.c - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 9a87979..506b2df 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -36,6 +36,7 @@ ADD_LIBRARY(blkid-tiny SHARED - libblkid-tiny/squashfs.c - libblkid-tiny/btrfs.c - libblkid-tiny/f2fs.c -+ libblkid-tiny/xfs.c - ) - INSTALL(TARGETS blkid-tiny LIBRARY DESTINATION lib) - INSTALL(FILES libblkid-tiny/libblkid-tiny.h DESTINATION include) -diff --git a/libblkid-tiny/libblkid-tiny.c b/libblkid-tiny/libblkid-tiny.c -index 8520f8a..3aca958 100644 ---- a/libblkid-tiny/libblkid-tiny.c -+++ b/libblkid-tiny/libblkid-tiny.c -@@ -188,6 +188,8 @@ static const struct blkid_idinfo *idinfos[] = - &hfs_idinfo, - &btrfs_idinfo, - &f2fs_idinfo, -+ &xfs_idinfo, -+ &xfs_log_idinfo, - }; - - int probe_block(char *block, struct blkid_struct_probe *pr) -diff --git a/libblkid-tiny/xfs.c b/libblkid-tiny/xfs.c -new file mode 100644 -index 0000000..0e35a44 ---- /dev/null -+++ b/libblkid-tiny/xfs.c -@@ -0,0 +1,278 @@ -+/* -+ * Copyright (C) 1999 by Andries Brouwer -+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o -+ * Copyright (C) 2001 by Andreas Dilger -+ * Copyright (C) 2004 Kay Sievers -+ * Copyright (C) 2008 Karel Zak -+ * Copyright (C) 2013 Eric Sandeen -+ * -+ * This file may be redistributed under the terms of the -+ * GNU Lesser General Public License. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "superblocks.h" -+ -+struct xfs_super_block { -+ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ -+ uint32_t sb_blocksize; /* logical block size, bytes */ -+ uint64_t sb_dblocks; /* number of data blocks */ -+ uint64_t sb_rblocks; /* number of realtime blocks */ -+ uint64_t sb_rextents; /* number of realtime extents */ -+ unsigned char sb_uuid[16]; /* file system unique id */ -+ uint64_t sb_logstart; /* starting block of log if internal */ -+ uint64_t sb_rootino; /* root inode number */ -+ uint64_t sb_rbmino; /* bitmap inode for realtime extents */ -+ uint64_t sb_rsumino; /* summary inode for rt bitmap */ -+ uint32_t sb_rextsize; /* realtime extent size, blocks */ -+ uint32_t sb_agblocks; /* size of an allocation group */ -+ uint32_t sb_agcount; /* number of allocation groups */ -+ uint32_t sb_rbmblocks; /* number of rt bitmap blocks */ -+ uint32_t sb_logblocks; /* number of log blocks */ -+ -+ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ -+ uint16_t sb_sectsize; /* volume sector size, bytes */ -+ uint16_t sb_inodesize; /* inode size, bytes */ -+ uint16_t sb_inopblock; /* inodes per block */ -+ char sb_fname[12]; /* file system name */ -+ uint8_t sb_blocklog; /* log2 of sb_blocksize */ -+ uint8_t sb_sectlog; /* log2 of sb_sectsize */ -+ uint8_t sb_inodelog; /* log2 of sb_inodesize */ -+ uint8_t sb_inopblog; /* log2 of sb_inopblock */ -+ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ -+ uint8_t sb_rextslog; /* log2 of sb_rextents */ -+ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ -+ uint8_t sb_imax_pct; /* max % of fs for inode space */ -+ /* statistics */ -+ uint64_t sb_icount; /* allocated inodes */ -+ uint64_t sb_ifree; /* free inodes */ -+ uint64_t sb_fdblocks; /* free data blocks */ -+ uint64_t sb_frextents; /* free realtime extents */ -+ -+ /* this is not all... but enough for libblkid */ -+ -+} __attribute__((packed)); -+ -+#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ -+#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ -+#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) -+#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) -+#define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ -+#define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ -+#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) -+#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) -+ -+#define XFS_DINODE_MIN_LOG 8 -+#define XFS_DINODE_MAX_LOG 11 -+#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) -+#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) -+ -+#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ -+#define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64kB */ -+#define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4kB */ -+ -+#define XFS_MIN_AG_BLOCKS 64 -+#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks) -+#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) * \ -+ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) -+ -+ -+static void sb_from_disk(struct xfs_super_block *from, -+ struct xfs_super_block *to) -+{ -+ -+ to->sb_magicnum = be32_to_cpu(from->sb_magicnum); -+ to->sb_blocksize = be32_to_cpu(from->sb_blocksize); -+ to->sb_dblocks = be64_to_cpu(from->sb_dblocks); -+ to->sb_rblocks = be64_to_cpu(from->sb_rblocks); -+ to->sb_rextents = be64_to_cpu(from->sb_rextents); -+ to->sb_logstart = be64_to_cpu(from->sb_logstart); -+ to->sb_rootino = be64_to_cpu(from->sb_rootino); -+ to->sb_rbmino = be64_to_cpu(from->sb_rbmino); -+ to->sb_rsumino = be64_to_cpu(from->sb_rsumino); -+ to->sb_rextsize = be32_to_cpu(from->sb_rextsize); -+ to->sb_agblocks = be32_to_cpu(from->sb_agblocks); -+ to->sb_agcount = be32_to_cpu(from->sb_agcount); -+ to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); -+ to->sb_logblocks = be32_to_cpu(from->sb_logblocks); -+ to->sb_versionnum = be16_to_cpu(from->sb_versionnum); -+ to->sb_sectsize = be16_to_cpu(from->sb_sectsize); -+ to->sb_inodesize = be16_to_cpu(from->sb_inodesize); -+ to->sb_inopblock = be16_to_cpu(from->sb_inopblock); -+ to->sb_blocklog = from->sb_blocklog; -+ to->sb_sectlog = from->sb_sectlog; -+ to->sb_inodelog = from->sb_inodelog; -+ to->sb_inopblog = from->sb_inopblog; -+ to->sb_agblklog = from->sb_agblklog; -+ to->sb_rextslog = from->sb_rextslog; -+ to->sb_inprogress = from->sb_inprogress; -+ to->sb_imax_pct = from->sb_imax_pct; -+ to->sb_icount = be64_to_cpu(from->sb_icount); -+ to->sb_ifree = be64_to_cpu(from->sb_ifree); -+ to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); -+ to->sb_frextents = be64_to_cpu(from->sb_frextents); -+} -+ -+static int xfs_verify_sb(struct xfs_super_block *ondisk) -+{ -+ struct xfs_super_block sb, *sbp = &sb; -+ -+ /* beXX_to_cpu(), but don't convert UUID and fsname! */ -+ sb_from_disk(ondisk, sbp); -+ -+ /* sanity checks, we don't want to rely on magic string only */ -+ if (sbp->sb_agcount <= 0 || -+ sbp->sb_sectsize < XFS_MIN_SECTORSIZE || -+ sbp->sb_sectsize > XFS_MAX_SECTORSIZE || -+ sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || -+ sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || -+ sbp->sb_sectsize != (1 << sbp->sb_sectlog) || -+ sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || -+ sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || -+ sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || -+ sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || -+ sbp->sb_blocksize != (1ULL << sbp->sb_blocklog) || -+ sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || -+ sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || -+ sbp->sb_inodelog < XFS_DINODE_MIN_LOG || -+ sbp->sb_inodelog > XFS_DINODE_MAX_LOG || -+ sbp->sb_inodesize != (1 << sbp->sb_inodelog) || -+ (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || -+ (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || -+ (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || -+ (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */) || -+ sbp->sb_dblocks == 0 || -+ sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || -+ sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp)) -+ return 0; -+ -+ /* TODO: version 5 has also checksum CRC32, maybe we can check it too */ -+ -+ return 1; -+} -+ -+static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag) -+{ -+ struct xfs_super_block *xs; -+ -+ xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block); -+ if (!xs) -+ return errno ? -errno : 1; -+ -+ if (!xfs_verify_sb(xs)) -+ return 1; -+ -+ if (*xs->sb_fname != '\0') -+ blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname, -+ sizeof(xs->sb_fname)); -+ blkid_probe_set_uuid(pr, xs->sb_uuid); -+ return 0; -+} -+ -+const struct blkid_idinfo xfs_idinfo = -+{ -+ .name = "xfs", -+ .usage = BLKID_USAGE_FILESYSTEM, -+ .probefunc = probe_xfs, -+ .magics = -+ { -+ { .magic = "XFSB", .len = 4 }, -+ { NULL } -+ } -+}; -+ -+struct xlog_rec_header { -+ uint32_t h_magicno; -+ uint32_t h_dummy1[1]; -+ uint32_t h_version; -+ uint32_t h_len; -+ uint32_t h_dummy2[71]; -+ uint32_t h_fmt; -+ unsigned char h_uuid[16]; -+} __attribute__((packed)); -+ -+#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe -+ -+/* -+ * For very small filesystems, the minimum log size -+ * can be smaller, but that seems vanishingly unlikely -+ * when used with an external log (which is used for -+ * performance reasons; tiny conflicts with that goal). -+ */ -+#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024) -+ -+#define XLOG_FMT_LINUX_LE 1 -+#define XLOG_FMT_LINUX_BE 2 -+#define XLOG_FMT_IRIX_BE 3 -+ -+#define XLOG_VERSION_1 1 -+#define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */ -+#define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2) -+ -+static int xlog_valid_rec_header(struct xlog_rec_header *rhead) -+{ -+ uint32_t hlen; -+ -+ if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) -+ return 0; -+ -+ if (!rhead->h_version || -+ (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))) -+ return 0; -+ -+ /* LR body must have data or it wouldn't have been written */ -+ hlen = be32_to_cpu(rhead->h_len); -+ if (hlen <= 0 || hlen > INT_MAX) -+ return 0; -+ -+ if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) && -+ rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) && -+ rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE)) -+ return 0; -+ -+ return 1; -+} -+ -+/* xlog record header will be in some sector in the first 256k */ -+static int probe_xfs_log(blkid_probe pr, -+ const struct blkid_idmag *mag __attribute__((__unused__))) -+{ -+ int i; -+ struct xlog_rec_header *rhead; -+ unsigned char *buf; -+ -+ buf = blkid_probe_get_buffer(pr, 0, 256*1024); -+ if (!buf) -+ return errno ? -errno : 1; -+ -+ if (memcmp(buf, "XFSB", 4) == 0) -+ return 1; /* this is regular XFS, ignore */ -+ -+ /* check the first 512 512-byte sectors */ -+ for (i = 0; i < 512; i++) { -+ rhead = (struct xlog_rec_header *)&buf[i*512]; -+ -+ if (xlog_valid_rec_header(rhead)) { -+ blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID"); -+ return 0; -+ } -+ } -+ -+ return 1; -+} -+ -+const struct blkid_idinfo xfs_log_idinfo = -+{ -+ .name = "xfs_external_log", -+ .usage = BLKID_USAGE_OTHER, -+ .probefunc = probe_xfs_log, -+ .magics = BLKID_NONE_MAGIC, -+ .minsz = XFS_MIN_LOG_BYTES, -+}; --- -2.34.1 - diff --git a/openwrt/patch/fstools/glibc/0003-block-add-xfsck-support.patch b/openwrt/patch/fstools/glibc/0003-block-add-xfsck-support.patch deleted file mode 100644 index 902e88210..000000000 --- a/openwrt/patch/fstools/glibc/0003-block-add-xfsck-support.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 71f459400f0990eb577a43345cd8507c8c9f5638 Mon Sep 17 00:00:00 2001 -From: sbwml <984419930@qq.com> -Date: Sat, 28 Jan 2023 20:31:55 +0800 -Subject: [PATCH 3/3] block: add xfsck support - ---- - block.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/block.c b/block.c -index 4b45200..6b8b28a 100644 ---- a/block.c -+++ b/block.c -@@ -764,6 +764,7 @@ static void check_filesystem(struct probe_info *pr) - const char *e2fsck = "/usr/sbin/e2fsck"; - const char *f2fsck = "/usr/sbin/fsck.f2fs"; - const char *fatfsck = "/usr/sbin/fsck.fat"; -+ const char *xfsck = "/usr/sbin/xfs_repair"; - const char *btrfsck = "/usr/bin/btrfsck"; - const char *ntfsck = "/usr/bin/ntfsfix"; - const char *ckfs; -@@ -776,6 +777,8 @@ static void check_filesystem(struct probe_info *pr) - ckfs = fatfsck; - } else if (!strncmp(pr->type, "f2fs", 4)) { - ckfs = f2fsck; -+ } else if (!strncmp(pr->type, "xfs", 3)) { -+ ckfs = xfsck; - } else if (!strncmp(pr->type, "ext", 3)) { - ckfs = e2fsck; - } else if (!strncmp(pr->type, "btrfs", 5)) { --- -2.34.1 - diff --git a/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch index bfc51feae..50bf16244 100644 --- a/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch +++ b/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch @@ -1,4 +1,4 @@ -From 441062a754bb94cace5e2bf700dc0b36c6bf2da7 Mon Sep 17 00:00:00 2001 +From a18334ecf9c643badcb33c034b59ea6c9c8fb323 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:35:57 +0800 Subject: [PATCH 01/11] tools: add llvm/clang toolchain diff --git a/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch b/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch index 77a15f70d..135f86d2a 100644 --- a/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch +++ b/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch @@ -1,4 +1,4 @@ -From 7b122fef7e663cdcca2a0f027a9abeddf28ac6fd Mon Sep 17 00:00:00 2001 +From a715edcd605ac305c60eace1e093abc5bf6d72c5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:39:25 +0800 Subject: [PATCH 02/11] tools: add upx tools diff --git a/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch b/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch index aedffdee2..d735e4ed7 100644 --- a/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch +++ b/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch @@ -1,4 +1,4 @@ -From cd93413b2c4d79fd0596f2029d79a0cbda687d56 Mon Sep 17 00:00:00 2001 +From c0843979a428633598583cd8d53a073d59a24e95 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:46:49 +0800 Subject: [PATCH 03/11] rootfs: add upx compression support @@ -18,10 +18,10 @@ Signed-off-by: sbwml 1 file changed, 5 insertions(+) diff --git a/include/rootfs.mk b/include/rootfs.mk -index 554dd48..d16618f 100644 +index e6cadc5..574e3fe 100644 --- a/include/rootfs.mk +++ b/include/rootfs.mk -@@ -122,6 +122,11 @@ define prepare_rootfs +@@ -120,6 +120,11 @@ define prepare_rootfs $(1)/usr/lib/opkg/info/*.postinst* \ $(1)/usr/lib/opkg/lists/* \ $(1)/var/lock/*.lock diff --git a/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch b/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch index f4e81b2f5..7e315f0c2 100644 --- a/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch +++ b/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch @@ -1,4 +1,4 @@ -From 2841d7c43220a473600e17c49dd7a8bba22a3108 Mon Sep 17 00:00:00 2001 +From 1595c68c698a95ee4fceb3b4b4d22a70b73ead15 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:47:41 +0800 Subject: [PATCH 04/11] rootfs: add r/w permissions for UCI configuration files @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 1 insertion(+) diff --git a/include/rootfs.mk b/include/rootfs.mk -index d16618f..02426c4 100644 +index 574e3fe..00203a4 100644 --- a/include/rootfs.mk +++ b/include/rootfs.mk -@@ -127,6 +127,7 @@ define prepare_rootfs +@@ -125,6 +125,7 @@ define prepare_rootfs $(STAGING_DIR_HOST)/bin/upx --lzma --best "$(1)$$file" || true; \ done < "$(TOPDIR)/upx_list.txt"; \ fi diff --git a/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch b/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch index 4bdfa418e..39235e841 100644 --- a/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch +++ b/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch @@ -1,4 +1,4 @@ -From c05c4c4a8765fc2dff676d38ee14319c8aee808e Mon Sep 17 00:00:00 2001 +From 38185cc7f8f6a6168fba302ba7268e7739b8c6be Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:48:29 +0800 Subject: [PATCH 05/11] rootfs: Add support for local kmod installation sources @@ -29,10 +29,10 @@ index 47f3dfc..ed9ecb2 100644 + endmenu diff --git a/include/rootfs.mk b/include/rootfs.mk -index 02426c4..db19192 100644 +index 00203a4..0bea0c1 100644 --- a/include/rootfs.mk +++ b/include/rootfs.mk -@@ -128,6 +128,12 @@ define prepare_rootfs +@@ -126,6 +126,12 @@ define prepare_rootfs done < "$(TOPDIR)/upx_list.txt"; \ fi chmod 600 $(1)/etc/config/* diff --git a/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch similarity index 94% rename from openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch rename to openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch index 9a46f8425..0fd11fad2 100644 --- a/openwrt/patch/generic-24.10/0007-kernel-Add-support-for-llvm-clang-compiler.patch +++ b/openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch @@ -1,7 +1,7 @@ -From e13ed92005152ae050d4a35f6912547ebe259847 Mon Sep 17 00:00:00 2001 +From dc1e35a7a4710a328b792d7b57e9eee961687eae Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:51:22 +0800 -Subject: [PATCH 07/13] kernel: Add support for llvm/clang compiler +Subject: [PATCH 06/11] kernel: Add support for llvm/clang compiler Signed-off-by: sbwml --- @@ -75,5 +75,5 @@ index 7fbecf9..3e988ed 100644 __unknown_flags=$(filter-out no-iremap no-mips16 gc-sections no-gc-sections lto no-lto no-mold,$(PKG_BUILD_FLAGS)) ifneq ($(__unknown_flags),) -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch b/openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch deleted file mode 100644 index 8309b25a4..000000000 --- a/openwrt/patch/generic-24.10/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch +++ /dev/null @@ -1,26 +0,0 @@ -From b7123fe13e05b078c978923bff06dfaa9cf41639 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Fri, 4 Oct 2024 10:50:08 +0800 -Subject: [PATCH 06/11] kernel: add MODULE_ALLOW_BTF_MISMATCH option - -Signed-off-by: sbwml ---- - config/Config-kernel.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index 4bd2cde..c83f2fb 100644 ---- a/config/Config-kernel.in -+++ b/config/Config-kernel.in -@@ -448,7 +448,7 @@ config KERNEL_MODULE_ALLOW_BTF_MISMATCH - BTF rather than refusing to load. The default behavior with - module BTF enabled is to reject modules with such mismatches; - this option will still load module BTF where possible but ignore -- it when a mismatch is found. -+ it when a mismatch is found. (skip patch) - - config KERNEL_DEBUG_INFO_REDUCED - bool "Reduce debugging information" --- -2.43.5 - diff --git a/openwrt/patch/generic-24.10/0009-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch similarity index 96% rename from openwrt/patch/generic-24.10/0009-build-kernel-add-out-of-tree-kernel-config.patch rename to openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch index 7d1a7840a..df0be8928 100644 --- a/openwrt/patch/generic-24.10/0009-build-kernel-add-out-of-tree-kernel-config.patch +++ b/openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch @@ -1,7 +1,7 @@ -From 532fa843ebb023b49421720f62ffae1a792b60e9 Mon Sep 17 00:00:00 2001 +From 6c430896b7113c79b80106dff806fa1a196bbd57 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:56:57 +0800 -Subject: [PATCH 09/11] build: kernel: add out-of-tree kernel config +Subject: [PATCH 07/11] build: kernel: add out-of-tree kernel config Signed-off-by: sbwml --- @@ -28,10 +28,10 @@ index 9079303..2cbefc2 100644 string "Use external kernel tree" if DEVEL default "" diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index c4a042b..2d6b968 100644 +index f94ed33..8e9ed74 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk -@@ -119,6 +119,78 @@ define Kernel/SetNoInitramfs +@@ -108,6 +108,78 @@ define Kernel/SetNoInitramfs echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config.set diff --git a/openwrt/patch/generic-24.10/0010-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch similarity index 78% rename from openwrt/patch/generic-24.10/0010-include-kernel-add-miss-config-for-linux-6.11.patch rename to openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch index 9638fa53b..d8f0bf94d 100644 --- a/openwrt/patch/generic-24.10/0010-include-kernel-add-miss-config-for-linux-6.11.patch +++ b/openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch @@ -1,7 +1,7 @@ -From 046d307da1b54936b69c701bb3a3aa587853c65f Mon Sep 17 00:00:00 2001 +From f1e4ddedeaae1b7bd8fb7e748f911c5d6b43cd92 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:29 +0800 -Subject: [PATCH 10/11] include: kernel: add miss config for linux-6.11 +Subject: [PATCH 08/11] include: kernel: add miss config for linux-6.11 Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 1 insertion(+) diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index 2d6b968..36a1b30 100644 +index 8e9ed74..d703d5d 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk -@@ -119,6 +119,7 @@ define Kernel/SetNoInitramfs +@@ -108,6 +108,7 @@ define Kernel/SetNoInitramfs echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config.set diff --git a/openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch b/openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch deleted file mode 100644 index 86b9d2be3..000000000 --- a/openwrt/patch/generic-24.10/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1754cecb299a3f83eb68dc777262c5f3d6e06dc3 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Fri, 4 Oct 2024 10:52:57 +0800 -Subject: [PATCH 08/11] libquadmath: Add libquadmath to the toolchain - -Signed-off-by: sbwml ---- - package/libs/toolchain/Makefile | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/package/libs/toolchain/Makefile b/package/libs/toolchain/Makefile -index 7c117b1..f342368 100644 ---- a/package/libs/toolchain/Makefile -+++ b/package/libs/toolchain/Makefile -@@ -4,6 +4,7 @@ - # This is free software, licensed under the GNU General Public License v2. - # See /LICENSE for more information. - # -+# skip patch - - include $(TOPDIR)/rules.mk - PKG_NAME:=toolchain --- -2.43.5 - diff --git a/openwrt/patch/generic-24.10/0011-meson-add-platform-variable-to-cross-compilation-fil.patch b/openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch similarity index 89% rename from openwrt/patch/generic-24.10/0011-meson-add-platform-variable-to-cross-compilation-fil.patch rename to openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch index 6d032d7dc..dfa928e0c 100644 --- a/openwrt/patch/generic-24.10/0011-meson-add-platform-variable-to-cross-compilation-fil.patch +++ b/openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch @@ -1,7 +1,7 @@ -From eb740ac64eeab24f9968d3013d2fa5752c7c2b0b Mon Sep 17 00:00:00 2001 +From 1826695bc17e5573fe137bf3576ed6a8ca49f3d4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:54 +0800 -Subject: [PATCH 11/11] meson: add platform variable to cross-compilation file +Subject: [PATCH 09/11] meson: add platform variable to cross-compilation file Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch b/openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch similarity index 86% rename from openwrt/patch/generic-24.10/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch rename to openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch index d4786d652..0ef0acae3 100644 --- a/openwrt/patch/generic-24.10/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch +++ b/openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch @@ -1,7 +1,7 @@ -From b7d40a7057e1ffe5b2dcf734243ef2ae791f5fb1 Mon Sep 17 00:00:00 2001 +From 1a29c74ae624f54ea9314f7ec1e629cdaa4a72e5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 21:40:05 +0800 -Subject: [PATCH] kernel: add legacy cgroup v1 memory controller +Subject: [PATCH 10/11] kernel: add legacy cgroup v1 memory controller Signed-off-by: sbwml --- @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 10 insertions(+) diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index c83f2fb..39a9730 100644 +index 0fa039d..a438621 100644 --- a/config/Config-kernel.in +++ b/config/Config-kernel.in @@ -934,6 +934,16 @@ if KERNEL_CGROUPS diff --git a/openwrt/patch/generic-24.10/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch b/openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch similarity index 87% rename from openwrt/patch/generic-24.10/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch rename to openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch index eebac8923..3d73a0333 100644 --- a/openwrt/patch/generic-24.10/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch +++ b/openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch @@ -1,7 +1,7 @@ -From 79b76c15bb981843e7a08f0c906c013e96a02d2e Mon Sep 17 00:00:00 2001 +From fccdd7ad134c215ddeed58239781db7666410b2a Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 12 Oct 2024 08:36:46 +0800 -Subject: [PATCH 13/13] kernel: add PREEMPT_RT support for aarch64/x86_64 +Subject: [PATCH 11/11] kernel: add PREEMPT_RT support for aarch64/x86_64 Signed-off-by: sbwml --- @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 13 insertions(+) diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index 39a9730..5439219 100644 +index a438621..47b7c4c 100644 --- a/config/Config-kernel.in +++ b/config/Config-kernel.in @@ -20,6 +20,19 @@ config KERNEL_BUILD_DOMAIN @@ -33,5 +33,5 @@ index 39a9730..5439219 100644 bool "Enable support for printk" default y -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch b/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch deleted file mode 100644 index 8ea6d85f6..000000000 --- a/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0b193c7b7c908758a703245071068182b08b7ef2 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 6 Oct 2024 06:20:50 +0800 -Subject: [PATCH] tools/mold: update to 2.34.1 - -Signed-off-by: sbwml ---- - tools/mold/Makefile | 7 +++---- - 1 file changed, 3 insertions(+), 4 deletions(-) - -diff --git a/tools/mold/Makefile b/tools/mold/Makefile -index 28d760d..1a37b68 100644 ---- a/tools/mold/Makefile -+++ b/tools/mold/Makefile -@@ -3,12 +3,11 @@ - include $(TOPDIR)/rules.mk - - PKG_NAME:=mold --PKG_VERSION:=2.33.0 -+PKG_VERSION:=2.34.1 - - PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz --PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz --PKG_SOURCE_URL:=https://github.com/rui314/mold/archive/refs/tags --PKG_HASH:=37b3aacbd9b6accf581b92ba1a98ca418672ae330b78fe56ae542c2dcb10a155 -+PKG_SOURCE_URL:=https://codeload.github.com/rui314/mold/tar.gz/v$(PKG_VERSION)? -+PKG_HASH:=a8cf638045b4a4b2697d0bcc77fd96eae93d54d57ad3021bf03b0333a727a59d - - include $(INCLUDE_DIR)/host-build.mk - include $(INCLUDE_DIR)/cmake.mk --- -2.43.5 - diff --git a/openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch b/openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch new file mode 100644 index 000000000..dddee6560 --- /dev/null +++ b/openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch @@ -0,0 +1,239 @@ +diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c +index 3313149..1442e1f 100644 +--- a/target/linux/generic/files/drivers/net/phy/ar8327.c ++++ b/target/linux/generic/files/drivers/net/phy/ar8327.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1171,6 +1172,7 @@ ar8327_sw_hw_apply(struct switch_dev *dev) + return 0; + } + ++static + int + ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, +@@ -1189,6 +1191,7 @@ ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev, + return 0; + } + ++static + int + ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, +@@ -1207,6 +1210,7 @@ ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev, + return 0; + } + ++static + int + ar8327_sw_get_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, +@@ -1224,6 +1228,7 @@ ar8327_sw_get_igmp_snooping(struct switch_dev *dev, + return 0; + } + ++static + int + ar8327_sw_set_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, +@@ -1240,6 +1245,7 @@ ar8327_sw_set_igmp_snooping(struct switch_dev *dev, + return 0; + } + ++static + int + ar8327_sw_get_igmp_v3(struct switch_dev *dev, + const struct switch_attr *attr, +@@ -1256,6 +1262,7 @@ ar8327_sw_get_igmp_v3(struct switch_dev *dev, + return 0; + } + ++static + int + ar8327_sw_set_igmp_v3(struct switch_dev *dev, + const struct switch_attr *attr, +diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c +index d5f9bfc..ac37ef9 100644 +--- a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c ++++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c +@@ -227,7 +227,7 @@ static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, + } + } + +-void b53_set_forwarding(struct b53_device *dev, int enable) ++static void b53_set_forwarding(struct b53_device *dev, int enable) + { + u8 mgmt; + +diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c +index c85df1f..fdcebc7 100644 +--- a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c ++++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c +@@ -400,7 +400,7 @@ static struct phy_driver b53_phy_driver_id3 = { + .read_status = b53_phy_read_status, + }; + +-int __init b53_phy_driver_register(void) ++static int __init b53_phy_driver_register(void) + { + int ret; + +@@ -422,7 +422,7 @@ err1: + return ret; + } + +-void __exit b53_phy_driver_unregister(void) ++static void __exit b53_phy_driver_unregister(void) + { + phy_driver_unregister(&b53_phy_driver_id3); + phy_driver_unregister(&b53_phy_driver_id2); +diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c +index a26fd20..c3d50a0 100644 +--- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c ++++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c +@@ -254,6 +254,7 @@ static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) + #define MDC_MDIO_WRITE_OP 0x0003 + #define MDC_REALTEK_PHY_ADDR 0x0 + ++static + int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) + { + u32 phy_id = smi->phy_id; +@@ -1577,6 +1578,7 @@ static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8 + } + #endif + ++static + int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi) + { + struct rtl8366_platform_data *pdata = pdev->dev.platform_data; +diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c +index 0e01160..88ac9cc 100644 +--- a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c ++++ b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c +@@ -1478,7 +1478,7 @@ static int rtl8366rb_probe(struct platform_device *pdev) + return err; + } + +-static int rtl8366rb_remove(struct platform_device *pdev) ++static void rtl8366rb_remove(struct platform_device *pdev) + { + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + +@@ -1488,8 +1488,6 @@ static int rtl8366rb_remove(struct platform_device *pdev) + rtl8366_smi_cleanup(smi); + kfree(smi); + } +- +- return 0; + } + + #ifdef CONFIG_OF +@@ -1507,7 +1505,7 @@ static struct platform_driver rtl8366rb_driver = { + .of_match_table = of_match_ptr(rtl8366rb_match), + }, + .probe = rtl8366rb_probe, +- .remove = rtl8366rb_remove, ++ .remove_new = rtl8366rb_remove, + }; + + static int __init rtl8366rb_module_init(void) +diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366s.c b/target/linux/generic/files/drivers/net/phy/rtl8366s.c +index 8c74677..e2efac6 100644 +--- a/target/linux/generic/files/drivers/net/phy/rtl8366s.c ++++ b/target/linux/generic/files/drivers/net/phy/rtl8366s.c +@@ -1266,7 +1266,7 @@ static int rtl8366s_probe(struct platform_device *pdev) + return err; + } + +-static int rtl8366s_remove(struct platform_device *pdev) ++static void rtl8366s_remove(struct platform_device *pdev) + { + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + +@@ -1276,8 +1276,6 @@ static int rtl8366s_remove(struct platform_device *pdev) + rtl8366_smi_cleanup(smi); + kfree(smi); + } +- +- return 0; + } + + #ifdef CONFIG_OF +@@ -1297,7 +1295,7 @@ static struct platform_driver rtl8366s_driver = { + #endif + }, + .probe = rtl8366s_probe, +- .remove = rtl8366s_remove, ++ .remove_new = rtl8366s_remove, + }; + + static int __init rtl8366s_module_init(void) +diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367.c b/target/linux/generic/files/drivers/net/phy/rtl8367.c +index 0acfeb5..3b1c870 100644 +--- a/target/linux/generic/files/drivers/net/phy/rtl8367.c ++++ b/target/linux/generic/files/drivers/net/phy/rtl8367.c +@@ -1801,7 +1801,7 @@ static int rtl8367_probe(struct platform_device *pdev) + return err; + } + +-static int rtl8367_remove(struct platform_device *pdev) ++static void rtl8367_remove(struct platform_device *pdev) + { + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + +@@ -1811,8 +1811,6 @@ static int rtl8367_remove(struct platform_device *pdev) + rtl8366_smi_cleanup(smi); + kfree(smi); + } +- +- return 0; + } + + static void rtl8367_shutdown(struct platform_device *pdev) +@@ -1840,7 +1838,7 @@ static struct platform_driver rtl8367_driver = { + #endif + }, + .probe = rtl8367_probe, +- .remove = rtl8367_remove, ++ .remove_new = rtl8367_remove, + .shutdown = rtl8367_shutdown, + }; + +diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c +index 4236912..89aa8d7 100644 +--- a/target/linux/generic/files/drivers/net/phy/rtl8367b.c ++++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c +@@ -1600,7 +1600,7 @@ static int rtl8367b_probe(struct platform_device *pdev) + return err; + } + +-static int rtl8367b_remove(struct platform_device *pdev) ++static void rtl8367b_remove(struct platform_device *pdev) + { + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + +@@ -1610,8 +1610,6 @@ static int rtl8367b_remove(struct platform_device *pdev) + rtl8366_smi_cleanup(smi); + kfree(smi); + } +- +- return 0; + } + + static void rtl8367b_shutdown(struct platform_device *pdev) +@@ -1639,7 +1637,7 @@ static struct platform_driver rtl8367b_driver = { + #endif + }, + .probe = rtl8367b_probe, +- .remove = rtl8367b_remove, ++ .remove_new = rtl8367b_remove, + .shutdown = rtl8367b_shutdown, + }; + diff --git a/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch deleted file mode 100644 index bb5deace2..000000000 --- a/openwrt/patch/generic/0001-tools-add-llvm-clang-toolchain.patch +++ /dev/null @@ -1,89 +0,0 @@ -From bc462181d8f9d64841f5a68625070efd116bc655 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 26 Sep 2024 06:32:20 +0800 -Subject: [PATCH 01/11] tools: add llvm/clang toolchain - -Signed-off-by: sbwml ---- - tools/Makefile | 7 +++++++ - tools/clang/Makefile | 43 +++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 50 insertions(+) - create mode 100644 tools/clang/Makefile - -diff --git a/tools/Makefile b/tools/Makefile -index 40c3ec1..88250b3 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -29,6 +29,12 @@ endif - ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),) - BUILD_LZO_TOOLS = y - endif -+ifeq ($(CONFIG_KERNEL_CC),clang) -+ BUILD_CLANG_HOST = y -+endif -+ifeq ($(CONFIG_BPF_TOOLCHAIN_HOST),y) -+ BUILD_CLANG_HOST = y -+endif - - tools-y += autoconf - tools-y += autoconf-archive -@@ -68,6 +74,7 @@ tools-y += sstrip - tools-y += zip - tools-y += zlib - tools-y += zstd -+tools-$(if $(BUILD_CLANG_HOST),y) += clang - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS),y) += liblzo - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_B43_TOOLS),y) += b43-tools - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_BZIP2_TOOLS),y) += bzip2 -diff --git a/tools/clang/Makefile b/tools/clang/Makefile -new file mode 100644 -index 0000000..0fcd4d0 ---- /dev/null -+++ b/tools/clang/Makefile -@@ -0,0 +1,43 @@ -+# -+# Copyright (C) 2006-2017 OpenWrt.org -+# -+# This is free software, licensed under the GNU General Public License v2. -+# See /LICENSE for more information. -+# -+ -+include $(TOPDIR)/rules.mk -+ -+PKG_NAME:=clang -+PKG_VERSION:=19.0.1 -+ -+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz -+PKG_SOURCE_URL:=https://github.com/sbwml/openwrt-llvm-toolchain/releases/download/$(PKG_VERSION)/ -+PKG_HASH:=a73c5ec6d62e0f47fd3cf25e3904b5818b18695b7302a9b404e411f2085110a3 -+ -+PKG_MAINTAINER:=sbwml -+PKG_LICENSE:=Apache-2.0 -+PKG_LICENSE_FILES:=LICENSE -+ -+include $(INCLUDE_DIR)/host-build.mk -+ -+define Host/Prepare -+ $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz -+endef -+ -+define Host/Compile -+endef -+ -+define Host/Install -+ $(CP) -a $(HOST_BUILD_DIR)/{bin,include,lib} $(STAGING_DIR_HOST)/ -+ $(RM) -rf $(HOST_BUILD_DIR)/{bin,include,lib,libexec,share} -+endef -+ -+define Host/Uninstall -+ ( \ -+ rm -rf $(STAGING_DIR_HOST)/bin/{*clang*,dsymutil,find-all-symbols,*lld*,llc,lli,llvm*,merge-fdata,opt,perf2bolt,wasm-ld} ; \ -+ rm -rf $(STAGING_DIR_HOST)/include/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,c++,clang*,i386-unknown-linux-gnu,i686-unknown-linux-musl,lld,llvm*,mach-o,polly,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ -+ rm -rf $(STAGING_DIR_HOST)/lib/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,bfd-plugins,clang,cmake,i386-unknown-linux-gnu,i686-unknown-linux-musl,libbolt*,libfindAllSymbols.a,liblld*,*LLVM*,libPolly*,libRemarks.so,libxml2*,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ -+ ) -+endef -+ -+$(eval $(call HostBuild)) --- -2.43.5 - diff --git a/openwrt/patch/generic/0002-tools-add-upx-tools.patch b/openwrt/patch/generic/0002-tools-add-upx-tools.patch deleted file mode 100644 index 813a2a665..000000000 --- a/openwrt/patch/generic/0002-tools-add-upx-tools.patch +++ /dev/null @@ -1,63 +0,0 @@ -From b31fe0b43bc35d9bf640b92375db9ec31d543721 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 26 Sep 2024 06:38:58 +0800 -Subject: [PATCH 02/11] tools: add upx tools - -Signed-off-by: sbwml ---- - tools/Makefile | 1 + - tools/upx/Makefile | 30 ++++++++++++++++++++++++++++++ - 2 files changed, 31 insertions(+) - create mode 100644 tools/upx/Makefile - -diff --git a/tools/Makefile b/tools/Makefile -index 88250b3..e4afc87 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -71,6 +71,7 @@ tools-y += pkgconf - tools-y += quilt - tools-y += squashfs4 - tools-y += sstrip -+tools-y += upx - tools-y += zip - tools-y += zlib - tools-y += zstd -diff --git a/tools/upx/Makefile b/tools/upx/Makefile -new file mode 100644 -index 0000000..9004514 ---- /dev/null -+++ b/tools/upx/Makefile -@@ -0,0 +1,30 @@ -+include $(TOPDIR)/rules.mk -+ -+PKG_NAME:=upx -+PKG_VERSION:=4.2.4 -+ -+PKG_SOURCE:=upx-$(PKG_VERSION)-src.tar.xz -+PKG_SOURCE_URL:=https://github.com/upx/upx/releases/download/v$(PKG_VERSION)/ -+PKG_HASH:=5ed6561607d27fb4ef346fc19f08a93696fa8fa127081e7a7114068306b8e1c4 -+ -+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)-src -+HOST_BUILD_PARALLEL:=1 -+ -+include $(INCLUDE_DIR)/host-build.mk -+ -+define Host/Compile -+ $(MAKE) -C $(HOST_BUILD_DIR)/src \ -+ LDFLAGS="$(HOST_LDFLAGS)" \ -+ CXX="$(HOSTCXX)" -+endef -+ -+define Host/Install -+ $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin -+ $(INSTALL_BIN) $(HOST_BUILD_DIR)/build/release/upx $(STAGING_DIR_HOST)/bin/upx -+endef -+ -+define Host/Clean -+ rm -f $(STAGING_DIR_HOST)/bin/upx -+endef -+ -+$(eval $(call HostBuild)) --- -2.43.5 - diff --git a/openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch b/openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch deleted file mode 100644 index 4a5aced69..000000000 --- a/openwrt/patch/generic/0003-rootfs-add-upx-compression-support.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 986b21972b58606f861d284f370c35bffa9b51b8 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 7 Apr 2024 04:08:40 +0800 -Subject: [PATCH 03/11] rootfs: add upx compression support - -* When the upx_list.txt file exists in the source code root directory, - it will be compressed by upx. - -* fill in the binary path with rootfs as the absolute path, like this: - -/usr/bin/xray -/usr/bin/xray-plugin -/usr/sbin/haproxy - -Signed-off-by: sbwml ---- - include/rootfs.mk | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/rootfs.mk b/include/rootfs.mk -index f2ed648..eb69a99 100644 ---- a/include/rootfs.mk -+++ b/include/rootfs.mk -@@ -95,6 +95,11 @@ define prepare_rootfs - $(1)/usr/lib/opkg/info/*.postinst* \ - $(1)/usr/lib/opkg/lists/* \ - $(1)/var/lock/*.lock -+ @if [ -f "$(TOPDIR)/upx_list.txt" ]; then \ -+ while IFS= read -r file; do \ -+ $(STAGING_DIR_HOST)/bin/upx --lzma --best "$(1)$$file" || true; \ -+ done < "$(TOPDIR)/upx_list.txt"; \ -+ fi - $(call clean_ipkg,$(1)) - $(call mklibs,$(1)) - $(if $(SOURCE_DATE_EPOCH),find $(1)/ -mindepth 1 -execdir touch -hcd "@$(SOURCE_DATE_EPOCH)" "{}" +) --- -2.43.5 - diff --git a/openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch b/openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch deleted file mode 100644 index 3709a3ca8..000000000 --- a/openwrt/patch/generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0bfe29ac8cefc3335184e93e5ae0a03bdaaff336 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 30 Jun 2024 21:58:24 +0800 -Subject: [PATCH 04/11] rootfs: add r/w permissions for UCI configuration files - -Signed-off-by: sbwml ---- - include/rootfs.mk | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/rootfs.mk b/include/rootfs.mk -index eb69a99..f8bc2ed 100644 ---- a/include/rootfs.mk -+++ b/include/rootfs.mk -@@ -100,6 +100,7 @@ define prepare_rootfs - $(STAGING_DIR_HOST)/bin/upx --lzma --best "$(1)$$file" || true; \ - done < "$(TOPDIR)/upx_list.txt"; \ - fi -+ chmod 600 $(1)/etc/config/* - $(call clean_ipkg,$(1)) - $(call mklibs,$(1)) - $(if $(SOURCE_DATE_EPOCH),find $(1)/ -mindepth 1 -execdir touch -hcd "@$(SOURCE_DATE_EPOCH)" "{}" +) --- -2.43.5 - diff --git a/openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch b/openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch deleted file mode 100644 index ac2b84b98..000000000 --- a/openwrt/patch/generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 8125e1abca321f218b90c797b0cc887d418f055c Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 14 Jul 2024 12:43:06 +0800 -Subject: [PATCH 05/11] rootfs: Add support for local kmod installation sources - -* CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES=y - -Signed-off-by: sbwml ---- - config/Config-images.in | 8 ++++++++ - include/rootfs.mk | 6 ++++++ - 2 files changed, 14 insertions(+) - -diff --git a/config/Config-images.in b/config/Config-images.in -index c32fa00..79d89f5 100644 ---- a/config/Config-images.in -+++ b/config/Config-images.in -@@ -318,4 +318,12 @@ menu "Target Images" - across reboots. When enabled, /var/run will still be linked - to /tmp/run. - -+ config TARGET_ROOTFS_LOCAL_PACKAGES -+ bool "Create a local target package opkg installation source" -+ select ALL_KMODS -+ default n -+ help -+ Copy target packages to rootfs and overwrite the original -+ openwrt_core installation source with local files. -+ - endmenu -diff --git a/include/rootfs.mk b/include/rootfs.mk -index f8bc2ed..06662d4 100644 ---- a/include/rootfs.mk -+++ b/include/rootfs.mk -@@ -101,6 +101,12 @@ define prepare_rootfs - done < "$(TOPDIR)/upx_list.txt"; \ - fi - chmod 600 $(1)/etc/config/* -+ @( \ -+ if [ "$(call qstrip,$(CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES))" = y ]; then \ -+ $(CP) $(TOPDIR)/bin/targets/$(BOARD)/$(SUBTARGET)/packages $(1)/usr/share/openwrt_core; \ -+ $(SED) "/openwrt_core/c\src/gz openwrt_core file:///usr/share/openwrt_core" $(1)/etc/opkg/distfeeds.conf; \ -+ fi; \ -+ ) - $(call clean_ipkg,$(1)) - $(call mklibs,$(1)) - $(if $(SOURCE_DATE_EPOCH),find $(1)/ -mindepth 1 -execdir touch -hcd "@$(SOURCE_DATE_EPOCH)" "{}" +) --- -2.43.5 - diff --git a/openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch b/openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch deleted file mode 100644 index 788c4b02d..000000000 --- a/openwrt/patch/generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch +++ /dev/null @@ -1,41 +0,0 @@ -From a28478cd750d5295a80eb84d74522bbec5d25f1c Mon Sep 17 00:00:00 2001 -From: Tianling Shen -Date: Tue, 16 May 2023 12:38:53 +0800 -Subject: [PATCH 06/11] kernel: add MODULE_ALLOW_BTF_MISMATCH option - -BTF mismatch can occur for a separately-built module even when the ABI -is otherwise compatible and nothing else would prevent successfully -loading. Add a new config to control how mismatches are handled. By -default, preserve the current behavior of refusing to load the -module. If MODULE_ALLOW_BTF_MISMATCH is enabled, load the module but -ignore its BTF information. - -Signed-off-by: Tianling Shen ---- - config/Config-kernel.in | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index ea828ae..a262d59 100644 ---- a/config/Config-kernel.in -+++ b/config/Config-kernel.in -@@ -364,6 +364,16 @@ config KERNEL_DEBUG_INFO_BTF - - Required to run BPF CO-RE applications. - -+config KERNEL_MODULE_ALLOW_BTF_MISMATCH -+ bool "Allow loading modules with non-matching BTF type info" -+ depends on KERNEL_DEBUG_INFO_BTF -+ help -+ For modules whose split BTF does not match vmlinux, load without -+ BTF rather than refusing to load. The default behavior with -+ module BTF enabled is to reject modules with such mismatches; -+ this option will still load module BTF where possible but ignore -+ it when a mismatch is found. -+ - config KERNEL_DEBUG_INFO_REDUCED - bool "Reduce debugging information" - default y --- -2.43.5 - diff --git a/openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch deleted file mode 100644 index 456d9f1e6..000000000 --- a/openwrt/patch/generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 57df3edf99312bbe39647d0dd9fd36896a9a3e09 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Mon, 6 May 2024 03:21:07 +0800 -Subject: [PATCH 07/11] kernel: Add support for llvm/clang compiler - -Signed-off-by: sbwml ---- - config/Config-devel.in | 7 +++++++ - include/kernel-defaults.mk | 11 +++++++++++ - include/kernel.mk | 13 ++++++++++++- - include/package.mk | 4 ++++ - 4 files changed, 34 insertions(+), 1 deletion(-) - -diff --git a/config/Config-devel.in b/config/Config-devel.in -index cbac91c..9079303 100644 ---- a/config/Config-devel.in -+++ b/config/Config-devel.in -@@ -95,6 +95,13 @@ menuconfig DEVEL - default "-falign-functions=32" if TARGET_bcm53xx - default "" - -+ config KERNEL_CC -+ string "Set kernel C compiler" if DEVEL -+ default "\$(TARGET_CC)" -+ help -+ Enter C compiler name or full pathname i.e.: clang -+ If not set, uses '$(TARGET_CC)' -+ - config EXTERNAL_KERNEL_TREE - string "Use external kernel tree" if DEVEL - default "" -diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index b17ff7f..b8a1479 100644 ---- a/include/kernel-defaults.mk -+++ b/include/kernel-defaults.mk -@@ -13,6 +13,17 @@ ifneq (,$(KERNEL_CC)) - KERNEL_MAKEOPTS += CC="$(KERNEL_CC)" - endif - -+ifneq (,$(findstring clang,$(KERNEL_CC))) -+ ifneq (,$(filter clang-%,$(KERNEL_CC))) -+ LLVM := $(subst clang-,,$(KERNEL_CC)) -+ LLVM_LLD := ld.lld-$(subst clang-,,$(KERNEL_CC)) -+ else -+ LLVM := 1 -+ LLVM_LLD := ld.lld -+ endif -+ KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)" LD="$(LLVM_LLD)" LD=ld.lld LLVM=$(LLVM) LLVM_IAS=1 -+endif -+ - export HOST_EXTRACFLAGS=-I$(STAGING_DIR_HOST)/include - - # defined in quilt.mk -diff --git a/include/kernel.mk b/include/kernel.mk -index 3012eb8..1d85a8f 100644 ---- a/include/kernel.mk -+++ b/include/kernel.mk -@@ -35,7 +35,7 @@ else - KERNEL_CC?=$(HOSTCC) - KERNEL_CROSS?= - else -- KERNEL_CC?=$(TARGET_CC) -+ KERNEL_CC?=$(call qstrip,$(CONFIG_KERNEL_CC)) - KERNEL_CROSS?=$(TARGET_CROSS) - endif - -@@ -119,6 +119,17 @@ KERNEL_MAKE_FLAGS = \ - cmd_syscalls= \ - $(if $(__package_mk),KBUILD_EXTRA_SYMBOLS="$(wildcard $(PKG_SYMVERS_DIR)/*.symvers)") - -+ifneq (,$(findstring clang,$(KERNEL_CC))) -+ ifneq (,$(filter clang-%,$(KERNEL_CC))) -+ LLVM := $(subst clang-,,$(KERNEL_CC)) -+ LLVM_LLD := ld.lld-$(subst clang-,,$(KERNEL_CC)) -+ else -+ LLVM := 1 -+ LLVM_LLD := ld.lld -+ endif -+ KERNEL_MAKE_FLAGS += CC="$(KERNEL_CC)" LD="$(LLVM_LLD)" LLVM=$(LLVM) LLVM_IAS=1 -+endif -+ - KERNEL_NOSTDINC_FLAGS = \ - -nostdinc $(if $(DUMP),, -isystem $(shell $(TARGET_CC) -print-file-name=include)) - -diff --git a/include/package.mk b/include/package.mk -index c391d32..802e33a 100644 ---- a/include/package.mk -+++ b/include/package.mk -@@ -23,6 +23,10 @@ else - PKG_JOBS?=$(if $(PKG_BUILD_PARALLEL),$(MAKE_J),-j1) - endif - -+ifneq (,$(findstring clang,$(KERNEL_CC))) -+ MAKE := $(KERNEL_MAKE) -+endif -+ - PKG_BUILD_FLAGS?= - __unknown_flags=$(filter-out no-iremap no-mips16 gc-sections no-gc-sections lto no-lto,$(PKG_BUILD_FLAGS)) - ifneq ($(__unknown_flags),) --- -2.43.5 - diff --git a/openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch b/openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch deleted file mode 100644 index a1607c732..000000000 --- a/openwrt/patch/generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 71414ef6e0847d4f9d546b45630633054e072ea4 Mon Sep 17 00:00:00 2001 -From: Carlos Miguel Ferreira -Date: Wed, 12 Jun 2024 01:20:59 +0100 -Subject: [PATCH 08/11] libquadmath: Add libquadmath to the toolchain - -This commit makes the libquadmath library available to the GCC -toolchain. This library is important for libraries such as -Boost.charconv - -Signed-off-by: Carlos Miguel Ferreira -Link: https://github.com/openwrt/openwrt/pull/15637 -Signed-off-by: Christian Marangi ---- - package/libs/toolchain/Makefile | 41 +++++++++++++++++++++++++++++++++ - 1 file changed, 41 insertions(+) - -diff --git a/package/libs/toolchain/Makefile b/package/libs/toolchain/Makefile -index f9f8ac9..8066e35 100644 ---- a/package/libs/toolchain/Makefile -+++ b/package/libs/toolchain/Makefile -@@ -83,6 +83,33 @@ define Package/libatomic/config - endmenu - endef - -+define Package/libquadmath -+$(call Package/gcc/Default) -+ DEPENDS:=@TARGET_x86||TARGET_x86_64 +libgcc -+ TITLE:=Quadmath support library -+ ABI_VERSION:=1 -+endef -+ -+define Package/libquadmath/config -+ menu "Configuration" -+ depends on EXTERNAL_TOOLCHAIN && PACKAGE_libquadmath -+ -+ config LIBQUADMATH_ROOT_DIR -+ string -+ prompt "libquadmath shared library base directory" -+ depends on EXTERNAL_TOOLCHAIN && PACKAGE_libquadmath -+ default TOOLCHAIN_ROOT if !NATIVE_TOOLCHAIN -+ default "/" if NATIVE_TOOLCHAIN -+ -+ config LIBQUADMATH_FILE_SPEC -+ string -+ prompt "libquadmath shared library files (use wildcards)" -+ depends on EXTERNAL_TOOLCHAIN && PACKAGE_libquadmath -+ default "./lib/libquadmath.so.*" -+ -+ endmenu -+endef -+ - define Package/libstdcpp - $(call Package/gcc/Default) - NAME:=libstdc++ -@@ -482,6 +509,11 @@ ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),) - $(CP) $(TOOLCHAIN_DIR)/lib/libatomic.so.* $(1)/lib/ - endef - -+ define Package/libquadmath/install -+ $(INSTALL_DIR) $(1)/lib -+ $(CP) $(TOOLCHAIN_DIR)/lib/libquadmath.so.* $(1)/lib/ -+ endef -+ - define Package/libgfortran/install - $(INSTALL_DIR) $(1)/usr/lib - $(CP) $(TOOLCHAIN_DIR)/lib/libgfortran.so.* $(1)/usr/lib/ -@@ -692,6 +724,14 @@ else - exit 0 - endef - -+ define Package/libquadmath/install -+ for file in $(call qstrip,$(CONFIG_LIBQUADMATH_FILE_SPEC)); do \ -+ $(INSTALL_DIR) $(1)/lib ; \ -+ $(CP) $(call qstrip,$(CONFIG_LIBQUADMATH_ROOT_DIR))/$$$$file $(1)/lib/ ; \ -+ done ; \ -+ exit 0 -+ endef -+ - define Package/libgomp/install - for file in $(call qstrip,$(CONFIG_LIBGOMP_FILE_SPEC)); do \ - $(INSTALL_DIR) $(1)/lib ; \ -@@ -723,6 +763,7 @@ endif - $(eval $(call BuildPackage,libc)) - $(eval $(call BuildPackage,libgcc)) - $(eval $(call BuildPackage,libatomic)) -+$(eval $(call BuildPackage,libquadmath)) - $(eval $(call BuildPackage,libstdcpp)) - $(eval $(call BuildPackage,libasan)) - $(eval $(call BuildPackage,libtsan)) --- -2.43.5 - diff --git a/openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch deleted file mode 100644 index 9e842ae46..000000000 --- a/openwrt/patch/generic/0009-build-kernel-add-out-of-tree-kernel-config.patch +++ /dev/null @@ -1,115 +0,0 @@ -From b30be7ae94d7e846e2037b1f73aaff8d559756ab Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 7 Jul 2024 18:51:18 +0800 -Subject: [PATCH 09/11] build: kernel: add out-of-tree kernel config - -Signed-off-by: sbwml ---- - config/Config-devel.in | 7 ++++ - include/kernel-defaults.mk | 72 ++++++++++++++++++++++++++++++++++++++ - 2 files changed, 79 insertions(+) - -diff --git a/config/Config-devel.in b/config/Config-devel.in -index 9079303..2cbefc2 100644 ---- a/config/Config-devel.in -+++ b/config/Config-devel.in -@@ -102,6 +102,13 @@ menuconfig DEVEL - Enter C compiler name or full pathname i.e.: clang - If not set, uses '$(TARGET_CC)' - -+ config KERNEL_LRNG -+ bool "Kernel LRNG" if DEVEL -+ help -+ If enabled, provides a different approach to /dev/random -+ which is called Linux Random Number Generator (LRNG) to collect -+ entropy within the Linux kernel. -+ - config EXTERNAL_KERNEL_TREE - string "Use external kernel tree" if DEVEL - default "" -diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index b8a1479..408bf2f 100644 ---- a/include/kernel-defaults.mk -+++ b/include/kernel-defaults.mk -@@ -110,6 +110,78 @@ define Kernel/SetNoInitramfs - grep -v INITRAMFS $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set - echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set - echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set -+# CLANG -+ mv $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.old -+ grep -v CONFIG_LTO $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set -+ifneq (,$(findstring clang,$(KERNEL_CC))) -+ echo 'CONFIG_LTO=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LTO_CLANG=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LTO_CLANG_FULL=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_HAS_LTO_CLANG=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_RANDSTRUCT_NONE=y' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_CFI_CLANG is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LTO_CLANG_THIN is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LTO_NONE is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_RANDSTRUCT_FULL is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_RELR is not set' >> $(LINUX_DIR)/.config.set -+endif -+# BTF -+ifeq ($(call qstrip,$(CONFIG_KERNEL_BPF_EVENTS)),y) -+ echo 'CONFIG_DEBUG_INFO_BTF_MODULES=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_PROBE_EVENTS_BTF_ARGS=y' >> $(LINUX_DIR)/.config.set -+endif -+# LRNG -+ifeq ($(call qstrip,$(CONFIG_KERNEL_LRNG)),y) -+ echo 'CONFIG_LRNG=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_AUTO_SELECTED=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_COLLECTION_SIZE_1024=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_CONTINUOUS_COMPRESSION_ENABLED=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_CPU=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_CPU_ENTROPY_RATE=8' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_DEV_IF=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_DFLT_DRNG_CHACHA20=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_IRQ=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_IRQ_DFLT_TIMER_ES=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_IRQ_ENTROPY_RATE=256' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_JENT=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_JENT_ENTROPY_BLOCKS=128' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_128=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_JENT_ENTROPY_RATE=16' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_KCAPI_IF=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_RUNTIME_ES_CONFIG=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_SCHED=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_SCHED_ENTROPY_RATE=4294967295' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_SWITCH_DRNG=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_SWITCH_HASH=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION=y' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_AIS2031_NTG1_SEEDING_STRATEGY is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_COLLECTION_SIZE_2048 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_COLLECTION_SIZE_256 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_COLLECTION_SIZE_4096 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_COLLECTION_SIZE_512 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_COLLECTION_SIZE_8192 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_CONTINUOUS_COMPRESSION_DISABLED is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_DFLT_DRNG_DRBG is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_DFLT_DRNG_KCAPI is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_HASH_KCAPI is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_HEALTH_TESTS is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_HWRAND_IF is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_DISABLED is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_1024 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_256 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_32 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_512 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_JENT_ENTROPY_BLOCKS_NO_64 is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_SCHED_DFLT_TIMER_ES is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_SELFTEST is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_SWITCH_DRBG is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_SWITCH_DRNG_KCAPI is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LRNG_TESTING_MENU is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_RANDOM_DEFAULT_IMPL is not set' >> $(LINUX_DIR)/.config.set -+else -+ echo '# CONFIG_LRNG is not set' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_RANDOM_DEFAULT_IMPL=y' >> $(LINUX_DIR)/.config.set -+endif - endef - - define Kernel/Configure/Default --- -2.43.5 - diff --git a/openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch deleted file mode 100644 index 590380f1b..000000000 --- a/openwrt/patch/generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch +++ /dev/null @@ -1,25 +0,0 @@ -From c6f2d815fb9c4ed906831fb89d4a0bac4c00df3f Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sat, 21 Sep 2024 04:08:14 +0800 -Subject: [PATCH 10/11] include: kernel: add miss config for linux-6.11 - -Signed-off-by: sbwml ---- - include/kernel-defaults.mk | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index 408bf2f..8422004 100644 ---- a/include/kernel-defaults.mk -+++ b/include/kernel-defaults.mk -@@ -110,6 +110,7 @@ define Kernel/SetNoInitramfs - grep -v INITRAMFS $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set - echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set - echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_FSCACHE is not set' >> $(LINUX_DIR)/.config.set - # CLANG - mv $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.old - grep -v CONFIG_LTO $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set --- -2.43.5 - diff --git a/openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch b/openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch deleted file mode 100644 index fcd30a405..000000000 --- a/openwrt/patch/generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch +++ /dev/null @@ -1,36 +0,0 @@ -From dcdf87bf2596f1df7805390df133d429b74892ef Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbyn=C4=9Bk=20Kocur?= -Date: Wed, 31 Jan 2024 15:17:51 +0100 -Subject: [PATCH 11/11] meson: add platform variable to cross-compilation file - -This patch adds the "platform" variable to the meson cross-compilation file for the ARM SoC. This variable is necessary to compile DPDK framework on ARM SoCs.(https://doc.dpdk.org/guides/linux_gsg/cross_build_dpdk_for_arm64.html) ---- - include/meson.mk | 1 + - tools/meson/files/openwrt-cross.txt.in | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/include/meson.mk b/include/meson.mk -index 7d67dcf..5a7c7a3 100644 ---- a/include/meson.mk -+++ b/include/meson.mk -@@ -89,6 +89,7 @@ define Meson/CreateCrossFile - -e "s|@LDFLAGS@|$(foreach FLAG,$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS),'$(FLAG)',)|" \ - -e "s|@ARCH@|$(MESON_ARCH)|" \ - -e "s|@CPU@|$(MESON_CPU)|" \ -+ -e "s|@PLAT@|$(MESON_CPU)|" \ - -e "s|@ENDIAN@|$(if $(CONFIG_BIG_ENDIAN),big,little)|" \ - < $(MESON_DIR)/openwrt-cross.txt.in \ - > $(1) -diff --git a/tools/meson/files/openwrt-cross.txt.in b/tools/meson/files/openwrt-cross.txt.in -index ec4b027..e7cbcd0 100644 ---- a/tools/meson/files/openwrt-cross.txt.in -+++ b/tools/meson/files/openwrt-cross.txt.in -@@ -22,4 +22,5 @@ cpu = '@CPU@' - endian = '@ENDIAN@' - - [properties] -+platform = '@PLAT@' - needs_exe_wrapper = true --- -2.43.5 - diff --git a/openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch b/openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch deleted file mode 100644 index 290d5c712..000000000 --- a/openwrt/patch/generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch +++ /dev/null @@ -1,39 +0,0 @@ -From f30ae23e29ba9a00280dc1498d8dfda373cc1eb9 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Fri, 25 Oct 2024 18:15:41 +0100 -Subject: [PATCH] kernel: enable Multi-Path TCP for !SMALL_FLASH targets - -Expose Kernel's CONFIG_MPTCP option and enable it by default for -!SMALL_FLASH targets. - -Signed-off-by: Daniel Golle ---- - config/Config-kernel.in | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index a262d59..c83337d 100644 ---- a/config/Config-kernel.in -+++ b/config/Config-kernel.in -@@ -1126,6 +1126,18 @@ config KERNEL_PAGE_POOL_STATS - bool "Page pool stats support" - depends on KERNEL_PAGE_POOL - -+config KERNEL_MPTCP -+ bool "Multi-Path TCP support" -+ default y if !SMALL_FLASH -+ help -+ Select this option to enable support for Multi-Path TCP. -+ Increases the compressed kernel size by ~214kB (as of Linux 6.6). -+ -+config KERNEL_MPTCP_IPV6 -+ bool "IPv6 support for Multipath TCP" -+ depends on KERNEL_MPTCP -+ default KERNEL_MPTCP -+ - # - # NFS related symbols - # --- -2.42.0 - diff --git a/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch b/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch deleted file mode 100644 index 4b2febe03..000000000 --- a/openwrt/patch/generic/200-toolchain-gcc-update-to-13.2.patch +++ /dev/null @@ -1,2206 +0,0 @@ -From 5a900bab61fcf9930d13c911004150345cdebc22 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Fri, 16 Feb 2024 23:44:25 +0800 -Subject: [PATCH 1/3] toolchain: gcc: update to 13.2 - -Signed-off-by: sbwml ---- - toolchain/gcc/Config.version | 2 +- - toolchain/gcc/common.mk | 4 +- - ...imization-109585-alias-analysis-typo.patch | 69 - - .../700-RISCV-Inline-subword-atomic-ops.patch | 2021 ----------------- - ...linux-Don-t-add-latomic-with-pthread.patch | 36 - - .../gcc/patches-13.x/910-mbsd_multi.patch | 2 +- - 6 files changed, 4 insertions(+), 2130 deletions(-) - delete mode 100644 toolchain/gcc/patches-13.x/001-rtl-optimization-109585-alias-analysis-typo.patch - delete mode 100644 toolchain/gcc/patches-13.x/700-RISCV-Inline-subword-atomic-ops.patch - delete mode 100644 toolchain/gcc/patches-13.x/701-riscv-linux-Don-t-add-latomic-with-pthread.patch - -diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version -index e40d6b2..92033af 100644 ---- a/toolchain/gcc/Config.version -+++ b/toolchain/gcc/Config.version -@@ -9,7 +9,7 @@ config GCC_VERSION_13 - config GCC_VERSION - string - default "11.3.0" if GCC_VERSION_11 -- default "13.1.0" if GCC_VERSION_13 -+ default "13.2.0" if GCC_VERSION_13 - default "12.3.0" - - config GCC_USE_DEFAULT_VERSION -diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index 31a1492..cdbf9fa 100644 ---- a/toolchain/gcc/common.mk -+++ b/toolchain/gcc/common.mk -@@ -38,8 +38,8 @@ ifeq ($(PKG_VERSION),12.3.0) - PKG_HASH:=949a5d4f99e786421a93b532b22ffab5578de7321369975b91aec97adfda8c3b - endif - --ifeq ($(PKG_VERSION),13.1.0) -- PKG_HASH:=61d684f0aa5e76ac6585ad8898a2427aade8979ed5e7f85492286c4dfc13ee86 -+ifeq ($(PKG_VERSION),13.2.0) -+ PKG_HASH:=e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da - endif - - PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x -diff --git a/toolchain/gcc/patches-13.x/001-rtl-optimization-109585-alias-analysis-typo.patch b/toolchain/gcc/patches-13.x/001-rtl-optimization-109585-alias-analysis-typo.patch -deleted file mode 100644 -index 7f73be4..0000000 ---- a/toolchain/gcc/patches-13.x/001-rtl-optimization-109585-alias-analysis-typo.patch -+++ /dev/null -@@ -1,69 +0,0 @@ --From bb406a6aea336966681927a27f54ee89c4fd4ea1 Mon Sep 17 00:00:00 2001 --From: Richard Biener --Date: Mon, 24 Apr 2023 13:31:07 +0200 --Subject: [PATCH] rtl-optimization/109585 - alias analysis typo -- --When r10-514-gc6b84edb6110dd2b4fb improved access path analysis --it introduced a typo that triggers when there's an access to a --trailing array in the first access path leading to false --disambiguation. -- -- PR rtl-optimization/109585 -- * tree-ssa-alias.cc (aliasing_component_refs_p): Fix typo. -- -- * gcc.dg/torture/pr109585.c: New testcase. -- --(cherry picked from commit 6d4bd27a60447c7505cb4783e675e98a191a8904) ----- -- gcc/testsuite/gcc.dg/torture/pr109585.c | 33 +++++++++++++++++++++++++ -- gcc/tree-ssa-alias.cc | 2 +- -- 2 files changed, 34 insertions(+), 1 deletion(-) -- create mode 100644 gcc/testsuite/gcc.dg/torture/pr109585.c -- ----- /dev/null --+++ b/gcc/testsuite/gcc.dg/torture/pr109585.c --@@ -0,0 +1,33 @@ --+/* { dg-do run } */ --+ --+#include --+ --+struct P { --+ long v; --+ struct P *n; --+}; --+ --+struct F { --+ long x; --+ struct P fam[]; --+}; --+ --+int __attribute__((noipa)) --+f(struct F *f, int i) --+{ --+ struct P *p = f->fam; --+ asm("" : "+r"(f): "r"(p)); --+ p->v = 0; --+ p->n = 0; --+ return f->fam->n != 0; --+} --+ --+int --+main() --+{ --+ struct F *m = malloc (sizeof (long) + 2 * sizeof (struct P)); --+ m->fam[0].n = &m->fam[1]; --+ if (f (m, 0)) --+ abort (); --+ return 0; --+} ----- a/gcc/tree-ssa-alias.cc --+++ b/gcc/tree-ssa-alias.cc --@@ -1330,7 +1330,7 @@ aliasing_component_refs_p (tree ref1, -- /* If we didn't find a common base, try the other way around. */ -- if (cmp_outer <= 0 -- || (end_struct_ref1 --- && compare_type_sizes (TREE_TYPE (end_struct_ref1), type1) <= 0)) --+ && compare_type_sizes (TREE_TYPE (end_struct_ref1), type2) <= 0)) -- { -- int res = aliasing_component_refs_walk (ref2, type2, base2, -- offset2, max_size2, -diff --git a/toolchain/gcc/patches-13.x/700-RISCV-Inline-subword-atomic-ops.patch b/toolchain/gcc/patches-13.x/700-RISCV-Inline-subword-atomic-ops.patch -deleted file mode 100644 -index 752480b..0000000 ---- a/toolchain/gcc/patches-13.x/700-RISCV-Inline-subword-atomic-ops.patch -+++ /dev/null -@@ -1,2021 +0,0 @@ --From f797260adaf52bee0ec0e16190bbefbe1bfc3692 Mon Sep 17 00:00:00 2001 --From: Patrick O'Neill --Date: Tue, 18 Apr 2023 14:33:13 -0700 --Subject: [PATCH] RISCV: Inline subword atomic ops -- --RISC-V has no support for subword atomic operations; code currently --generates libatomic library calls. -- --This patch changes the default behavior to inline subword atomic calls --(using the same logic as the existing library call). --Behavior can be specified using the -minline-atomics and ---mno-inline-atomics command line flags. -- --gcc/libgcc/config/riscv/atomic.c has the same logic implemented in asm. --This will need to stay for backwards compatibility and the ---mno-inline-atomics flag. -- --2023-04-18 Patrick O'Neill -- --gcc/ChangeLog: -- PR target/104338 -- * config/riscv/riscv-protos.h: Add helper function stubs. -- * config/riscv/riscv.cc: Add helper functions for subword masking. -- * config/riscv/riscv.opt: Add command-line flag. -- * config/riscv/sync.md: Add masking logic and inline asm for fetch_and_op, -- fetch_and_nand, CAS, and exchange ops. -- * doc/invoke.texi: Add blurb regarding command-line flag. -- --libgcc/ChangeLog: -- PR target/104338 -- * config/riscv/atomic.c: Add reference to duplicate logic. -- --gcc/testsuite/ChangeLog: -- PR target/104338 -- * gcc.target/riscv/inline-atomics-1.c: New test. -- * gcc.target/riscv/inline-atomics-2.c: New test. -- * gcc.target/riscv/inline-atomics-3.c: New test. -- * gcc.target/riscv/inline-atomics-4.c: New test. -- * gcc.target/riscv/inline-atomics-5.c: New test. -- * gcc.target/riscv/inline-atomics-6.c: New test. -- * gcc.target/riscv/inline-atomics-7.c: New test. -- * gcc.target/riscv/inline-atomics-8.c: New test. -- --Signed-off-by: Patrick O'Neill --Signed-off-by: Palmer Dabbelt ----- -- gcc/config/riscv/riscv-protos.h | 2 + -- gcc/config/riscv/riscv.cc | 49 ++ -- gcc/config/riscv/riscv.opt | 4 + -- gcc/config/riscv/sync.md | 301 +++++++++ -- gcc/doc/invoke.texi | 10 +- -- .../gcc.target/riscv/inline-atomics-1.c | 18 + -- .../gcc.target/riscv/inline-atomics-2.c | 9 + -- .../gcc.target/riscv/inline-atomics-3.c | 569 ++++++++++++++++++ -- .../gcc.target/riscv/inline-atomics-4.c | 566 +++++++++++++++++ -- .../gcc.target/riscv/inline-atomics-5.c | 87 +++ -- .../gcc.target/riscv/inline-atomics-6.c | 87 +++ -- .../gcc.target/riscv/inline-atomics-7.c | 69 +++ -- .../gcc.target/riscv/inline-atomics-8.c | 69 +++ -- libgcc/config/riscv/atomic.c | 2 + -- 14 files changed, 1841 insertions(+), 1 deletion(-) -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-1.c -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-2.c -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-3.c -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-4.c -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-5.c -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-6.c -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-7.c -- create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-8.c -- ----- a/gcc/config/riscv/riscv-protos.h --+++ b/gcc/config/riscv/riscv-protos.h --@@ -79,6 +79,8 @@ extern void riscv_reinit (void); -- extern poly_uint64 riscv_regmode_natural_size (machine_mode); -- extern bool riscv_v_ext_vector_mode_p (machine_mode); -- extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT); --+extern void riscv_subword_address (rtx, rtx *, rtx *, rtx *, rtx *); --+extern void riscv_lshift_subword (machine_mode, rtx, rtx, rtx *); -- -- /* Routines implemented in riscv-c.cc. */ -- void riscv_cpu_cpp_builtins (cpp_reader *); ----- a/gcc/config/riscv/riscv.cc --+++ b/gcc/config/riscv/riscv.cc --@@ -7143,6 +7143,55 @@ riscv_zero_call_used_regs (HARD_REG_SET -- & ~zeroed_hardregs); -- } -- --+/* Given memory reference MEM, expand code to compute the aligned --+ memory address, shift and mask values and store them into --+ *ALIGNED_MEM, *SHIFT, *MASK and *NOT_MASK. */ --+ --+void --+riscv_subword_address (rtx mem, rtx *aligned_mem, rtx *shift, rtx *mask, --+ rtx *not_mask) --+{ --+ /* Align the memory address to a word. */ --+ rtx addr = force_reg (Pmode, XEXP (mem, 0)); --+ --+ rtx addr_mask = gen_int_mode (-4, Pmode); --+ --+ rtx aligned_addr = gen_reg_rtx (Pmode); --+ emit_move_insn (aligned_addr, gen_rtx_AND (Pmode, addr, addr_mask)); --+ --+ *aligned_mem = change_address (mem, SImode, aligned_addr); --+ --+ /* Calculate the shift amount. */ --+ emit_move_insn (*shift, gen_rtx_AND (SImode, gen_lowpart (SImode, addr), --+ gen_int_mode (3, SImode))); --+ emit_move_insn (*shift, gen_rtx_ASHIFT (SImode, *shift, --+ gen_int_mode (3, SImode))); --+ --+ /* Calculate the mask. */ --+ int unshifted_mask = GET_MODE_MASK (GET_MODE (mem)); --+ --+ emit_move_insn (*mask, gen_int_mode (unshifted_mask, SImode)); --+ --+ emit_move_insn (*mask, gen_rtx_ASHIFT (SImode, *mask, --+ gen_lowpart (QImode, *shift))); --+ --+ emit_move_insn (*not_mask, gen_rtx_NOT(SImode, *mask)); --+} --+ --+/* Leftshift a subword within an SImode register. */ --+ --+void --+riscv_lshift_subword (machine_mode mode, rtx value, rtx shift, --+ rtx *shifted_value) --+{ --+ rtx value_reg = gen_reg_rtx (SImode); --+ emit_move_insn (value_reg, simplify_gen_subreg (SImode, value, --+ mode, 0)); --+ --+ emit_move_insn(*shifted_value, gen_rtx_ASHIFT (SImode, value_reg, --+ gen_lowpart (QImode, shift))); --+} --+ -- /* Initialize the GCC target structure. */ -- #undef TARGET_ASM_ALIGNED_HI_OP -- #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" ----- a/gcc/config/riscv/riscv.opt --+++ b/gcc/config/riscv/riscv.opt --@@ -238,6 +238,10 @@ int riscv_sv_subext -- TargetVariable -- int riscv_xthead_subext -- --+minline-atomics --+Target Var(TARGET_INLINE_SUBWORD_ATOMIC) Init(1) --+Always inline subword atomic operations. --+ -- Enum -- Name(isa_spec_class) Type(enum riscv_isa_spec_class) -- Supported ISA specs (for use with the -misa-spec= option): ----- a/gcc/config/riscv/sync.md --+++ b/gcc/config/riscv/sync.md --@@ -21,8 +21,11 @@ -- -- (define_c_enum "unspec" [ -- UNSPEC_COMPARE_AND_SWAP --+ UNSPEC_COMPARE_AND_SWAP_SUBWORD -- UNSPEC_SYNC_OLD_OP --+ UNSPEC_SYNC_OLD_OP_SUBWORD -- UNSPEC_SYNC_EXCHANGE --+ UNSPEC_SYNC_EXCHANGE_SUBWORD -- UNSPEC_ATOMIC_STORE -- UNSPEC_MEMORY_BARRIER -- ]) --@@ -91,6 +94,135 @@ -- [(set_attr "type" "atomic") -- (set (attr "length") (const_int 8))]) -- --+(define_insn "subword_atomic_fetch_strong_" --+ [(set (match_operand:SI 0 "register_operand" "=&r") ;; old value at mem --+ (match_operand:SI 1 "memory_operand" "+A")) ;; mem location --+ (set (match_dup 1) --+ (unspec_volatile:SI --+ [(any_atomic:SI (match_dup 1) --+ (match_operand:SI 2 "register_operand" "rI")) ;; value for op --+ (match_operand:SI 3 "register_operand" "rI")] ;; mask --+ UNSPEC_SYNC_OLD_OP_SUBWORD)) --+ (match_operand:SI 4 "register_operand" "rI") ;; not_mask --+ (clobber (match_scratch:SI 5 "=&r")) ;; tmp_1 --+ (clobber (match_scratch:SI 6 "=&r"))] ;; tmp_2 --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+ { --+ return "1:\;" --+ "lr.w.aq\t%0, %1\;" --+ "\t%5, %0, %2\;" --+ "and\t%5, %5, %3\;" --+ "and\t%6, %0, %4\;" --+ "or\t%6, %6, %5\;" --+ "sc.w.rl\t%5, %6, %1\;" --+ "bnez\t%5, 1b"; --+ } --+ [(set (attr "length") (const_int 28))]) --+ --+(define_expand "atomic_fetch_nand" --+ [(match_operand:SHORT 0 "register_operand") ;; old value at mem --+ (not:SHORT (and:SHORT (match_operand:SHORT 1 "memory_operand") ;; mem location --+ (match_operand:SHORT 2 "reg_or_0_operand"))) ;; value for op --+ (match_operand:SI 3 "const_int_operand")] ;; model --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+{ --+ /* We have no QImode/HImode atomics, so form a mask, then use --+ subword_atomic_fetch_strong_nand to implement a LR/SC version of the --+ operation. */ --+ --+ /* Logic duplicated in gcc/libgcc/config/riscv/atomic.c for use when inlining --+ is disabled */ --+ --+ rtx old = gen_reg_rtx (SImode); --+ rtx mem = operands[1]; --+ rtx value = operands[2]; --+ rtx aligned_mem = gen_reg_rtx (SImode); --+ rtx shift = gen_reg_rtx (SImode); --+ rtx mask = gen_reg_rtx (SImode); --+ rtx not_mask = gen_reg_rtx (SImode); --+ --+ riscv_subword_address (mem, &aligned_mem, &shift, &mask, ¬_mask); --+ --+ rtx shifted_value = gen_reg_rtx (SImode); --+ riscv_lshift_subword (mode, value, shift, &shifted_value); --+ --+ emit_insn (gen_subword_atomic_fetch_strong_nand (old, aligned_mem, --+ shifted_value, --+ mask, not_mask)); --+ --+ emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old, --+ gen_lowpart (QImode, shift))); --+ --+ emit_move_insn (operands[0], gen_lowpart (mode, old)); --+ --+ DONE; --+}) --+ --+(define_insn "subword_atomic_fetch_strong_nand" --+ [(set (match_operand:SI 0 "register_operand" "=&r") ;; old value at mem --+ (match_operand:SI 1 "memory_operand" "+A")) ;; mem location --+ (set (match_dup 1) --+ (unspec_volatile:SI --+ [(not:SI (and:SI (match_dup 1) --+ (match_operand:SI 2 "register_operand" "rI"))) ;; value for op --+ (match_operand:SI 3 "register_operand" "rI")] ;; mask --+ UNSPEC_SYNC_OLD_OP_SUBWORD)) --+ (match_operand:SI 4 "register_operand" "rI") ;; not_mask --+ (clobber (match_scratch:SI 5 "=&r")) ;; tmp_1 --+ (clobber (match_scratch:SI 6 "=&r"))] ;; tmp_2 --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+ { --+ return "1:\;" --+ "lr.w.aq\t%0, %1\;" --+ "and\t%5, %0, %2\;" --+ "not\t%5, %5\;" --+ "and\t%5, %5, %3\;" --+ "and\t%6, %0, %4\;" --+ "or\t%6, %6, %5\;" --+ "sc.w.rl\t%5, %6, %1\;" --+ "bnez\t%5, 1b"; --+ } --+ [(set (attr "length") (const_int 32))]) --+ --+(define_expand "atomic_fetch_" --+ [(match_operand:SHORT 0 "register_operand") ;; old value at mem --+ (any_atomic:SHORT (match_operand:SHORT 1 "memory_operand") ;; mem location --+ (match_operand:SHORT 2 "reg_or_0_operand")) ;; value for op --+ (match_operand:SI 3 "const_int_operand")] ;; model --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+{ --+ /* We have no QImode/HImode atomics, so form a mask, then use --+ subword_atomic_fetch_strong_ to implement a LR/SC version of the --+ operation. */ --+ --+ /* Logic duplicated in gcc/libgcc/config/riscv/atomic.c for use when inlining --+ is disabled */ --+ --+ rtx old = gen_reg_rtx (SImode); --+ rtx mem = operands[1]; --+ rtx value = operands[2]; --+ rtx aligned_mem = gen_reg_rtx (SImode); --+ rtx shift = gen_reg_rtx (SImode); --+ rtx mask = gen_reg_rtx (SImode); --+ rtx not_mask = gen_reg_rtx (SImode); --+ --+ riscv_subword_address (mem, &aligned_mem, &shift, &mask, ¬_mask); --+ --+ rtx shifted_value = gen_reg_rtx (SImode); --+ riscv_lshift_subword (mode, value, shift, &shifted_value); --+ --+ emit_insn (gen_subword_atomic_fetch_strong_ (old, aligned_mem, --+ shifted_value, --+ mask, not_mask)); --+ --+ emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old, --+ gen_lowpart (QImode, shift))); --+ --+ emit_move_insn (operands[0], gen_lowpart (mode, old)); --+ --+ DONE; --+}) --+ -- (define_insn "atomic_exchange" -- [(set (match_operand:GPR 0 "register_operand" "=&r") -- (unspec_volatile:GPR --@@ -104,6 +236,56 @@ -- [(set_attr "type" "atomic") -- (set (attr "length") (const_int 8))]) -- --+(define_expand "atomic_exchange" --+ [(match_operand:SHORT 0 "register_operand") ;; old value at mem --+ (match_operand:SHORT 1 "memory_operand") ;; mem location --+ (match_operand:SHORT 2 "register_operand") ;; value --+ (match_operand:SI 3 "const_int_operand")] ;; model --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+{ --+ rtx old = gen_reg_rtx (SImode); --+ rtx mem = operands[1]; --+ rtx value = operands[2]; --+ rtx aligned_mem = gen_reg_rtx (SImode); --+ rtx shift = gen_reg_rtx (SImode); --+ rtx mask = gen_reg_rtx (SImode); --+ rtx not_mask = gen_reg_rtx (SImode); --+ --+ riscv_subword_address (mem, &aligned_mem, &shift, &mask, ¬_mask); --+ --+ rtx shifted_value = gen_reg_rtx (SImode); --+ riscv_lshift_subword (mode, value, shift, &shifted_value); --+ --+ emit_insn (gen_subword_atomic_exchange_strong (old, aligned_mem, --+ shifted_value, not_mask)); --+ --+ emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old, --+ gen_lowpart (QImode, shift))); --+ --+ emit_move_insn (operands[0], gen_lowpart (mode, old)); --+ DONE; --+}) --+ --+(define_insn "subword_atomic_exchange_strong" --+ [(set (match_operand:SI 0 "register_operand" "=&r") ;; old value at mem --+ (match_operand:SI 1 "memory_operand" "+A")) ;; mem location --+ (set (match_dup 1) --+ (unspec_volatile:SI --+ [(match_operand:SI 2 "reg_or_0_operand" "rI") ;; value --+ (match_operand:SI 3 "reg_or_0_operand" "rI")] ;; not_mask --+ UNSPEC_SYNC_EXCHANGE_SUBWORD)) --+ (clobber (match_scratch:SI 4 "=&r"))] ;; tmp_1 --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+ { --+ return "1:\;" --+ "lr.w.aq\t%0, %1\;" --+ "and\t%4, %0, %3\;" --+ "or\t%4, %4, %2\;" --+ "sc.w.rl\t%4, %4, %1\;" --+ "bnez\t%4, 1b"; --+ } --+ [(set (attr "length") (const_int 20))]) --+ -- (define_insn "atomic_cas_value_strong" -- [(set (match_operand:GPR 0 "register_operand" "=&r") -- (match_operand:GPR 1 "memory_operand" "+A")) --@@ -153,6 +335,125 @@ -- DONE; -- }) -- --+(define_expand "atomic_compare_and_swap" --+ [(match_operand:SI 0 "register_operand") ;; bool output --+ (match_operand:SHORT 1 "register_operand") ;; val output --+ (match_operand:SHORT 2 "memory_operand") ;; memory --+ (match_operand:SHORT 3 "reg_or_0_operand") ;; expected value --+ (match_operand:SHORT 4 "reg_or_0_operand") ;; desired value --+ (match_operand:SI 5 "const_int_operand") ;; is_weak --+ (match_operand:SI 6 "const_int_operand") ;; mod_s --+ (match_operand:SI 7 "const_int_operand")] ;; mod_f --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+{ --+ emit_insn (gen_atomic_cas_value_strong (operands[1], operands[2], --+ operands[3], operands[4], --+ operands[6], operands[7])); --+ --+ rtx val = gen_reg_rtx (SImode); --+ if (operands[1] != const0_rtx) --+ emit_move_insn (val, gen_rtx_SIGN_EXTEND (SImode, operands[1])); --+ else --+ emit_move_insn (val, const0_rtx); --+ --+ rtx exp = gen_reg_rtx (SImode); --+ if (operands[3] != const0_rtx) --+ emit_move_insn (exp, gen_rtx_SIGN_EXTEND (SImode, operands[3])); --+ else --+ emit_move_insn (exp, const0_rtx); --+ --+ rtx compare = val; --+ if (exp != const0_rtx) --+ { --+ rtx difference = gen_rtx_MINUS (SImode, val, exp); --+ compare = gen_reg_rtx (SImode); --+ emit_move_insn (compare, difference); --+ } --+ --+ if (word_mode != SImode) --+ { --+ rtx reg = gen_reg_rtx (word_mode); --+ emit_move_insn (reg, gen_rtx_SIGN_EXTEND (word_mode, compare)); --+ compare = reg; --+ } --+ --+ emit_move_insn (operands[0], gen_rtx_EQ (SImode, compare, const0_rtx)); --+ DONE; --+}) --+ --+(define_expand "atomic_cas_value_strong" --+ [(match_operand:SHORT 0 "register_operand") ;; val output --+ (match_operand:SHORT 1 "memory_operand") ;; memory --+ (match_operand:SHORT 2 "reg_or_0_operand") ;; expected value --+ (match_operand:SHORT 3 "reg_or_0_operand") ;; desired value --+ (match_operand:SI 4 "const_int_operand") ;; mod_s --+ (match_operand:SI 5 "const_int_operand") ;; mod_f --+ (match_scratch:SHORT 6)] --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+{ --+ /* We have no QImode/HImode atomics, so form a mask, then use --+ subword_atomic_cas_strong to implement a LR/SC version of the --+ operation. */ --+ --+ /* Logic duplicated in gcc/libgcc/config/riscv/atomic.c for use when inlining --+ is disabled */ --+ --+ rtx old = gen_reg_rtx (SImode); --+ rtx mem = operands[1]; --+ rtx aligned_mem = gen_reg_rtx (SImode); --+ rtx shift = gen_reg_rtx (SImode); --+ rtx mask = gen_reg_rtx (SImode); --+ rtx not_mask = gen_reg_rtx (SImode); --+ --+ riscv_subword_address (mem, &aligned_mem, &shift, &mask, ¬_mask); --+ --+ rtx o = operands[2]; --+ rtx n = operands[3]; --+ rtx shifted_o = gen_reg_rtx (SImode); --+ rtx shifted_n = gen_reg_rtx (SImode); --+ --+ riscv_lshift_subword (mode, o, shift, &shifted_o); --+ riscv_lshift_subword (mode, n, shift, &shifted_n); --+ --+ emit_move_insn (shifted_o, gen_rtx_AND (SImode, shifted_o, mask)); --+ emit_move_insn (shifted_n, gen_rtx_AND (SImode, shifted_n, mask)); --+ --+ emit_insn (gen_subword_atomic_cas_strong (old, aligned_mem, --+ shifted_o, shifted_n, --+ mask, not_mask)); --+ --+ emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old, --+ gen_lowpart (QImode, shift))); --+ --+ emit_move_insn (operands[0], gen_lowpart (mode, old)); --+ --+ DONE; --+}) --+ --+(define_insn "subword_atomic_cas_strong" --+ [(set (match_operand:SI 0 "register_operand" "=&r") ;; old value at mem --+ (match_operand:SI 1 "memory_operand" "+A")) ;; mem location --+ (set (match_dup 1) --+ (unspec_volatile:SI [(match_operand:SI 2 "reg_or_0_operand" "rJ") ;; expected value --+ (match_operand:SI 3 "reg_or_0_operand" "rJ")] ;; desired value --+ UNSPEC_COMPARE_AND_SWAP_SUBWORD)) --+ (match_operand:SI 4 "register_operand" "rI") ;; mask --+ (match_operand:SI 5 "register_operand" "rI") ;; not_mask --+ (clobber (match_scratch:SI 6 "=&r"))] ;; tmp_1 --+ "TARGET_ATOMIC && TARGET_INLINE_SUBWORD_ATOMIC" --+ { --+ return "1:\;" --+ "lr.w.aq\t%0, %1\;" --+ "and\t%6, %0, %4\;" --+ "bne\t%6, %z2, 1f\;" --+ "and\t%6, %0, %5\;" --+ "or\t%6, %6, %3\;" --+ "sc.w.rl\t%6, %6, %1\;" --+ "bnez\t%6, 1b\;" --+ "1:"; --+ } --+ [(set (attr "length") (const_int 28))]) --+ -- (define_expand "atomic_test_and_set" -- [(match_operand:QI 0 "register_operand" "") ;; bool output -- (match_operand:QI 1 "memory_operand" "+A") ;; memory ----- a/gcc/doc/invoke.texi --+++ b/gcc/doc/invoke.texi --@@ -1226,7 +1226,8 @@ See RS/6000 and PowerPC Options. -- -mbig-endian -mlittle-endian -- -mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} -- -mstack-protector-guard-offset=@var{offset} ----mcsr-check -mno-csr-check} --+-mcsr-check -mno-csr-check --+-minline-atomics -mno-inline-atomics} -- -- @emph{RL78 Options} -- @gccoptlist{-msim -mmul=none -mmul=g13 -mmul=g14 -mallregs --@@ -29006,6 +29007,13 @@ Do or don't use smaller but slower prolo -- library function calls. The default is to use fast inline prologues and -- epilogues. -- --+@opindex minline-atomics --+@item -minline-atomics --+@itemx -mno-inline-atomics --+Do or don't use smaller but slower subword atomic emulation code that uses --+libatomic function calls. The default is to use fast inline subword atomics --+that do not require libatomic. --+ -- @opindex mshorten-memrefs -- @item -mshorten-memrefs -- @itemx -mno-shorten-memrefs ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-1.c --@@ -0,0 +1,18 @@ --+/* { dg-do compile } */ --+/* { dg-options "-mno-inline-atomics" } */ --+/* { dg-message "note: '__sync_fetch_and_nand' changed semantics in GCC 4.4" "fetch_and_nand" { target *-*-* } 0 } */ --+/* { dg-final { scan-assembler "\tcall\t__sync_fetch_and_add_1" } } */ --+/* { dg-final { scan-assembler "\tcall\t__sync_fetch_and_nand_1" } } */ --+/* { dg-final { scan-assembler "\tcall\t__sync_bool_compare_and_swap_1" } } */ --+ --+char foo; --+char bar; --+char baz; --+ --+int --+main () --+{ --+ __sync_fetch_and_add(&foo, 1); --+ __sync_fetch_and_nand(&bar, 1); --+ __sync_bool_compare_and_swap (&baz, 1, 2); --+} ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-2.c --@@ -0,0 +1,9 @@ --+/* { dg-do compile } */ --+/* Verify that subword atomics do not generate calls. */ --+/* { dg-options "-minline-atomics" } */ --+/* { dg-message "note: '__sync_fetch_and_nand' changed semantics in GCC 4.4" "fetch_and_nand" { target *-*-* } 0 } */ --+/* { dg-final { scan-assembler-not "\tcall\t__sync_fetch_and_add_1" } } */ --+/* { dg-final { scan-assembler-not "\tcall\t__sync_fetch_and_nand_1" } } */ --+/* { dg-final { scan-assembler-not "\tcall\t__sync_bool_compare_and_swap_1" } } */ --+ --+#include "inline-atomics-1.c" --\ No newline at end of file ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-3.c --@@ -0,0 +1,569 @@ --+/* Check all char alignments. */ --+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-op-1.c */ --+/* Test __atomic routines for existence and proper execution on 1 byte --+ values with each valid memory model. */ --+/* { dg-do run } */ --+/* { dg-options "-minline-atomics -Wno-address-of-packed-member" } */ --+ --+/* Test the execution of the __atomic_*OP builtin routines for a char. */ --+ --+extern void abort(void); --+ --+char count, res; --+const char init = ~0; --+ --+struct A --+{ --+ char a; --+ char b; --+ char c; --+ char d; --+} __attribute__ ((packed)) A; --+ --+/* The fetch_op routines return the original value before the operation. */ --+ --+void --+test_fetch_add (char* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_fetch_add (v, count, __ATOMIC_RELAXED) != 0) --+ abort (); --+ --+ if (__atomic_fetch_add (v, 1, __ATOMIC_CONSUME) != 1) --+ abort (); --+ --+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQUIRE) != 2) --+ abort (); --+ --+ if (__atomic_fetch_add (v, 1, __ATOMIC_RELEASE) != 3) --+ abort (); --+ --+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQ_REL) != 4) --+ abort (); --+ --+ if (__atomic_fetch_add (v, 1, __ATOMIC_SEQ_CST) != 5) --+ abort (); --+} --+ --+ --+void --+test_fetch_sub (char* v) --+{ --+ *v = res = 20; --+ count = 0; --+ --+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_RELAXED) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, 1, __ATOMIC_CONSUME) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQUIRE) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, 1, __ATOMIC_RELEASE) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQ_REL) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, 1, __ATOMIC_SEQ_CST) != res--) --+ abort (); --+} --+ --+void --+test_fetch_and (char* v) --+{ --+ *v = init; --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_fetch_and (v, init, __ATOMIC_CONSUME) != 0) --+ abort (); --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ *v = ~*v; --+ if (__atomic_fetch_and (v, init, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST) != 0) --+ abort (); --+} --+ --+void --+test_fetch_nand (char* v) --+{ --+ *v = init; --+ --+ if (__atomic_fetch_nand (v, 0, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, init, __ATOMIC_CONSUME) != init) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, 0, __ATOMIC_ACQUIRE) != 0 ) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, init, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL) != 0) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, 0, __ATOMIC_SEQ_CST) != init) --+ abort (); --+} --+ --+void --+test_fetch_xor (char* v) --+{ --+ *v = init; --+ count = 0; --+ --+ if (__atomic_fetch_xor (v, count, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME) != init) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE) != 0) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_SEQ_CST) != init) --+ abort (); --+} --+ --+void --+test_fetch_or (char* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_fetch_or (v, count, __ATOMIC_RELAXED) != 0) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, 2, __ATOMIC_CONSUME) != 1) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQUIRE) != 3) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, 8, __ATOMIC_RELEASE) != 7) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQ_REL) != 15) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, count, __ATOMIC_SEQ_CST) != 31) --+ abort (); --+} --+ --+/* The OP_fetch routines return the new value after the operation. */ --+ --+void --+test_add_fetch (char* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_RELAXED) != 1) --+ abort (); --+ --+ if (__atomic_add_fetch (v, 1, __ATOMIC_CONSUME) != 2) --+ abort (); --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQUIRE) != 3) --+ abort (); --+ --+ if (__atomic_add_fetch (v, 1, __ATOMIC_RELEASE) != 4) --+ abort (); --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQ_REL) != 5) --+ abort (); --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_SEQ_CST) != 6) --+ abort (); --+} --+ --+ --+void --+test_sub_fetch (char* v) --+{ --+ *v = res = 20; --+ count = 0; --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, 1, __ATOMIC_CONSUME) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQUIRE) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, 1, __ATOMIC_RELEASE) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_SEQ_CST) != --res) --+ abort (); --+} --+ --+void --+test_and_fetch (char* v) --+{ --+ *v = init; --+ --+ if (__atomic_and_fetch (v, 0, __ATOMIC_RELAXED) != 0) --+ abort (); --+ --+ *v = init; --+ if (__atomic_and_fetch (v, init, __ATOMIC_CONSUME) != init) --+ abort (); --+ --+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ *v = ~*v; --+ if (__atomic_and_fetch (v, init, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL) != 0) --+ abort (); --+ --+ *v = ~*v; --+ if (__atomic_and_fetch (v, 0, __ATOMIC_SEQ_CST) != 0) --+ abort (); --+} --+ --+void --+test_nand_fetch (char* v) --+{ --+ *v = init; --+ --+ if (__atomic_nand_fetch (v, 0, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, init, __ATOMIC_CONSUME) != 0) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE) != init) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, init, __ATOMIC_RELEASE) != 0) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, init, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST) != init) --+ abort (); --+} --+ --+ --+ --+void --+test_xor_fetch (char* v) --+{ --+ *v = init; --+ count = 0; --+ --+ if (__atomic_xor_fetch (v, count, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_CONSUME) != 0) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST) != 0) --+ abort (); --+} --+ --+void --+test_or_fetch (char* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_or_fetch (v, count, __ATOMIC_RELAXED) != 1) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, 2, __ATOMIC_CONSUME) != 3) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQUIRE) != 7) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, 8, __ATOMIC_RELEASE) != 15) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQ_REL) != 31) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, count, __ATOMIC_SEQ_CST) != 63) --+ abort (); --+} --+ --+ --+/* Test the OP routines with a result which isn't used. Use both variations --+ within each function. */ --+ --+void --+test_add (char* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ __atomic_add_fetch (v, count, __ATOMIC_RELAXED); --+ if (*v != 1) --+ abort (); --+ --+ __atomic_fetch_add (v, count, __ATOMIC_CONSUME); --+ if (*v != 2) --+ abort (); --+ --+ __atomic_add_fetch (v, 1 , __ATOMIC_ACQUIRE); --+ if (*v != 3) --+ abort (); --+ --+ __atomic_fetch_add (v, 1, __ATOMIC_RELEASE); --+ if (*v != 4) --+ abort (); --+ --+ __atomic_add_fetch (v, count, __ATOMIC_ACQ_REL); --+ if (*v != 5) --+ abort (); --+ --+ __atomic_fetch_add (v, count, __ATOMIC_SEQ_CST); --+ if (*v != 6) --+ abort (); --+} --+ --+ --+void --+test_sub (char* v) --+{ --+ *v = res = 20; --+ count = 0; --+ --+ __atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_fetch_sub (v, count + 1, __ATOMIC_CONSUME); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_sub_fetch (v, 1, __ATOMIC_ACQUIRE); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_fetch_sub (v, 1, __ATOMIC_RELEASE); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_fetch_sub (v, count + 1, __ATOMIC_SEQ_CST); --+ if (*v != --res) --+ abort (); --+} --+ --+void --+test_and (char* v) --+{ --+ *v = init; --+ --+ __atomic_and_fetch (v, 0, __ATOMIC_RELAXED); --+ if (*v != 0) --+ abort (); --+ --+ *v = init; --+ __atomic_fetch_and (v, init, __ATOMIC_CONSUME); --+ if (*v != init) --+ abort (); --+ --+ __atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE); --+ if (*v != 0) --+ abort (); --+ --+ *v = ~*v; --+ __atomic_fetch_and (v, init, __ATOMIC_RELEASE); --+ if (*v != init) --+ abort (); --+ --+ __atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL); --+ if (*v != 0) --+ abort (); --+ --+ *v = ~*v; --+ __atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST); --+ if (*v != 0) --+ abort (); --+} --+ --+void --+test_nand (char* v) --+{ --+ *v = init; --+ --+ __atomic_fetch_nand (v, 0, __ATOMIC_RELAXED); --+ if (*v != init) --+ abort (); --+ --+ __atomic_fetch_nand (v, init, __ATOMIC_CONSUME); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE); --+ if (*v != init) --+ abort (); --+ --+ __atomic_nand_fetch (v, init, __ATOMIC_RELEASE); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL); --+ if (*v != init) --+ abort (); --+ --+ __atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST); --+ if (*v != init) --+ abort (); --+} --+ --+ --+ --+void --+test_xor (char* v) --+{ --+ *v = init; --+ count = 0; --+ --+ __atomic_xor_fetch (v, count, __ATOMIC_RELAXED); --+ if (*v != init) --+ abort (); --+ --+ __atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE); --+ if (*v != init) --+ abort (); --+ --+ __atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL); --+ if (*v != init) --+ abort (); --+ --+ __atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST); --+ if (*v != 0) --+ abort (); --+} --+ --+void --+test_or (char* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ __atomic_or_fetch (v, count, __ATOMIC_RELAXED); --+ if (*v != 1) --+ abort (); --+ --+ count *= 2; --+ __atomic_fetch_or (v, count, __ATOMIC_CONSUME); --+ if (*v != 3) --+ abort (); --+ --+ count *= 2; --+ __atomic_or_fetch (v, 4, __ATOMIC_ACQUIRE); --+ if (*v != 7) --+ abort (); --+ --+ count *= 2; --+ __atomic_fetch_or (v, 8, __ATOMIC_RELEASE); --+ if (*v != 15) --+ abort (); --+ --+ count *= 2; --+ __atomic_or_fetch (v, count, __ATOMIC_ACQ_REL); --+ if (*v != 31) --+ abort (); --+ --+ count *= 2; --+ __atomic_fetch_or (v, count, __ATOMIC_SEQ_CST); --+ if (*v != 63) --+ abort (); --+} --+ --+int --+main () --+{ --+ char* V[] = {&A.a, &A.b, &A.c, &A.d}; --+ --+ for (int i = 0; i < 4; i++) { --+ test_fetch_add (V[i]); --+ test_fetch_sub (V[i]); --+ test_fetch_and (V[i]); --+ test_fetch_nand (V[i]); --+ test_fetch_xor (V[i]); --+ test_fetch_or (V[i]); --+ --+ test_add_fetch (V[i]); --+ test_sub_fetch (V[i]); --+ test_and_fetch (V[i]); --+ test_nand_fetch (V[i]); --+ test_xor_fetch (V[i]); --+ test_or_fetch (V[i]); --+ --+ test_add (V[i]); --+ test_sub (V[i]); --+ test_and (V[i]); --+ test_nand (V[i]); --+ test_xor (V[i]); --+ test_or (V[i]); --+ } --+ --+ return 0; --+} ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-4.c --@@ -0,0 +1,566 @@ --+/* Check all short alignments. */ --+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-op-2.c */ --+/* Test __atomic routines for existence and proper execution on 2 byte --+ values with each valid memory model. */ --+/* { dg-do run } */ --+/* { dg-options "-minline-atomics -Wno-address-of-packed-member" } */ --+ --+/* Test the execution of the __atomic_*OP builtin routines for a short. */ --+ --+extern void abort(void); --+ --+short count, res; --+const short init = ~0; --+ --+struct A --+{ --+ short a; --+ short b; --+} __attribute__ ((packed)) A; --+ --+/* The fetch_op routines return the original value before the operation. */ --+ --+void --+test_fetch_add (short* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_fetch_add (v, count, __ATOMIC_RELAXED) != 0) --+ abort (); --+ --+ if (__atomic_fetch_add (v, 1, __ATOMIC_CONSUME) != 1) --+ abort (); --+ --+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQUIRE) != 2) --+ abort (); --+ --+ if (__atomic_fetch_add (v, 1, __ATOMIC_RELEASE) != 3) --+ abort (); --+ --+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQ_REL) != 4) --+ abort (); --+ --+ if (__atomic_fetch_add (v, 1, __ATOMIC_SEQ_CST) != 5) --+ abort (); --+} --+ --+ --+void --+test_fetch_sub (short* v) --+{ --+ *v = res = 20; --+ count = 0; --+ --+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_RELAXED) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, 1, __ATOMIC_CONSUME) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQUIRE) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, 1, __ATOMIC_RELEASE) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQ_REL) != res--) --+ abort (); --+ --+ if (__atomic_fetch_sub (v, 1, __ATOMIC_SEQ_CST) != res--) --+ abort (); --+} --+ --+void --+test_fetch_and (short* v) --+{ --+ *v = init; --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_fetch_and (v, init, __ATOMIC_CONSUME) != 0) --+ abort (); --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ *v = ~*v; --+ if (__atomic_fetch_and (v, init, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST) != 0) --+ abort (); --+} --+ --+void --+test_fetch_nand (short* v) --+{ --+ *v = init; --+ --+ if (__atomic_fetch_nand (v, 0, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, init, __ATOMIC_CONSUME) != init) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, 0, __ATOMIC_ACQUIRE) != 0 ) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, init, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL) != 0) --+ abort (); --+ --+ if (__atomic_fetch_nand (v, 0, __ATOMIC_SEQ_CST) != init) --+ abort (); --+} --+ --+void --+test_fetch_xor (short* v) --+{ --+ *v = init; --+ count = 0; --+ --+ if (__atomic_fetch_xor (v, count, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME) != init) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE) != 0) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_SEQ_CST) != init) --+ abort (); --+} --+ --+void --+test_fetch_or (short* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_fetch_or (v, count, __ATOMIC_RELAXED) != 0) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, 2, __ATOMIC_CONSUME) != 1) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQUIRE) != 3) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, 8, __ATOMIC_RELEASE) != 7) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQ_REL) != 15) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_fetch_or (v, count, __ATOMIC_SEQ_CST) != 31) --+ abort (); --+} --+ --+/* The OP_fetch routines return the new value after the operation. */ --+ --+void --+test_add_fetch (short* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_RELAXED) != 1) --+ abort (); --+ --+ if (__atomic_add_fetch (v, 1, __ATOMIC_CONSUME) != 2) --+ abort (); --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQUIRE) != 3) --+ abort (); --+ --+ if (__atomic_add_fetch (v, 1, __ATOMIC_RELEASE) != 4) --+ abort (); --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQ_REL) != 5) --+ abort (); --+ --+ if (__atomic_add_fetch (v, count, __ATOMIC_SEQ_CST) != 6) --+ abort (); --+} --+ --+ --+void --+test_sub_fetch (short* v) --+{ --+ *v = res = 20; --+ count = 0; --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, 1, __ATOMIC_CONSUME) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQUIRE) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, 1, __ATOMIC_RELEASE) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL) != --res) --+ abort (); --+ --+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_SEQ_CST) != --res) --+ abort (); --+} --+ --+void --+test_and_fetch (short* v) --+{ --+ *v = init; --+ --+ if (__atomic_and_fetch (v, 0, __ATOMIC_RELAXED) != 0) --+ abort (); --+ --+ *v = init; --+ if (__atomic_and_fetch (v, init, __ATOMIC_CONSUME) != init) --+ abort (); --+ --+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ *v = ~*v; --+ if (__atomic_and_fetch (v, init, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL) != 0) --+ abort (); --+ --+ *v = ~*v; --+ if (__atomic_and_fetch (v, 0, __ATOMIC_SEQ_CST) != 0) --+ abort (); --+} --+ --+void --+test_nand_fetch (short* v) --+{ --+ *v = init; --+ --+ if (__atomic_nand_fetch (v, 0, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, init, __ATOMIC_CONSUME) != 0) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE) != init) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, init, __ATOMIC_RELEASE) != 0) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, init, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST) != init) --+ abort (); --+} --+ --+ --+ --+void --+test_xor_fetch (short* v) --+{ --+ *v = init; --+ count = 0; --+ --+ if (__atomic_xor_fetch (v, count, __ATOMIC_RELAXED) != init) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_CONSUME) != 0) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE) != 0) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_RELEASE) != init) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQ_REL) != init) --+ abort (); --+ --+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST) != 0) --+ abort (); --+} --+ --+void --+test_or_fetch (short* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ if (__atomic_or_fetch (v, count, __ATOMIC_RELAXED) != 1) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, 2, __ATOMIC_CONSUME) != 3) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQUIRE) != 7) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, 8, __ATOMIC_RELEASE) != 15) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQ_REL) != 31) --+ abort (); --+ --+ count *= 2; --+ if (__atomic_or_fetch (v, count, __ATOMIC_SEQ_CST) != 63) --+ abort (); --+} --+ --+ --+/* Test the OP routines with a result which isn't used. Use both variations --+ within each function. */ --+ --+void --+test_add (short* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ __atomic_add_fetch (v, count, __ATOMIC_RELAXED); --+ if (*v != 1) --+ abort (); --+ --+ __atomic_fetch_add (v, count, __ATOMIC_CONSUME); --+ if (*v != 2) --+ abort (); --+ --+ __atomic_add_fetch (v, 1 , __ATOMIC_ACQUIRE); --+ if (*v != 3) --+ abort (); --+ --+ __atomic_fetch_add (v, 1, __ATOMIC_RELEASE); --+ if (*v != 4) --+ abort (); --+ --+ __atomic_add_fetch (v, count, __ATOMIC_ACQ_REL); --+ if (*v != 5) --+ abort (); --+ --+ __atomic_fetch_add (v, count, __ATOMIC_SEQ_CST); --+ if (*v != 6) --+ abort (); --+} --+ --+ --+void --+test_sub (short* v) --+{ --+ *v = res = 20; --+ count = 0; --+ --+ __atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_fetch_sub (v, count + 1, __ATOMIC_CONSUME); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_sub_fetch (v, 1, __ATOMIC_ACQUIRE); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_fetch_sub (v, 1, __ATOMIC_RELEASE); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL); --+ if (*v != --res) --+ abort (); --+ --+ __atomic_fetch_sub (v, count + 1, __ATOMIC_SEQ_CST); --+ if (*v != --res) --+ abort (); --+} --+ --+void --+test_and (short* v) --+{ --+ *v = init; --+ --+ __atomic_and_fetch (v, 0, __ATOMIC_RELAXED); --+ if (*v != 0) --+ abort (); --+ --+ *v = init; --+ __atomic_fetch_and (v, init, __ATOMIC_CONSUME); --+ if (*v != init) --+ abort (); --+ --+ __atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE); --+ if (*v != 0) --+ abort (); --+ --+ *v = ~*v; --+ __atomic_fetch_and (v, init, __ATOMIC_RELEASE); --+ if (*v != init) --+ abort (); --+ --+ __atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL); --+ if (*v != 0) --+ abort (); --+ --+ *v = ~*v; --+ __atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST); --+ if (*v != 0) --+ abort (); --+} --+ --+void --+test_nand (short* v) --+{ --+ *v = init; --+ --+ __atomic_fetch_nand (v, 0, __ATOMIC_RELAXED); --+ if (*v != init) --+ abort (); --+ --+ __atomic_fetch_nand (v, init, __ATOMIC_CONSUME); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE); --+ if (*v != init) --+ abort (); --+ --+ __atomic_nand_fetch (v, init, __ATOMIC_RELEASE); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL); --+ if (*v != init) --+ abort (); --+ --+ __atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST); --+ if (*v != init) --+ abort (); --+} --+ --+ --+ --+void --+test_xor (short* v) --+{ --+ *v = init; --+ count = 0; --+ --+ __atomic_xor_fetch (v, count, __ATOMIC_RELAXED); --+ if (*v != init) --+ abort (); --+ --+ __atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE); --+ if (*v != 0) --+ abort (); --+ --+ __atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE); --+ if (*v != init) --+ abort (); --+ --+ __atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL); --+ if (*v != init) --+ abort (); --+ --+ __atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST); --+ if (*v != 0) --+ abort (); --+} --+ --+void --+test_or (short* v) --+{ --+ *v = 0; --+ count = 1; --+ --+ __atomic_or_fetch (v, count, __ATOMIC_RELAXED); --+ if (*v != 1) --+ abort (); --+ --+ count *= 2; --+ __atomic_fetch_or (v, count, __ATOMIC_CONSUME); --+ if (*v != 3) --+ abort (); --+ --+ count *= 2; --+ __atomic_or_fetch (v, 4, __ATOMIC_ACQUIRE); --+ if (*v != 7) --+ abort (); --+ --+ count *= 2; --+ __atomic_fetch_or (v, 8, __ATOMIC_RELEASE); --+ if (*v != 15) --+ abort (); --+ --+ count *= 2; --+ __atomic_or_fetch (v, count, __ATOMIC_ACQ_REL); --+ if (*v != 31) --+ abort (); --+ --+ count *= 2; --+ __atomic_fetch_or (v, count, __ATOMIC_SEQ_CST); --+ if (*v != 63) --+ abort (); --+} --+ --+int --+main () { --+ short* V[] = {&A.a, &A.b}; --+ --+ for (int i = 0; i < 2; i++) { --+ test_fetch_add (V[i]); --+ test_fetch_sub (V[i]); --+ test_fetch_and (V[i]); --+ test_fetch_nand (V[i]); --+ test_fetch_xor (V[i]); --+ test_fetch_or (V[i]); --+ --+ test_add_fetch (V[i]); --+ test_sub_fetch (V[i]); --+ test_and_fetch (V[i]); --+ test_nand_fetch (V[i]); --+ test_xor_fetch (V[i]); --+ test_or_fetch (V[i]); --+ --+ test_add (V[i]); --+ test_sub (V[i]); --+ test_and (V[i]); --+ test_nand (V[i]); --+ test_xor (V[i]); --+ test_or (V[i]); --+ } --+ --+ return 0; --+} ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-5.c --@@ -0,0 +1,87 @@ --+/* Test __atomic routines for existence and proper execution on 1 byte --+ values with each valid memory model. */ --+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-compare-exchange-1.c */ --+/* { dg-do run } */ --+/* { dg-options "-minline-atomics" } */ --+ --+/* Test the execution of the __atomic_compare_exchange_n builtin for a char. */ --+ --+extern void abort(void); --+ --+char v = 0; --+char expected = 0; --+char max = ~0; --+char desired = ~0; --+char zero = 0; --+ --+#define STRONG 0 --+#define WEAK 1 --+ --+int --+main () --+{ --+ --+ if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != max) --+ abort (); --+ --+ if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != max) --+ abort (); --+ if (v != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ if (v != max) --+ abort (); --+ --+ /* Now test the generic version. */ --+ --+ v = 0; --+ --+ if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != max) --+ abort (); --+ --+ if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != max) --+ abort (); --+ if (v != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ if (v != max) --+ abort (); --+ --+ return 0; --+} ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-6.c --@@ -0,0 +1,87 @@ --+/* Test __atomic routines for existence and proper execution on 2 byte --+ values with each valid memory model. */ --+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-compare-exchange-2.c */ --+/* { dg-do run } */ --+/* { dg-options "-minline-atomics" } */ --+ --+/* Test the execution of the __atomic_compare_exchange_n builtin for a short. */ --+ --+extern void abort(void); --+ --+short v = 0; --+short expected = 0; --+short max = ~0; --+short desired = ~0; --+short zero = 0; --+ --+#define STRONG 0 --+#define WEAK 1 --+ --+int --+main () --+{ --+ --+ if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != max) --+ abort (); --+ --+ if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != max) --+ abort (); --+ if (v != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ if (v != max) --+ abort (); --+ --+ /* Now test the generic version. */ --+ --+ v = 0; --+ --+ if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) --+ abort (); --+ if (expected != max) --+ abort (); --+ --+ if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != max) --+ abort (); --+ if (v != 0) --+ abort (); --+ --+ if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ --+ if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) --+ abort (); --+ if (expected != 0) --+ abort (); --+ if (v != max) --+ abort (); --+ --+ return 0; --+} ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-7.c --@@ -0,0 +1,69 @@ --+/* Test __atomic routines for existence and proper execution on 1 byte --+ values with each valid memory model. */ --+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-exchange-1.c */ --+/* { dg-do run } */ --+/* { dg-options "-minline-atomics" } */ --+ --+/* Test the execution of the __atomic_exchange_n builtin for a char. */ --+ --+extern void abort(void); --+ --+char v, count, ret; --+ --+int --+main () --+{ --+ v = 0; --+ count = 0; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count) --+ abort (); --+ count++; --+ --+ /* Now test the generic version. */ --+ --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ return 0; --+} ----- /dev/null --+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-8.c --@@ -0,0 +1,69 @@ --+/* Test __atomic routines for existence and proper execution on 2 byte --+ values with each valid memory model. */ --+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-exchange-2.c */ --+/* { dg-do run } */ --+/* { dg-options "-minline-atomics" } */ --+ --+/* Test the execution of the __atomic_X builtin for a short. */ --+ --+extern void abort(void); --+ --+short v, count, ret; --+ --+int --+main () --+{ --+ v = 0; --+ count = 0; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count) --+ abort (); --+ count++; --+ --+ if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count) --+ abort (); --+ count++; --+ --+ /* Now test the generic version. */ --+ --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); --+ if (ret != count - 1 || v != count) --+ abort (); --+ count++; --+ --+ return 0; --+} ----- a/libgcc/config/riscv/atomic.c --+++ b/libgcc/config/riscv/atomic.c --@@ -30,6 +30,8 @@ see the files COPYING3 and COPYING.RUNTI -- #define INVERT "not %[tmp1], %[tmp1]\n\t" -- #define DONT_INVERT "" -- --+/* Logic duplicated in gcc/gcc/config/riscv/sync.md for use when inlining is enabled */ --+ -- #define GENERATE_FETCH_AND_OP(type, size, opname, insn, invert, cop) \ -- type __sync_fetch_and_ ## opname ## _ ## size (type *p, type v) \ -- { \ -diff --git a/toolchain/gcc/patches-13.x/701-riscv-linux-Don-t-add-latomic-with-pthread.patch b/toolchain/gcc/patches-13.x/701-riscv-linux-Don-t-add-latomic-with-pthread.patch -deleted file mode 100644 -index 328c7be..0000000 ---- a/toolchain/gcc/patches-13.x/701-riscv-linux-Don-t-add-latomic-with-pthread.patch -+++ /dev/null -@@ -1,36 +0,0 @@ --From 203f3060dd363361b172f7295f42bb6bf5ac0b3b Mon Sep 17 00:00:00 2001 --From: Andreas Schwab --Date: Sat, 23 Apr 2022 15:48:42 +0200 --Subject: [PATCH] riscv/linux: Don't add -latomic with -pthread -- --Now that we have support for inline subword atomic operations, it is no --longer necessary to link against libatomic. This also fixes testsuite --failures because the framework does not properly set up the linker flags --for finding libatomic. --The use of atomic operations is also independent of the use of libpthread. -- --gcc/ -- * config/riscv/linux.h (LIB_SPEC): Don't redefine. ----- -- gcc/config/riscv/linux.h | 10 ---------- -- 1 file changed, 10 deletions(-) -- ----- a/gcc/config/riscv/linux.h --+++ b/gcc/config/riscv/linux.h --@@ -35,16 +35,6 @@ along with GCC; see the file COPYING3. -- #undef MUSL_DYNAMIC_LINKER -- #define MUSL_DYNAMIC_LINKER "/lib/ld-musl-riscv" XLEN_SPEC MUSL_ABI_SUFFIX ".so.1" -- ---/* Because RISC-V only has word-sized atomics, it requries libatomic where --- others do not. So link libatomic by default, as needed. */ ---#undef LIB_SPEC ---#ifdef LD_AS_NEEDED_OPTION ---#define LIB_SPEC GNU_USER_TARGET_LIB_SPEC \ --- " %{pthread:" LD_AS_NEEDED_OPTION " -latomic " LD_NO_AS_NEEDED_OPTION "}" ---#else ---#define LIB_SPEC GNU_USER_TARGET_LIB_SPEC " -latomic " ---#endif --- -- #define ICACHE_FLUSH_FUNC "__riscv_flush_icache" -- -- #define CPP_SPEC "%{pthread:-D_REENTRANT}" -diff --git a/toolchain/gcc/patches-13.x/910-mbsd_multi.patch b/toolchain/gcc/patches-13.x/910-mbsd_multi.patch -index 8af05c9..4138e79 100644 ---- a/toolchain/gcc/patches-13.x/910-mbsd_multi.patch -+++ b/toolchain/gcc/patches-13.x/910-mbsd_multi.patch -@@ -114,7 +114,7 @@ Date: Tue Jul 31 00:52:27 2007 +0000 - ; On SVR4 targets, it also controls whether or not to emit a - --- a/gcc/doc/invoke.texi - +++ b/gcc/doc/invoke.texi --@@ -10062,6 +10062,17 @@ This option is only supported for C and -+@@ -10065,6 +10065,17 @@ This option is only supported for C and - @option{-Wall} and by @option{-Wpedantic}, which can be disabled with - @option{-Wno-pointer-sign}. - --- -2.43.5 - diff --git a/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch b/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch deleted file mode 100644 index 74a9ec8db..000000000 --- a/openwrt/patch/generic/201-toolchain-gcc-add-support-for-GCC-14.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 9e5c2ff4ad3358ff9ef7584c8a315ddd4995ffe8 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 26 Sep 2024 07:11:19 +0800 -Subject: [PATCH 2/3] toolchain: gcc: add support for GCC 14 - -Signed-off-by: sbwml ---- - toolchain/gcc/Config.in | 3 +++ - toolchain/gcc/Config.version | 5 +++++ - toolchain/gcc/common.mk | 4 ++++ - 3 files changed, 12 insertions(+) - -diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in -index 9156f9c..ca89051 100644 ---- a/toolchain/gcc/Config.in -+++ b/toolchain/gcc/Config.in -@@ -14,6 +14,9 @@ choice - - config GCC_USE_VERSION_13 - bool "gcc 13.x" -+ -+ config GCC_USE_VERSION_14 -+ bool "gcc 14.x" - endchoice - - config GCC_USE_GRAPHITE -diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version -index 92033af..7ff5bc0 100644 ---- a/toolchain/gcc/Config.version -+++ b/toolchain/gcc/Config.version -@@ -6,10 +6,15 @@ config GCC_VERSION_13 - default y if GCC_USE_VERSION_13 - bool - -+config GCC_VERSION_14 -+ default y if GCC_USE_VERSION_14 -+ bool -+ - config GCC_VERSION - string - default "11.3.0" if GCC_VERSION_11 - default "13.2.0" if GCC_VERSION_13 -+ default "14.2.0" if GCC_VERSION_14 - default "12.3.0" - - config GCC_USE_DEFAULT_VERSION -diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index cdbf9fa..a1a5108 100644 ---- a/toolchain/gcc/common.mk -+++ b/toolchain/gcc/common.mk -@@ -42,6 +42,10 @@ ifeq ($(PKG_VERSION),13.2.0) - PKG_HASH:=e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da - endif - -+ifeq ($(PKG_VERSION),14.2.0) -+ PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 -+endif -+ - PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x - - BUGURL=http://bugs.openwrt.org/ --- -2.43.5 - diff --git a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch deleted file mode 100644 index 2e0bdcc6b..000000000 --- a/openwrt/patch/generic/202-toolchain-gcc-add-support-for-GCC-15.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 8d1db41ed127a9aa614dd5c1cb17c4bb8a7005a0 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 26 Sep 2024 07:12:34 +0800 -Subject: [PATCH 3/3] toolchain: gcc: add support for GCC 15 - -Signed-off-by: sbwml ---- - toolchain/gcc/Config.in | 3 +++ - toolchain/gcc/Config.version | 5 +++++ - toolchain/gcc/common.mk | 10 +++++++++- - 3 files changed, 17 insertions(+), 1 deletion(-) - -diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in -index ca89051..510c813 100644 ---- a/toolchain/gcc/Config.in -+++ b/toolchain/gcc/Config.in -@@ -17,6 +17,9 @@ choice - - config GCC_USE_VERSION_14 - bool "gcc 14.x" -+ -+ config GCC_USE_VERSION_15 -+ bool "gcc 15.x" - endchoice - - config GCC_USE_GRAPHITE -diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version -index 7ff5bc0..7d8ee09 100644 ---- a/toolchain/gcc/Config.version -+++ b/toolchain/gcc/Config.version -@@ -10,11 +10,16 @@ config GCC_VERSION_14 - default y if GCC_USE_VERSION_14 - bool - -+config GCC_VERSION_15 -+ default y if GCC_USE_VERSION_15 -+ bool -+ - config GCC_VERSION - string - default "11.3.0" if GCC_VERSION_11 - default "13.2.0" if GCC_VERSION_13 - default "14.2.0" if GCC_VERSION_14 -+ default "15.0.0" if GCC_VERSION_15 - default "12.3.0" - - config GCC_USE_DEFAULT_VERSION -diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index a1a5108..feae36a 100644 ---- a/toolchain/gcc/common.mk -+++ b/toolchain/gcc/common.mk -@@ -26,7 +26,11 @@ PKG_VERSION:=$(firstword $(subst +, ,$(GCC_VERSION))) - GCC_MAJOR_VERSION:=$(word 1,$(subst ., ,$(PKG_VERSION))) - GCC_DIR:=$(PKG_NAME)-$(PKG_VERSION) - --PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) -+ifeq ($(PKG_VERSION),15.0.0) -+ PKG_SOURCE_URL:=https://us.cooluc.com/gcc/20241103 -+else -+ PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) -+endif - PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz - PKG_CPE_ID:=cpe:/a:gnu:gcc - -@@ -46,6 +50,10 @@ ifeq ($(PKG_VERSION),14.2.0) - PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 - endif - -+ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=da4db21566241844d14b5b2caad4e2cfccbcbe656f10c0b929eea68dfe807ca3 -+endif -+ - PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x - - BUGURL=http://bugs.openwrt.org/ --- -2.43.5 - diff --git a/openwrt/patch/generic/gcc-14/910-mbsd_multi.patch b/openwrt/patch/generic/gcc-14/910-mbsd_multi.patch deleted file mode 100644 index 4138e79bc..000000000 --- a/openwrt/patch/generic/gcc-14/910-mbsd_multi.patch +++ /dev/null @@ -1,146 +0,0 @@ -commit 99368862e44740ff4fd33760893f04e14f9dbdf1 -Author: Felix Fietkau -Date: Tue Jul 31 00:52:27 2007 +0000 - - Port the mbsd_multi patch from freewrt, which adds -fhonour-copts. This will emit warnings in packages that don't use our target cflags properly - - SVN-Revision: 8256 - - This patch brings over a feature from MirBSD: - * -fhonour-copts - If this option is not given, it's warned (depending - on environment variables). This is to catch errors - of misbuilt packages which override CFLAGS themselves. - - This patch was authored by Thorsten Glaser - with copyright assignment to the FSF in effect. - ---- a/gcc/c-family/c-opts.cc -+++ b/gcc/c-family/c-opts.cc -@@ -104,6 +104,9 @@ static size_t include_cursor; - /* Whether any standard preincluded header has been preincluded. */ - static bool done_preinclude; - -+/* Check if a port honours COPTS. */ -+static int honour_copts = 0; -+ - static void handle_OPT_d (const char *); - static void set_std_cxx98 (int); - static void set_std_cxx11 (int); -@@ -475,6 +478,12 @@ c_common_handle_option (size_t scode, co - flag_no_builtin = !value; - break; - -+ case OPT_fhonour_copts: -+ if (c_language == clk_c) { -+ honour_copts++; -+ } -+ break; -+ - case OPT_fconstant_string_class_: - constant_string_class_name = arg; - break; -@@ -1228,6 +1237,47 @@ c_common_init (void) - return false; - } - -+ if (c_language == clk_c) { -+ char *ev = getenv ("GCC_HONOUR_COPTS"); -+ int evv; -+ if (ev == NULL) -+ evv = -1; -+ else if ((*ev == '0') || (*ev == '\0')) -+ evv = 0; -+ else if (*ev == '1') -+ evv = 1; -+ else if (*ev == '2') -+ evv = 2; -+ else if (*ev == 's') -+ evv = -1; -+ else { -+ warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1"); -+ evv = 1; /* maybe depend this on something like MIRBSD_NATIVE? */ -+ } -+ if (evv == 1) { -+ if (honour_copts == 0) { -+ error ("someone does not honour COPTS at all in lenient mode"); -+ return false; -+ } else if (honour_copts != 1) { -+ warning (0, "someone does not honour COPTS correctly, passed %d times", -+ honour_copts); -+ } -+ } else if (evv == 2) { -+ if (honour_copts == 0) { -+ error ("someone does not honour COPTS at all in strict mode"); -+ return false; -+ } else if (honour_copts != 1) { -+ error ("someone does not honour COPTS correctly, passed %d times", -+ honour_copts); -+ return false; -+ } -+ } else if (evv == 0) { -+ if (honour_copts != 1) -+ inform (UNKNOWN_LOCATION, "someone does not honour COPTS correctly, passed %d times", -+ honour_copts); -+ } -+ } -+ - return true; - } - ---- a/gcc/c-family/c.opt -+++ b/gcc/c-family/c.opt -@@ -1837,6 +1837,9 @@ C++ ObjC++ Optimization Alias(fexception - fhonor-std - C++ ObjC++ WarnRemoved - -+fhonour-copts -+C ObjC C++ ObjC++ RejectNegative -+ - fhosted - C ObjC - Assume normal C execution environment. ---- a/gcc/common.opt -+++ b/gcc/common.opt -@@ -1801,6 +1801,9 @@ fharden-conditional-branches - Common Var(flag_harden_conditional_branches) Optimization - Harden conditional branches by checking reversed conditions. - -+fhonour-copts -+Common RejectNegative -+ - ; Nonzero means ignore `#ident' directives. 0 means handle them. - ; Generate position-independent code for executables if possible - ; On SVR4 targets, it also controls whether or not to emit a ---- a/gcc/doc/invoke.texi -+++ b/gcc/doc/invoke.texi -@@ -10065,6 +10065,17 @@ This option is only supported for C and - @option{-Wall} and by @option{-Wpedantic}, which can be disabled with - @option{-Wno-pointer-sign}. - -+@item -fhonour-copts -+@opindex fhonour-copts -+If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not -+given at least once, and warn if it is given more than once. -+If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not -+given exactly once. -+If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option -+is not given exactly once. -+The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}. -+This flag and environment variable only affect the C language. -+ - @opindex Wstack-protector - @opindex Wno-stack-protector - @item -Wstack-protector ---- a/gcc/opts.cc -+++ b/gcc/opts.cc -@@ -2767,6 +2767,9 @@ common_handle_option (struct gcc_options - add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg); - break; - -+ case OPT_fhonour_copts: -+ break; -+ - case OPT_Werror: - dc->warning_as_error_requested = value; - break; diff --git a/openwrt/patch/generic/gcc-15/970-macos_arm64-building-fix.patch b/openwrt/patch/generic/gcc-15/970-macos_arm64-building-fix.patch deleted file mode 100644 index 042a92676..000000000 --- a/openwrt/patch/generic/gcc-15/970-macos_arm64-building-fix.patch +++ /dev/null @@ -1,45 +0,0 @@ -commit 9c6e71079b46ad5433165feaa2001450f2017b56 -Author: Przemysław Buczkowski -Date: Mon Aug 16 13:16:21 2021 +0100 - - GCC: Patch for Apple Silicon compatibility - - This patch fixes a linker error occuring when compiling - the cross-compiler on macOS and ARM64 architecture. - - Adapted from: - https://github.com/richfelker/musl-cross-make/issues/116#issuecomment-823612404 - - Change-Id: Ia3ee98a163bbb62689f42e2da83a5ef36beb0913 - Reviewed-on: https://review.haiku-os.org/c/buildtools/+/4329 - Reviewed-by: John Scipione - Reviewed-by: Adrien Destugues - ---- a/gcc/config/aarch64/aarch64.h -+++ b/gcc/config/aarch64/aarch64.h -@@ -1410,7 +1410,7 @@ extern enum aarch64_code_model aarch64_cmodel; - - /* Extra specs when building a native AArch64-hosted compiler. - Option rewriting rules based on host system. */ --#if defined(__aarch64__) -+#if defined(__aarch64__) && ! defined(__APPLE__) - extern const char *host_detect_local_cpu (int argc, const char **argv); - #define HAVE_LOCAL_CPU_DETECT - # define EXTRA_SPEC_FUNCTIONS \ ---- a/gcc/config/host-darwin.cc -+++ b/gcc/config/host-darwin.cc -@@ -23,6 +23,8 @@ - #include "options.h" - #include "diagnostic-core.h" - #include "config/host-darwin.h" -+#include "hosthooks.h" -+#include "hosthooks-def.h" - #include - - /* For Darwin (macOS only) platforms, without ASLR (PIE) enabled on the -@@ -181,3 +183,5 @@ darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, size_t off) - - return 1; - } -+ -+const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; diff --git a/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch b/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch deleted file mode 100644 index fba38b980..000000000 --- a/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 09a3ce6cd32555c06db829f5b56b23b0d47b5ebe Mon Sep 17 00:00:00 2001 -From: Andre Heider -Date: Fri, 27 Jan 2023 16:35:46 +0100 -Subject: [PATCH 1/8] build: add support to use the mold linker for packages - -If CONFIG_USE_MOLD is set, all target packages will use the mold linker. -Except the ones which opted-out via setting PKG_BUILD_FLAGS:=no-mold. - -Signed-off-by: Andre Heider ---- - include/package.mk | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/package.mk b/include/package.mk -index 802e33a..6988e5f 100644 ---- a/include/package.mk -+++ b/include/package.mk -@@ -59,6 +59,11 @@ ifeq ($(call pkg_build_flag,lto,$(if $(CONFIG_USE_LTO),1,0)),1) - TARGET_CXXFLAGS+= -flto=auto -fno-fat-lto-objects - TARGET_LDFLAGS+= -flto=auto -fuse-linker-plugin - endif -+ifdef CONFIG_USE_MOLD -+ ifeq ($(call pkg_build_flag,mold,1),1) -+ TARGET_LINKER:=mold -+ endif -+endif - - include $(INCLUDE_DIR)/hardening.mk - include $(INCLUDE_DIR)/prereq.mk --- -2.43.5 - diff --git a/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch b/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch deleted file mode 100644 index e4f12af50..000000000 --- a/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 9a4fc4505a6cd8e74bd05df02ef8cc88662a8be7 Mon Sep 17 00:00:00 2001 -From: Andre Heider -Date: Fri, 27 Jan 2023 18:22:43 +0100 -Subject: [PATCH 2/8] treewide: opt-out of tree-wide mold usage - -These use linker scripts, which mold doesn't support. - -Signed-off-by: Andre Heider ---- - include/package.mk | 2 +- - package/boot/grub2/Makefile | 2 +- - package/kernel/lantiq/ltq-ifxos/Makefile | 1 + - package/kernel/lantiq/ltq-vdsl-vr11-mei/Makefile | 1 + - package/kernel/lantiq/ltq-vdsl-vr11/Makefile | 1 + - 5 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/include/package.mk b/include/package.mk -index 6988e5f..e992f37 100644 ---- a/include/package.mk -+++ b/include/package.mk -@@ -28,7 +28,7 @@ ifneq (,$(findstring clang,$(KERNEL_CC))) - endif - - PKG_BUILD_FLAGS?= --__unknown_flags=$(filter-out no-iremap no-mips16 gc-sections no-gc-sections lto no-lto,$(PKG_BUILD_FLAGS)) -+__unknown_flags=$(filter-out no-iremap no-mips16 gc-sections no-gc-sections lto no-lto no-mold,$(PKG_BUILD_FLAGS)) - ifneq ($(__unknown_flags),) - $(error unknown PKG_BUILD_FLAGS: $(__unknown_flags)) - endif -diff --git a/package/boot/grub2/Makefile b/package/boot/grub2/Makefile -index 865feee..44dafe1 100644 ---- a/package/boot/grub2/Makefile -+++ b/package/boot/grub2/Makefile -@@ -25,7 +25,7 @@ ifneq ($(BUILD_VARIANT),none) - endif - - PKG_FLAGS:=nonshared --PKG_BUILD_FLAGS:=no-lto -+PKG_BUILD_FLAGS:=no-lto no-mold - - include $(INCLUDE_DIR)/host-build.mk - include $(INCLUDE_DIR)/package.mk -diff --git a/package/kernel/lantiq/ltq-ifxos/Makefile b/package/kernel/lantiq/ltq-ifxos/Makefile -index d941a9d..97f7ca7 100644 ---- a/package/kernel/lantiq/ltq-ifxos/Makefile -+++ b/package/kernel/lantiq/ltq-ifxos/Makefile -@@ -23,6 +23,7 @@ PKG_LICENSE_FILES:=LICENSE - PKG_EXTMOD_SUBDIRS:=src - - PKG_FIXUP:=autoreconf -+PKG_BUILD_FLAGS:=no-mold - - include $(INCLUDE_DIR)/package.mk - -diff --git a/package/kernel/lantiq/ltq-vdsl-vr11-mei/Makefile b/package/kernel/lantiq/ltq-vdsl-vr11-mei/Makefile -index f2dcf8d..7b8a948 100644 ---- a/package/kernel/lantiq/ltq-vdsl-vr11-mei/Makefile -+++ b/package/kernel/lantiq/ltq-vdsl-vr11-mei/Makefile -@@ -25,6 +25,7 @@ PKG_EXTMOD_SUBDIRS:=src - - PKG_FIXUP:=autoreconf - PKG_FLAGS:=nonshared -+PKG_BUILD_FLAGS:=no-mold - - include $(INCLUDE_DIR)/package.mk - -diff --git a/package/kernel/lantiq/ltq-vdsl-vr11/Makefile b/package/kernel/lantiq/ltq-vdsl-vr11/Makefile -index 8284cba..11f96d7 100644 ---- a/package/kernel/lantiq/ltq-vdsl-vr11/Makefile -+++ b/package/kernel/lantiq/ltq-vdsl-vr11/Makefile -@@ -23,6 +23,7 @@ PKG_LICENSE:=GPL-2.0 BSD-2-Clause - PKG_LICENSE_FILES:=LICENSE - - PKG_FIXUP:=autoreconf -+PKG_BUILD_FLAGS:=no-mold - - include $(INCLUDE_DIR)/package.mk - --- -2.43.5 - diff --git a/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch b/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch deleted file mode 100644 index 2e09bcfa5..000000000 --- a/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0de92a05246317259aa4e071689b0fca26e108db Mon Sep 17 00:00:00 2001 -From: Andre Heider -Date: Fri, 27 Jan 2023 17:53:02 +0100 -Subject: [PATCH 3/8] toolchain: add mold as additional linker - -Install it as $tripple-ld.mold in order to use -fuse-ld=mold. - -Signed-off-by: Andre Heider ---- - toolchain/Makefile | 2 +- - toolchain/mold/Makefile | 22 ++++++++++++++++++++++ - 2 files changed, 23 insertions(+), 1 deletion(-) - create mode 100644 toolchain/mold/Makefile - -diff --git a/toolchain/Makefile b/toolchain/Makefile -index c004629..09c16f7 100644 ---- a/toolchain/Makefile -+++ b/toolchain/Makefile -@@ -27,7 +27,7 @@ - curdir:=toolchain - - # subdirectories to descend into --$(curdir)/builddirs := $(if $(CONFIG_GDB),gdb) $(if $(CONFIG_EXTERNAL_TOOLCHAIN),wrapper,kernel-headers binutils gcc/initial gcc/final $(LIBC) fortify-headers) $(if $(CONFIG_NASM),nasm) -+$(curdir)/builddirs := $(if $(CONFIG_GDB),gdb) $(if $(CONFIG_EXTERNAL_TOOLCHAIN),wrapper,kernel-headers binutils gcc/initial gcc/final $(LIBC) fortify-headers) $(if $(CONFIG_NASM),nasm) $(if $(CONFIG_USE_MOLD),mold) - - # builddir dependencies - ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),) -diff --git a/toolchain/mold/Makefile b/toolchain/mold/Makefile -new file mode 100644 -index 0000000..a2acba8 ---- /dev/null -+++ b/toolchain/mold/Makefile -@@ -0,0 +1,22 @@ -+# -+# This is free software, licensed under the GNU General Public License v2. -+# See /LICENSE for more information. -+# -+include $(TOPDIR)/rules.mk -+include $(INCLUDE_DIR)/toolchain-build.mk -+ -+define Host/Configure -+endef -+ -+define Host/Compile -+endef -+ -+define Host/Install -+ $(INSTALL_DIR) $(TOOLCHAIN_DIR)/bin -+ $(INSTALL_BIN) $(STAGING_DIR_HOST)/bin/mold $(TOOLCHAIN_DIR)/bin/$(REAL_GNU_TARGET_NAME)-ld.mold -+endef -+ -+define Host/Clean -+endef -+ -+$(eval $(call HostBuild)) --- -2.43.5 - diff --git a/openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch b/openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch deleted file mode 100644 index ea93b799a..000000000 --- a/openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch +++ /dev/null @@ -1,71 +0,0 @@ -From fdadb3131437c1f64d801ca7cf65c527f69a8a5f Mon Sep 17 00:00:00 2001 -From: Andre Heider -Date: Fri, 27 Jan 2023 17:53:02 +0100 -Subject: [PATCH 4/8] tools: add mold, a modern linker - -mold is a faster drop-in replacement for existing Unix linkers. - -A single binary is able to link various targets, which is why this lives -in tools/. - -All toolchain builds then just need to copy the linker over, hence avoiding -multiple builds with the same outcome. - -Signed-off-by: Andre Heider ---- - tools/Makefile | 2 ++ - tools/mold/Makefile | 22 ++++++++++++++++++++++ - 2 files changed, 24 insertions(+) - create mode 100644 tools/mold/Makefile - -diff --git a/tools/Makefile b/tools/Makefile -index e4afc87..6f27de5 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -91,6 +91,7 @@ tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_TARGET_tegra),y) += cbootimage - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USES_MINOR),y) += kernel2minor - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_SPARSE),y) += sparse - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_LLVM_BUILD),y) += llvm-bpf -+tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_USE_MOLD),y) += mold - - # builddir dependencies - $(curdir)/autoconf/compile := $(curdir)/m4/compile -@@ -122,6 +123,7 @@ $(curdir)/meson/compile := $(curdir)/ninja/compile - $(curdir)/missing-macros/compile := $(curdir)/autoconf/compile - $(curdir)/mkimage/compile += $(curdir)/bison/compile $(curdir)/libressl/compile - $(curdir)/mklibs/compile := $(curdir)/libtool/compile -+$(curdir)/mold/compile := $(curdir)/cmake/compile $(curdir)/zlib/compile $(curdir)/zstd/compile - $(curdir)/mpc/compile := $(curdir)/mpfr/compile $(curdir)/gmp/compile - $(curdir)/mpfr/compile := $(curdir)/gmp/compile - $(curdir)/mtd-utils/compile := $(curdir)/libtool/compile $(curdir)/e2fsprogs/compile $(curdir)/zlib/compile -diff --git a/tools/mold/Makefile b/tools/mold/Makefile -new file mode 100644 -index 0000000..e8fcecb ---- /dev/null -+++ b/tools/mold/Makefile -@@ -0,0 +1,22 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ -+include $(TOPDIR)/rules.mk -+ -+PKG_NAME:=mold -+PKG_VERSION:=1.11.0 -+ -+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -+PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz -+PKG_SOURCE_URL:=https://github.com/rui314/mold/archive/refs/tags -+PKG_HASH:=99318eced81b09a77e4c657011076cc8ec3d4b6867bd324b8677974545bc4d6f -+ -+include $(INCLUDE_DIR)/host-build.mk -+include $(INCLUDE_DIR)/cmake.mk -+ -+CMAKE_HOST_OPTIONS += \ -+ -DMOLD_LTO=ON \ -+ -DMOLD_MOSTLY_STATIC=ON \ -+ -DMOLD_USE_SYSTEM_MIMALLOC=OFF \ -+ -DMOLD_USE_SYSTEM_TBB=OFF -+ -+$(eval $(call HostBuild)) --- -2.43.5 - diff --git a/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch b/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch deleted file mode 100644 index ac6139e93..000000000 --- a/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch +++ /dev/null @@ -1,63 +0,0 @@ -From a5f1c52a8ce42243323a9a79bbd29128af1920a2 Mon Sep 17 00:00:00 2001 -From: Andre Heider -Date: Sat, 28 Jan 2023 21:16:16 +0100 -Subject: [PATCH 5/8] build: replace SSTRIP_ARGS with - SSTRIP_DISCARD_TRAILING_ZEROES - -sstrip only has one functional arg. Make that a bool option, which can -easily depend on other knobs then. - -This is required to be disabled for the mold linker. - -Signed-off-by: Andre Heider ---- - config/Config-build.in | 10 ++++------ - rules.mk | 2 +- - 2 files changed, 5 insertions(+), 7 deletions(-) - -diff --git a/config/Config-build.in b/config/Config-build.in -index fe16d81..a96ed2f 100644 ---- a/config/Config-build.in -+++ b/config/Config-build.in -@@ -190,7 +190,6 @@ menu "Global build settings" - help - This will install binaries stripped using strip from binutils. - -- - config USE_SSTRIP - bool "sstrip" - depends on !USE_GLIBC -@@ -207,13 +206,12 @@ menu "Global build settings" - help - Specifies arguments passed to the strip command when stripping binaries. - -- config SSTRIP_ARGS -- string -- prompt "Sstrip arguments" -+ config SSTRIP_DISCARD_TRAILING_ZEROES -+ bool "Strip trailing zero bytes" - depends on USE_SSTRIP -- default "-z" -+ default y - help -- Specifies arguments passed to the sstrip command when stripping binaries. -+ Use sstrip's -z option to discard trailing zero bytes - - config STRIP_KERNEL_EXPORTS - bool "Strip unnecessary exports from the kernel image" -diff --git a/rules.mk b/rules.mk -index 58c5370..c768ccc 100644 ---- a/rules.mk -+++ b/rules.mk -@@ -325,7 +325,7 @@ else - STRIP:=$(TARGET_CROSS)strip $(call qstrip,$(CONFIG_STRIP_ARGS)) - else - ifneq ($(CONFIG_USE_SSTRIP),) -- STRIP:=$(STAGING_DIR_HOST)/bin/sstrip $(call qstrip,$(CONFIG_SSTRIP_ARGS)) -+ STRIP:=$(STAGING_DIR_HOST)/bin/sstrip $(if $(CONFIG_SSTRIP_DISCARD_TRAILING_ZEROES),-z) - endif - endif - RSTRIP= \ --- -2.43.5 - diff --git a/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch b/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch deleted file mode 100644 index 36a7dbf75..000000000 --- a/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 5840abe142ba5e5e6bfcaa6435887990f2568cec Mon Sep 17 00:00:00 2001 -From: Andre Heider -Date: Fri, 27 Jan 2023 17:13:15 +0100 -Subject: [PATCH 6/8] config: add a knob to use the mold linker for packages - -Building it requires gcc >= 10.2 or clang >= 12. - -Using sstrip with its -z argument can produce non-working binaries, like -a segfaulting `getrandom`, so don't allow that combination. - -Signed-off-by: Andre Heider ---- - config/Config-build.in | 15 ++++++++++++++- - config/check-hostcxx.sh | 12 ++++++++++++ - 2 files changed, 26 insertions(+), 1 deletion(-) - create mode 100755 config/check-hostcxx.sh - -diff --git a/config/Config-build.in b/config/Config-build.in -index a96ed2f..ebfce8a 100644 ---- a/config/Config-build.in -+++ b/config/Config-build.in -@@ -167,6 +167,19 @@ menu "Global build settings" - Adds LTO flags to the CFLAGS and LDFLAGS. - Packages can choose to opt-out via setting PKG_BUILD_FLAGS:=no-lto - -+ config MOLD -+ depends on (aarch64 || arm || i386 || i686 || m68k || powerpc || powerpc64 || sh4 || x86_64) -+ depends on !GCC_USE_VERSION_11 -+ def_bool $(shell, ./config/check-hostcxx.sh 10 2 12) -+ -+ config USE_MOLD -+ bool -+ prompt "Use the mold linker for all packages" -+ depends on MOLD -+ help -+ Link packages with mold, a modern linker -+ Packages can opt-out via setting PKG_BUILD_FLAGS:=no-mold -+ - config IPV6 - def_bool y - -@@ -208,7 +221,7 @@ menu "Global build settings" - - config SSTRIP_DISCARD_TRAILING_ZEROES - bool "Strip trailing zero bytes" -- depends on USE_SSTRIP -+ depends on USE_SSTRIP && !USE_MOLD - default y - help - Use sstrip's -z option to discard trailing zero bytes -diff --git a/config/check-hostcxx.sh b/config/check-hostcxx.sh -new file mode 100755 -index 0000000..442f4cf ---- /dev/null -+++ b/config/check-hostcxx.sh -@@ -0,0 +1,12 @@ -+cat << EOF | "$STAGING_DIR_HOST/bin/g++" -c -x c++ -o /dev/null - >/dev/null 2>&1 -+#if __clang__ -+ #if __clang_major__ < $3 -+ #error "clang too old" -+ #endif -+#else -+ #if __GNUC__ < $1 || (__GNUC__ == $1 && (__GNUC_MINOR__ < $2)) -+ #error "gcc too old" -+ #endif -+#endif -+EOF -+[ $? -eq 0 ] && echo y || echo n --- -2.43.5 - diff --git a/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch b/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch deleted file mode 100644 index 2b2d75558..000000000 --- a/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch +++ /dev/null @@ -1,49 +0,0 @@ -From def4db1bbcef727db78dbce12dc95df9903f135f Mon Sep 17 00:00:00 2001 -From: Andre Heider -Date: Fri, 27 Jan 2023 16:32:31 +0100 -Subject: [PATCH 7/8] rules: prepare to use different linkers - -This explicitely adds the default linker to the target LDFLAGS. - -No functional change intended. - -Signed-off-by: Andre Heider ---- - rules.mk | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/rules.mk b/rules.mk -index c768ccc..ca27583 100644 ---- a/rules.mk -+++ b/rules.mk -@@ -211,6 +211,10 @@ ifndef DUMP - endif - endif - endif -+ -+TARGET_LINKER?=bfd -+TARGET_LDFLAGS+= -fuse-ld=$(TARGET_LINKER) -+ - TARGET_PATH_PKG:=$(STAGING_DIR)/host/bin:$(STAGING_DIR_HOSTPKG)/bin:$(TARGET_PATH) - - ifeq ($(CONFIG_SOFT_FLOAT),y) -@@ -252,6 +256,7 @@ TARGET_RANLIB:=$(TARGET_CROSS)gcc-ranlib - TARGET_NM:=$(TARGET_CROSS)gcc-nm - TARGET_CC:=$(TARGET_CROSS)gcc - TARGET_CXX:=$(TARGET_CROSS)g++ -+TARGET_LD:=$(TARGET_CROSS)ld.$(TARGET_LINKER) - KPATCH:=$(SCRIPT_DIR)/patch-kernel.sh - FILECMD:=$(STAGING_DIR_HOST)/bin/file - SED:=$(STAGING_DIR_HOST)/bin/sed -i -e -@@ -305,7 +310,7 @@ endif - TARGET_CONFIGURE_OPTS = \ - AR="$(TARGET_AR)" \ - AS="$(TARGET_CC) -c $(TARGET_ASFLAGS)" \ -- LD=$(TARGET_CROSS)ld \ -+ LD="$(TARGET_LD)" \ - NM="$(TARGET_NM)" \ - CC="$(TARGET_CC)" \ - GCC="$(TARGET_CC)" \ --- -2.43.5 - diff --git a/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch b/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch deleted file mode 100644 index 834ad6e5c..000000000 --- a/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 76471b08d9e1b5e9686b4444c5db53dd9c56bcfe Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 17 Jul 2024 08:51:39 +0800 -Subject: [PATCH 8/8] tools/mold: update to 2.34.1 - -Signed-off-by: sbwml ---- - tools/mold/Makefile | 7 +++---- - 1 file changed, 3 insertions(+), 4 deletions(-) - -diff --git a/tools/mold/Makefile b/tools/mold/Makefile -index e8fcecb..d0b4443 100644 ---- a/tools/mold/Makefile -+++ b/tools/mold/Makefile -@@ -3,12 +3,11 @@ - include $(TOPDIR)/rules.mk - - PKG_NAME:=mold --PKG_VERSION:=1.11.0 -+PKG_VERSION:=2.34.1 - - PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz --PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz --PKG_SOURCE_URL:=https://github.com/rui314/mold/archive/refs/tags --PKG_HASH:=99318eced81b09a77e4c657011076cc8ec3d4b6867bd324b8677974545bc4d6f -+PKG_SOURCE_URL:=https://codeload.github.com/rui314/mold/tar.gz/v$(PKG_VERSION)? -+PKG_HASH:=a8cf638045b4a4b2697d0bcc77fd96eae93d54d57ad3021bf03b0333a727a59d - - include $(INCLUDE_DIR)/host-build.mk - include $(INCLUDE_DIR)/cmake.mk --- -2.43.5 - diff --git a/openwrt/patch/kernel-6.6/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch b/openwrt/patch/kernel-6.6/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch deleted file mode 100644 index 811224428..000000000 --- a/openwrt/patch/kernel-6.6/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch +++ /dev/null @@ -1,32 +0,0 @@ -From b2277680a6fbb06e7af2b1583d72a587ca4c637a Mon Sep 17 00:00:00 2001 -From: Sumit Gupta -Date: Mon, 29 Aug 2016 14:32:25 +0530 -Subject: [PATCH 1/2] arm64: cpuinfo: Add "model name" in /proc/cpuinfo for - 64bit tasks also - -Removed restriction of displaying model name for 32 bit tasks only. -Because of this Processor details were not displayed in -"System setting -> Details" in Ubuntu model name display is generic -and can be printed for 64 bit also. - -model name : ARMv8 Processor rev X (v8l) - -Signed-off-by: Sumit Gupta ---- - arch/arm64/kernel/cpuinfo.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - ---- a/arch/arm64/kernel/cpuinfo.c -+++ b/arch/arm64/kernel/cpuinfo.c -@@ -189,9 +189,8 @@ static int c_show(struct seq_file *m, vo - * "processor". Give glibc what it expects. - */ - seq_printf(m, "processor\t: %d\n", i); -- if (compat) -- seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", -- MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); -+ seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", -+ MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); - - seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", - loops_per_jiffy / (500000UL/HZ), diff --git a/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch b/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch deleted file mode 100644 index 4b16244de..000000000 --- a/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch +++ /dev/null @@ -1,76 +0,0 @@ -From bc4f29b3a63183e33b7506f742070aaa2e8ccc4e Mon Sep 17 00:00:00 2001 -From: Coco Li -Date: Wed, 29 Nov 2023 07:27:53 +0000 -Subject: [PATCH 1/4] cache: enforce cache groups - -Set up build time warnings to safeguard against future header changes of -organized structs. - -Warning includes: - -1) whether all variables are still in the same cache group -2) whether all the cache groups have the sum of the members size (in the - maximum condition, including all members defined in configs) - -The __cache_group* variables are ignored in kernel-doc check in the -various header files they appear in to enforce the cache groups. - -Suggested-by: Daniel Borkmann -Acked-by: Daniel Borkmann -Signed-off-by: Coco Li -Reviewed-by: Eric Dumazet -Reviewed-by: Shakeel Butt -Signed-off-by: David S. Miller ---- - include/linux/cache.h | 25 +++++++++++++++++++++++++ - scripts/kernel-doc | 5 +++++ - 2 files changed, 30 insertions(+) - ---- a/include/linux/cache.h -+++ b/include/linux/cache.h -@@ -85,6 +85,31 @@ - #define cache_line_size() L1_CACHE_BYTES - #endif - -+#ifndef __cacheline_group_begin -+#define __cacheline_group_begin(GROUP) \ -+ __u8 __cacheline_group_begin__##GROUP[0] -+#endif -+ -+#ifndef __cacheline_group_end -+#define __cacheline_group_end(GROUP) \ -+ __u8 __cacheline_group_end__##GROUP[0] -+#endif -+ -+#ifndef CACHELINE_ASSERT_GROUP_MEMBER -+#define CACHELINE_ASSERT_GROUP_MEMBER(TYPE, GROUP, MEMBER) \ -+ BUILD_BUG_ON(!(offsetof(TYPE, MEMBER) >= \ -+ offsetofend(TYPE, __cacheline_group_begin__##GROUP) && \ -+ offsetofend(TYPE, MEMBER) <= \ -+ offsetof(TYPE, __cacheline_group_end__##GROUP))) -+#endif -+ -+#ifndef CACHELINE_ASSERT_GROUP_SIZE -+#define CACHELINE_ASSERT_GROUP_SIZE(TYPE, GROUP, SIZE) \ -+ BUILD_BUG_ON(offsetof(TYPE, __cacheline_group_end__##GROUP) - \ -+ offsetofend(TYPE, __cacheline_group_begin__##GROUP) > \ -+ SIZE) -+#endif -+ - /* - * Helper to add padding within a struct to ensure data fall into separate - * cachelines. ---- a/scripts/kernel-doc -+++ b/scripts/kernel-doc -@@ -1592,6 +1592,11 @@ sub push_parameter($$$$$) { - $parameterdescs{$param} = "anonymous\n"; - $anon_struct_union = 1; - } -+ elsif ($param =~ "__cacheline_group" ) -+ # handle cache group enforcing variables: they do not need be described in header files -+ { -+ return; # ignore __cacheline_group_begin and __cacheline_group_end -+ } - - # warn if parameter has no description - # (but ignore ones starting with # as these are not parameters diff --git a/openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch b/openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch deleted file mode 100644 index 9643755c0..000000000 --- a/openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch +++ /dev/null @@ -1,192 +0,0 @@ -From b705dec4428b050bdcaad8b5b9d4fddbb5f8e8d4 Mon Sep 17 00:00:00 2001 -From: Coco Li -Date: Wed, 29 Nov 2023 07:27:54 +0000 -Subject: [PATCH 2/4] netns-ipv4: reorganize netns_ipv4 fast path variables - -Reorganize fast path variables on tx-txrx-rx order. -Fastpath cacheline ends after sysctl_tcp_rmem. -There are only read-only variables here. (write is on the control path -and not considered in this case) - -Below data generated with pahole on x86 architecture. -Fast path variables span cache lines before change: 4 -Fast path variables span cache lines after change: 2 - -Suggested-by: Eric Dumazet -Reviewed-by: Wei Wang -Reviewed-by: David Ahern -Signed-off-by: Coco Li -Reviewed-by: Eric Dumazet -Reviewed-by: Shakeel Butt -Signed-off-by: David S. Miller ---- - include/net/netns/ipv4.h | 47 +++++++++++++++++++++++++++------------- - net/core/net_namespace.c | 45 ++++++++++++++++++++++++++++++++++++++ - 2 files changed, 77 insertions(+), 15 deletions(-) - ---- a/include/net/netns/ipv4.h -+++ b/include/net/netns/ipv4.h -@@ -42,6 +42,38 @@ struct inet_timewait_death_row { - struct tcp_fastopen_context; - - struct netns_ipv4 { -+ /* Cacheline organization can be found documented in -+ * Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst. -+ * Please update the document when adding new fields. -+ */ -+ -+ /* TX readonly hotpath cache lines */ -+ __cacheline_group_begin(netns_ipv4_read_tx); -+ u8 sysctl_tcp_early_retrans; -+ u8 sysctl_tcp_tso_win_divisor; -+ u8 sysctl_tcp_tso_rtt_log; -+ u8 sysctl_tcp_autocorking; -+ int sysctl_tcp_min_snd_mss; -+ unsigned int sysctl_tcp_notsent_lowat; -+ int sysctl_tcp_limit_output_bytes; -+ int sysctl_tcp_min_rtt_wlen; -+ int sysctl_tcp_wmem[3]; -+ u8 sysctl_ip_fwd_use_pmtu; -+ __cacheline_group_end(netns_ipv4_read_tx); -+ -+ /* TXRX readonly hotpath cache lines */ -+ __cacheline_group_begin(netns_ipv4_read_txrx); -+ u8 sysctl_tcp_moderate_rcvbuf; -+ __cacheline_group_end(netns_ipv4_read_txrx); -+ -+ /* RX readonly hotpath cache line */ -+ __cacheline_group_begin(netns_ipv4_read_rx); -+ u8 sysctl_ip_early_demux; -+ u8 sysctl_tcp_early_demux; -+ int sysctl_tcp_reordering; -+ int sysctl_tcp_rmem[3]; -+ __cacheline_group_end(netns_ipv4_read_rx); -+ - struct inet_timewait_death_row tcp_death_row; - struct udp_table *udp_table; - -@@ -96,17 +128,14 @@ struct netns_ipv4 { - - u8 sysctl_ip_default_ttl; - u8 sysctl_ip_no_pmtu_disc; -- u8 sysctl_ip_fwd_use_pmtu; - u8 sysctl_ip_fwd_update_priority; - u8 sysctl_ip_nonlocal_bind; - u8 sysctl_ip_autobind_reuse; - /* Shall we try to damage output packets if routing dev changes? */ - u8 sysctl_ip_dynaddr; -- u8 sysctl_ip_early_demux; - #ifdef CONFIG_NET_L3_MASTER_DEV - u8 sysctl_raw_l3mdev_accept; - #endif -- u8 sysctl_tcp_early_demux; - u8 sysctl_udp_early_demux; - - u8 sysctl_nexthop_compat_mode; -@@ -119,7 +148,6 @@ struct netns_ipv4 { - u8 sysctl_tcp_mtu_probing; - int sysctl_tcp_mtu_probe_floor; - int sysctl_tcp_base_mss; -- int sysctl_tcp_min_snd_mss; - int sysctl_tcp_probe_threshold; - u32 sysctl_tcp_probe_interval; - -@@ -132,17 +160,14 @@ struct netns_ipv4 { - u8 sysctl_tcp_syncookies; - u8 sysctl_tcp_migrate_req; - u8 sysctl_tcp_comp_sack_nr; -- int sysctl_tcp_reordering; - u8 sysctl_tcp_retries1; - u8 sysctl_tcp_retries2; - u8 sysctl_tcp_orphan_retries; - u8 sysctl_tcp_tw_reuse; - int sysctl_tcp_fin_timeout; -- unsigned int sysctl_tcp_notsent_lowat; - u8 sysctl_tcp_sack; - u8 sysctl_tcp_window_scaling; - u8 sysctl_tcp_timestamps; -- u8 sysctl_tcp_early_retrans; - u8 sysctl_tcp_recovery; - u8 sysctl_tcp_thin_linear_timeouts; - u8 sysctl_tcp_slow_start_after_idle; -@@ -158,21 +183,13 @@ struct netns_ipv4 { - u8 sysctl_tcp_frto; - u8 sysctl_tcp_nometrics_save; - u8 sysctl_tcp_no_ssthresh_metrics_save; -- u8 sysctl_tcp_moderate_rcvbuf; -- u8 sysctl_tcp_tso_win_divisor; - u8 sysctl_tcp_workaround_signed_windows; -- int sysctl_tcp_limit_output_bytes; - int sysctl_tcp_challenge_ack_limit; -- int sysctl_tcp_min_rtt_wlen; - u8 sysctl_tcp_min_tso_segs; -- u8 sysctl_tcp_tso_rtt_log; -- u8 sysctl_tcp_autocorking; - u8 sysctl_tcp_reflect_tos; - int sysctl_tcp_invalid_ratelimit; - int sysctl_tcp_pacing_ss_ratio; - int sysctl_tcp_pacing_ca_ratio; -- int sysctl_tcp_wmem[3]; -- int sysctl_tcp_rmem[3]; - unsigned int sysctl_tcp_child_ehash_entries; - unsigned long sysctl_tcp_comp_sack_delay_ns; - unsigned long sysctl_tcp_comp_sack_slack_ns; ---- a/net/core/net_namespace.c -+++ b/net/core/net_namespace.c -@@ -1107,11 +1107,56 @@ out: - rtnl_set_sk_err(net, RTNLGRP_NSID, err); - } - -+#ifdef CONFIG_NET_NS -+static void __init netns_ipv4_struct_check(void) -+{ -+ /* TX readonly hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_early_retrans); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_tso_win_divisor); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_tso_rtt_log); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_autocorking); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_min_snd_mss); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_notsent_lowat); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_limit_output_bytes); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_min_rtt_wlen); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_tcp_wmem); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_tx, -+ sysctl_ip_fwd_use_pmtu); -+ CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_tx, 33); -+ -+ /* TXRX readonly hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_txrx, -+ sysctl_tcp_moderate_rcvbuf); -+ CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_txrx, 1); -+ -+ /* RX readonly hotpath cache line */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, -+ sysctl_ip_early_demux); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, -+ sysctl_tcp_early_demux); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, -+ sysctl_tcp_reordering); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct netns_ipv4, netns_ipv4_read_rx, -+ sysctl_tcp_rmem); -+ CACHELINE_ASSERT_GROUP_SIZE(struct netns_ipv4, netns_ipv4_read_rx, 18); -+} -+#endif -+ - void __init net_ns_init(void) - { - struct net_generic *ng; - - #ifdef CONFIG_NET_NS -+ netns_ipv4_struct_check(); - net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), - SMP_CACHE_BYTES, - SLAB_PANIC|SLAB_ACCOUNT, NULL); diff --git a/openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch b/openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch deleted file mode 100644 index 82534acc4..000000000 --- a/openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch +++ /dev/null @@ -1,309 +0,0 @@ -From 0a6d7cbf8e290251bc8f41f02dd4244ee66f4677 Mon Sep 17 00:00:00 2001 -From: Coco Li -Date: Mon, 4 Dec 2023 20:12:30 +0000 -Subject: [PATCH 3/4] net-device: reorganize net_device fast path variables - -Reorganize fast path variables on tx-txrx-rx order -Fastpath variables end after npinfo. - -Below data generated with pahole on x86 architecture. - -Fast path variables span cache lines before change: 12 -Fast path variables span cache lines after change: 4 - -Suggested-by: Eric Dumazet -Signed-off-by: Coco Li -Reviewed-by: Eric Dumazet -Reviewed-by: David Ahern -Link: https://lore.kernel.org/r/20231204201232.520025-2-lixiaoyan@google.com -Signed-off-by: Jakub Kicinski ---- - include/linux/netdevice.h | 116 +++++++++++++++++++++----------------- - net/core/dev.c | 56 ++++++++++++++++++ - 2 files changed, 120 insertions(+), 52 deletions(-) - ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -2089,6 +2089,70 @@ enum netdev_stat_type { - */ - - struct net_device { -+ /* Cacheline organization can be found documented in -+ * Documentation/networking/net_cachelines/net_device.rst. -+ * Please update the document when adding new fields. -+ */ -+ -+ /* TX read-mostly hotpath */ -+ __cacheline_group_begin(net_device_read_tx); -+ unsigned long long priv_flags; -+ const struct net_device_ops *netdev_ops; -+ const struct header_ops *header_ops; -+ struct netdev_queue *_tx; -+ unsigned int real_num_tx_queues; -+ unsigned int gso_max_size; -+ unsigned int gso_ipv4_max_size; -+ u16 gso_max_segs; -+ s16 num_tc; -+ /* Note : dev->mtu is often read without holding a lock. -+ * Writers usually hold RTNL. -+ * It is recommended to use READ_ONCE() to annotate the reads, -+ * and to use WRITE_ONCE() to annotate the writes. -+ */ -+ unsigned int mtu; -+ unsigned short needed_headroom; -+ struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE]; -+#ifdef CONFIG_XPS -+ struct xps_dev_maps __rcu *xps_maps[XPS_MAPS_MAX]; -+#endif -+#ifdef CONFIG_NETFILTER_EGRESS -+ struct nf_hook_entries __rcu *nf_hooks_egress; -+#endif -+#ifdef CONFIG_NET_XGRESS -+ struct bpf_mprog_entry __rcu *tcx_egress; -+#endif -+ __cacheline_group_end(net_device_read_tx); -+ -+ /* TXRX read-mostly hotpath */ -+ __cacheline_group_begin(net_device_read_txrx); -+ unsigned int flags; -+ unsigned short hard_header_len; -+ netdev_features_t features; -+ struct inet6_dev __rcu *ip6_ptr; -+ __cacheline_group_end(net_device_read_txrx); -+ -+ /* RX read-mostly hotpath */ -+ __cacheline_group_begin(net_device_read_rx); -+ struct list_head ptype_specific; -+ int ifindex; -+ unsigned int real_num_rx_queues; -+ struct netdev_rx_queue *_rx; -+ unsigned long gro_flush_timeout; -+ int napi_defer_hard_irqs; -+ unsigned int gro_max_size; -+ unsigned int gro_ipv4_max_size; -+ rx_handler_func_t __rcu *rx_handler; -+ void __rcu *rx_handler_data; -+ possible_net_t nd_net; -+#ifdef CONFIG_NETPOLL -+ struct netpoll_info __rcu *npinfo; -+#endif -+#ifdef CONFIG_NET_XGRESS -+ struct bpf_mprog_entry __rcu *tcx_ingress; -+#endif -+ __cacheline_group_end(net_device_read_rx); -+ - char name[IFNAMSIZ]; - struct netdev_name_node *name_node; - struct dev_ifalias __rcu *ifalias; -@@ -2113,7 +2177,6 @@ struct net_device { - struct list_head unreg_list; - struct list_head close_list; - struct list_head ptype_all; -- struct list_head ptype_specific; - - struct { - struct list_head upper; -@@ -2121,25 +2184,12 @@ struct net_device { - } adj_list; - - /* Read-mostly cache-line for fast-path access */ -- unsigned int flags; - xdp_features_t xdp_features; -- unsigned long long priv_flags; -- const struct net_device_ops *netdev_ops; - const struct xdp_metadata_ops *xdp_metadata_ops; -- int ifindex; - unsigned short gflags; -- unsigned short hard_header_len; - -- /* Note : dev->mtu is often read without holding a lock. -- * Writers usually hold RTNL. -- * It is recommended to use READ_ONCE() to annotate the reads, -- * and to use WRITE_ONCE() to annotate the writes. -- */ -- unsigned int mtu; -- unsigned short needed_headroom; - unsigned short needed_tailroom; - -- netdev_features_t features; - netdev_features_t hw_features; - netdev_features_t wanted_features; - netdev_features_t vlan_features; -@@ -2183,8 +2233,6 @@ struct net_device { - const struct tlsdev_ops *tlsdev_ops; - #endif - -- const struct header_ops *header_ops; -- - unsigned char operstate; - unsigned char link_mode; - -@@ -2225,9 +2273,7 @@ struct net_device { - - - /* Protocol-specific pointers */ -- - struct in_device __rcu *ip_ptr; -- struct inet6_dev __rcu *ip6_ptr; - #if IS_ENABLED(CONFIG_VLAN_8021Q) - struct vlan_info __rcu *vlan_info; - #endif -@@ -2262,26 +2308,15 @@ struct net_device { - /* Interface address info used in eth_type_trans() */ - const unsigned char *dev_addr; - -- struct netdev_rx_queue *_rx; - unsigned int num_rx_queues; -- unsigned int real_num_rx_queues; - - struct bpf_prog __rcu *xdp_prog; -- unsigned long gro_flush_timeout; -- int napi_defer_hard_irqs; - #define GRO_LEGACY_MAX_SIZE 65536u - /* TCP minimal MSS is 8 (TCP_MIN_GSO_SIZE), - * and shinfo->gso_segs is a 16bit field. - */ - #define GRO_MAX_SIZE (8 * 65535u) -- unsigned int gro_max_size; -- unsigned int gro_ipv4_max_size; - unsigned int xdp_zc_max_segs; -- rx_handler_func_t __rcu *rx_handler; -- void __rcu *rx_handler_data; --#ifdef CONFIG_NET_XGRESS -- struct bpf_mprog_entry __rcu *tcx_ingress; --#endif - struct netdev_queue __rcu *ingress_queue; - #ifdef CONFIG_NETFILTER_INGRESS - struct nf_hook_entries __rcu *nf_hooks_ingress; -@@ -2296,25 +2331,13 @@ struct net_device { - /* - * Cache lines mostly used on transmit path - */ -- struct netdev_queue *_tx ____cacheline_aligned_in_smp; - unsigned int num_tx_queues; -- unsigned int real_num_tx_queues; - struct Qdisc __rcu *qdisc; - unsigned int tx_queue_len; - spinlock_t tx_global_lock; - - struct xdp_dev_bulk_queue __percpu *xdp_bulkq; - --#ifdef CONFIG_XPS -- struct xps_dev_maps __rcu *xps_maps[XPS_MAPS_MAX]; --#endif --#ifdef CONFIG_NET_XGRESS -- struct bpf_mprog_entry __rcu *tcx_egress; --#endif --#ifdef CONFIG_NETFILTER_EGRESS -- struct nf_hook_entries __rcu *nf_hooks_egress; --#endif -- - #ifdef CONFIG_NET_SCHED - DECLARE_HASHTABLE (qdisc_hash, 4); - #endif -@@ -2353,12 +2376,6 @@ struct net_device { - bool needs_free_netdev; - void (*priv_destructor)(struct net_device *dev); - --#ifdef CONFIG_NETPOLL -- struct netpoll_info __rcu *npinfo; --#endif -- -- possible_net_t nd_net; -- - /* mid-layer private */ - void *ml_priv; - enum netdev_ml_priv_type ml_priv_type; -@@ -2393,20 +2410,15 @@ struct net_device { - */ - #define GSO_MAX_SIZE (8 * GSO_MAX_SEGS) - -- unsigned int gso_max_size; - #define TSO_LEGACY_MAX_SIZE 65536 - #define TSO_MAX_SIZE UINT_MAX - unsigned int tso_max_size; -- u16 gso_max_segs; - #define TSO_MAX_SEGS U16_MAX - u16 tso_max_segs; -- unsigned int gso_ipv4_max_size; - - #ifdef CONFIG_DCB - const struct dcbnl_rtnl_ops *dcbnl_ops; - #endif -- s16 num_tc; -- struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE]; - u8 prio_tc_map[TC_BITMASK + 1]; - - #if IS_ENABLED(CONFIG_FCOE) ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -11626,6 +11626,60 @@ static struct pernet_operations __net_in - .exit_batch = default_device_exit_batch, - }; - -+static void __init net_dev_struct_check(void) -+{ -+ /* TX read-mostly hotpath */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, priv_flags); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, netdev_ops); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, header_ops); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, _tx); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, real_num_tx_queues); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, gso_max_size); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, gso_ipv4_max_size); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, gso_max_segs); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, num_tc); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, mtu); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, needed_headroom); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, tc_to_txq); -+#ifdef CONFIG_XPS -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, xps_maps); -+#endif -+#ifdef CONFIG_NETFILTER_EGRESS -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, nf_hooks_egress); -+#endif -+#ifdef CONFIG_NET_XGRESS -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_tx, tcx_egress); -+#endif -+ CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_tx, 152); -+ -+ /* TXRX read-mostly hotpath */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, flags); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, hard_header_len); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, features); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, ip6_ptr); -+ CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 30); -+ -+ /* RX read-mostly hotpath */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ptype_specific); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ifindex); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, real_num_rx_queues); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, _rx); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, gro_flush_timeout); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, napi_defer_hard_irqs); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, gro_max_size); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, gro_ipv4_max_size); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, rx_handler); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, rx_handler_data); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, nd_net); -+#ifdef CONFIG_NETPOLL -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, npinfo); -+#endif -+#ifdef CONFIG_NET_XGRESS -+ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, tcx_ingress); -+#endif -+ CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_rx, 96); -+} -+ - /* - * Initialize the DEV module. At boot time this walks the device list and - * unhooks any devices that fail to initialise (normally hardware not -@@ -11675,6 +11729,8 @@ static int __init net_dev_init(void) - - BUG_ON(!dev_boot_phase); - -+ net_dev_struct_check(); -+ - if (dev_proc_init()) - goto out; - diff --git a/openwrt/patch/kernel-6.6/backport/904-v6.8-tcp-reorganize-tcp_sock-fast-path-variables.patch b/openwrt/patch/kernel-6.6/backport/904-v6.8-tcp-reorganize-tcp_sock-fast-path-variables.patch deleted file mode 100644 index e37ffdd57..000000000 --- a/openwrt/patch/kernel-6.6/backport/904-v6.8-tcp-reorganize-tcp_sock-fast-path-variables.patch +++ /dev/null @@ -1,495 +0,0 @@ -From 700b417042d13b4920b4193682f8b209b6221bb5 Mon Sep 17 00:00:00 2001 -From: Coco Li -Date: Mon, 4 Dec 2023 20:12:31 +0000 -Subject: [PATCH 4/4] tcp: reorganize tcp_sock fast path variables - -The variables are organized according in the following way: - -- TX read-mostly hotpath cache lines -- TXRX read-mostly hotpath cache lines -- RX read-mostly hotpath cache lines -- TX read-write hotpath cache line -- TXRX read-write hotpath cache line -- RX read-write hotpath cache line - -Fastpath cachelines end after rcvq_space. - -Cache line boundaries are enforced only between read-mostly and -read-write. That is, if read-mostly tx cachelines bleed into -read-mostly txrx cachelines, we do not care. We care about the -boundaries between read and write cachelines because we want -to prevent false sharing. - -Fast path variables span cache lines before change: 12 -Fast path variables span cache lines after change: 8 - -Suggested-by: Eric Dumazet -Reviewed-by: Wei Wang -Signed-off-by: Coco Li -Reviewed-by: Eric Dumazet -Reviewed-by: David Ahern -Link: https://lore.kernel.org/r/20231204201232.520025-3-lixiaoyan@google.com -Signed-off-by: Jakub Kicinski ---- - include/linux/tcp.h | 252 ++++++++++++++++++++++++-------------------- - net/ipv4/tcp.c | 93 ++++++++++++++++ - 2 files changed, 229 insertions(+), 116 deletions(-) - ---- a/include/linux/tcp.h -+++ b/include/linux/tcp.h -@@ -175,23 +175,121 @@ static inline struct tcp_request_sock *t - #define TCP_RMEM_TO_WIN_SCALE 8 - - struct tcp_sock { -+ /* Cacheline organization can be found documented in -+ * Documentation/networking/net_cachelines/tcp_sock.rst. -+ * Please update the document when adding new fields. -+ */ -+ - /* inet_connection_sock has to be the first member of tcp_sock */ - struct inet_connection_sock inet_conn; -- u16 tcp_header_len; /* Bytes of tcp header to send */ -+ -+ /* TX read-mostly hotpath cache lines */ -+ __cacheline_group_begin(tcp_sock_read_tx); -+ /* timestamp of last sent data packet (for restart window) */ -+ u32 max_window; /* Maximal window ever seen from peer */ -+ u32 rcv_ssthresh; /* Current window clamp */ -+ u32 reordering; /* Packet reordering metric. */ -+ u32 notsent_lowat; /* TCP_NOTSENT_LOWAT */ - u16 gso_segs; /* Max number of segs per GSO packet */ -+ /* from STCP, retrans queue hinting */ -+ struct sk_buff *lost_skb_hint; -+ struct sk_buff *retransmit_skb_hint; -+ __cacheline_group_end(tcp_sock_read_tx); -+ -+ /* TXRX read-mostly hotpath cache lines */ -+ __cacheline_group_begin(tcp_sock_read_txrx); -+ u32 tsoffset; /* timestamp offset */ -+ u32 snd_wnd; /* The window we expect to receive */ -+ u32 mss_cache; /* Cached effective mss, not including SACKS */ -+ u32 snd_cwnd; /* Sending congestion window */ -+ u32 prr_out; /* Total number of pkts sent during Recovery. */ -+ u32 lost_out; /* Lost packets */ -+ u32 sacked_out; /* SACK'd packets */ -+ u16 tcp_header_len; /* Bytes of tcp header to send */ -+ u8 chrono_type : 2, /* current chronograph type */ -+ repair : 1, -+ is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ -+ is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ -+ __cacheline_group_end(tcp_sock_read_txrx); -+ -+ /* RX read-mostly hotpath cache lines */ -+ __cacheline_group_begin(tcp_sock_read_rx); -+ u32 copied_seq; /* Head of yet unread data */ -+ u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ -+ u32 snd_wl1; /* Sequence for window update */ -+ u32 tlp_high_seq; /* snd_nxt at the time of TLP */ -+ u32 rttvar_us; /* smoothed mdev_max */ -+ u32 retrans_out; /* Retransmitted packets out */ -+ u16 advmss; /* Advertised MSS */ -+ u16 urg_data; /* Saved octet of OOB data and control flags */ -+ u32 lost; /* Total data packets lost incl. rexmits */ -+ struct minmax rtt_min; -+ /* OOO segments go in this rbtree. Socket lock must be held. */ -+ struct rb_root out_of_order_queue; -+ u32 snd_ssthresh; /* Slow start size threshold */ -+ __cacheline_group_end(tcp_sock_read_rx); -+ -+ /* TX read-write hotpath cache lines */ -+ __cacheline_group_begin(tcp_sock_write_tx) ____cacheline_aligned; -+ u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut -+ * The total number of segments sent. -+ */ -+ u32 data_segs_out; /* RFC4898 tcpEStatsPerfDataSegsOut -+ * total number of data segments sent. -+ */ -+ u64 bytes_sent; /* RFC4898 tcpEStatsPerfHCDataOctetsOut -+ * total number of data bytes sent. -+ */ -+ u32 snd_sml; /* Last byte of the most recently transmitted small packet */ -+ u32 chrono_start; /* Start time in jiffies of a TCP chrono */ -+ u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ -+ u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ -+ u32 pushed_seq; /* Last pushed seq, required to talk to windows */ -+ u32 lsndtime; -+ u32 mdev_us; /* medium deviation */ -+ u64 tcp_wstamp_ns; /* departure time for next sent data packet */ -+ u64 tcp_clock_cache; /* cache last tcp_clock_ns() (see tcp_mstamp_refresh()) */ -+ u64 tcp_mstamp; /* most recent packet received/sent */ -+ u32 rtt_seq; /* sequence number to update rttvar */ -+ struct list_head tsorted_sent_queue; /* time-sorted sent but un-SACKed skbs */ -+ struct sk_buff *highest_sack; /* skb just after the highest -+ * skb with SACKed bit set -+ * (validity guaranteed only if -+ * sacked_out > 0) -+ */ -+ u8 ecn_flags; /* ECN status bits. */ -+ __cacheline_group_end(tcp_sock_write_tx); - -+ /* TXRX read-write hotpath cache lines */ -+ __cacheline_group_begin(tcp_sock_write_txrx); - /* - * Header prediction flags - * 0x5?10 << 16 + snd_wnd in net byte order - */ - __be32 pred_flags; -- -+ u32 rcv_nxt; /* What we want to receive next */ -+ u32 snd_nxt; /* Next sequence we send */ -+ u32 snd_una; /* First byte we want an ack for */ -+ u32 window_clamp; /* Maximal window to advertise */ -+ u32 srtt_us; /* smoothed round trip time << 3 in usecs */ -+ u32 packets_out; /* Packets which are "in flight" */ -+ u32 snd_up; /* Urgent pointer */ -+ u32 delivered; /* Total data packets delivered incl. rexmits */ -+ u32 delivered_ce; /* Like the above but only ECE marked packets */ -+ u32 app_limited; /* limited until "delivered" reaches this val */ -+ u32 rcv_wnd; /* Current receiver window */ - /* -- * RFC793 variables by their proper names. This means you can -- * read the code and the spec side by side (and laugh ...) -- * See RFC793 and RFC1122. The RFC writes these in capitals. -- */ -- u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived -+ * Options received (usually on last packet, some only on SYN packets). -+ */ -+ struct tcp_options_received rx_opt; -+ u8 nonagle : 4,/* Disable Nagle algorithm? */ -+ rate_app_limited:1; /* rate_{delivered,interval_us} limited? */ -+ __cacheline_group_end(tcp_sock_write_txrx); -+ -+ /* RX read-write hotpath cache lines */ -+ __cacheline_group_begin(tcp_sock_write_rx); -+ u64 bytes_received; -+ /* RFC4898 tcpEStatsAppHCThruOctetsReceived - * sum(delta(rcv_nxt)), or how many bytes - * were acked. - */ -@@ -201,45 +299,44 @@ struct tcp_sock { - u32 data_segs_in; /* RFC4898 tcpEStatsPerfDataSegsIn - * total number of data segments in. - */ -- u32 rcv_nxt; /* What we want to receive next */ -- u32 copied_seq; /* Head of yet unread data */ - u32 rcv_wup; /* rcv_nxt on last window update sent */ -- u32 snd_nxt; /* Next sequence we send */ -- u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut -- * The total number of segments sent. -- */ -- u32 data_segs_out; /* RFC4898 tcpEStatsPerfDataSegsOut -- * total number of data segments sent. -- */ -- u64 bytes_sent; /* RFC4898 tcpEStatsPerfHCDataOctetsOut -- * total number of data bytes sent. -- */ -+ u32 max_packets_out; /* max packets_out in last window */ -+ u32 cwnd_usage_seq; /* right edge of cwnd usage tracking flight */ -+ u32 rate_delivered; /* saved rate sample: packets delivered */ -+ u32 rate_interval_us; /* saved rate sample: time elapsed */ -+ u32 rcv_rtt_last_tsecr; -+ u64 first_tx_mstamp; /* start of window send phase */ -+ u64 delivered_mstamp; /* time we reached "delivered" */ - u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked - * sum(delta(snd_una)), or how many bytes - * were acked. - */ -+ struct { -+ u32 rtt_us; -+ u32 seq; -+ u64 time; -+ } rcv_rtt_est; -+/* Receiver queue space */ -+ struct { -+ u32 space; -+ u32 seq; -+ u64 time; -+ } rcvq_space; -+ __cacheline_group_end(tcp_sock_write_rx); -+ /* End of Hot Path */ -+ -+/* -+ * RFC793 variables by their proper names. This means you can -+ * read the code and the spec side by side (and laugh ...) -+ * See RFC793 and RFC1122. The RFC writes these in capitals. -+ */ - u32 dsack_dups; /* RFC4898 tcpEStatsStackDSACKDups - * total number of DSACK blocks received - */ -- u32 snd_una; /* First byte we want an ack for */ -- u32 snd_sml; /* Last byte of the most recently transmitted small packet */ -- u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ -- u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ - u32 last_oow_ack_time; /* timestamp of last out-of-window ACK */ - u32 compressed_ack_rcv_nxt; - -- u32 tsoffset; /* timestamp offset */ -- - struct list_head tsq_node; /* anchor in tsq_tasklet.head list */ -- struct list_head tsorted_sent_queue; /* time-sorted sent but un-SACKed skbs */ -- -- u32 snd_wl1; /* Sequence for window update */ -- u32 snd_wnd; /* The window we expect to receive */ -- u32 max_window; /* Maximal window ever seen from peer */ -- u32 mss_cache; /* Cached effective mss, not including SACKS */ -- -- u32 window_clamp; /* Maximal window to advertise */ -- u32 rcv_ssthresh; /* Current window clamp */ - u8 scaling_ratio; /* see tcp_win_from_space() */ - /* Information of the most recently (s)acked skb */ - struct tcp_rack { -@@ -253,25 +350,17 @@ struct tcp_sock { - dsack_seen:1, /* Whether DSACK seen after last adj */ - advanced:1; /* mstamp advanced since last lost marking */ - } rack; -- u16 advmss; /* Advertised MSS */ - u8 compressed_ack; - u8 dup_ack_counter:2, - tlp_retrans:1, /* TLP is a retransmission */ - fast_ack_mode:2, /* which fast ack mode ? */ - tlp_orig_data_app_limited:1, /* app-limited before TLP rtx? */ - unused:2; -- u32 chrono_start; /* Start time in jiffies of a TCP chrono */ -- u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ -- u8 chrono_type:2, /* current chronograph type */ -- rate_app_limited:1, /* rate_{delivered,interval_us} limited? */ -+ u8 thin_lto : 1,/* Use linear timeouts for thin streams */ -+ recvmsg_inq : 1,/* Indicate # of bytes in queue upon recvmsg */ - fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ - fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ -- is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ -- fastopen_client_fail:2; /* reason why fastopen failed */ -- u8 nonagle : 4,/* Disable Nagle algorithm? */ -- thin_lto : 1,/* Use linear timeouts for thin streams */ -- recvmsg_inq : 1,/* Indicate # of bytes in queue upon recvmsg */ -- repair : 1, -+ fastopen_client_fail:2, /* reason why fastopen failed */ - frto : 1;/* F-RTO (RFC5682) activated in CA_Loss */ - u8 repair_queue; - u8 save_syn:2, /* Save headers of SYN packet */ -@@ -279,45 +368,19 @@ struct tcp_sock { - syn_fastopen:1, /* SYN includes Fast Open option */ - syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */ - syn_fastopen_ch:1, /* Active TFO re-enabling probe */ -- syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ -- is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ -- u32 tlp_high_seq; /* snd_nxt at the time of TLP */ -+ syn_data_acked:1;/* data in SYN is acked by SYN-ACK */ - - u32 tcp_tx_delay; /* delay (in usec) added to TX packets */ -- u64 tcp_wstamp_ns; /* departure time for next sent data packet */ -- u64 tcp_clock_cache; /* cache last tcp_clock_ns() (see tcp_mstamp_refresh()) */ - - /* RTT measurement */ -- u64 tcp_mstamp; /* most recent packet received/sent */ -- u32 srtt_us; /* smoothed round trip time << 3 in usecs */ -- u32 mdev_us; /* medium deviation */ - u32 mdev_max_us; /* maximal mdev for the last rtt period */ -- u32 rttvar_us; /* smoothed mdev_max */ -- u32 rtt_seq; /* sequence number to update rttvar */ -- struct minmax rtt_min; - -- u32 packets_out; /* Packets which are "in flight" */ -- u32 retrans_out; /* Retransmitted packets out */ -- u32 max_packets_out; /* max packets_out in last window */ -- u32 cwnd_usage_seq; /* right edge of cwnd usage tracking flight */ -- -- u16 urg_data; /* Saved octet of OOB data and control flags */ -- u8 ecn_flags; /* ECN status bits. */ - u8 keepalive_probes; /* num of allowed keep alive probes */ -- u32 reordering; /* Packet reordering metric. */ - u32 reord_seen; /* number of data packet reordering events */ -- u32 snd_up; /* Urgent pointer */ -- --/* -- * Options received (usually on last packet, some only on SYN packets). -- */ -- struct tcp_options_received rx_opt; - - /* - * Slow start and congestion control (see also Nagle, and Karn & Partridge) - */ -- u32 snd_ssthresh; /* Slow start size threshold */ -- u32 snd_cwnd; /* Sending congestion window */ - u32 snd_cwnd_cnt; /* Linear increase counter */ - u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ - u32 snd_cwnd_used; -@@ -325,33 +388,11 @@ struct tcp_sock { - u32 prior_cwnd; /* cwnd right before starting loss recovery */ - u32 prr_delivered; /* Number of newly delivered packets to - * receiver in Recovery. */ -- u32 prr_out; /* Total number of pkts sent during Recovery. */ -- u32 delivered; /* Total data packets delivered incl. rexmits */ -- u32 delivered_ce; /* Like the above but only ECE marked packets */ -- u32 lost; /* Total data packets lost incl. rexmits */ -- u32 app_limited; /* limited until "delivered" reaches this val */ -- u64 first_tx_mstamp; /* start of window send phase */ -- u64 delivered_mstamp; /* time we reached "delivered" */ -- u32 rate_delivered; /* saved rate sample: packets delivered */ -- u32 rate_interval_us; /* saved rate sample: time elapsed */ -- -- u32 rcv_wnd; /* Current receiver window */ -- u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ -- u32 notsent_lowat; /* TCP_NOTSENT_LOWAT */ -- u32 pushed_seq; /* Last pushed seq, required to talk to windows */ -- u32 lost_out; /* Lost packets */ -- u32 sacked_out; /* SACK'd packets */ - - struct hrtimer pacing_timer; - struct hrtimer compressed_ack_timer; - -- /* from STCP, retrans queue hinting */ -- struct sk_buff* lost_skb_hint; -- struct sk_buff *retransmit_skb_hint; -- -- /* OOO segments go in this rbtree. Socket lock must be held. */ -- struct rb_root out_of_order_queue; -- struct sk_buff *ooo_last_skb; /* cache rb_last(out_of_order_queue) */ -+ struct sk_buff *ooo_last_skb; /* cache rb_last(out_of_order_queue) */ - - /* SACKs data, these 2 need to be together (see tcp_options_write) */ - struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ -@@ -359,12 +400,6 @@ struct tcp_sock { - - struct tcp_sack_block recv_sack_cache[4]; - -- struct sk_buff *highest_sack; /* skb just after the highest -- * skb with SACKed bit set -- * (validity guaranteed only if -- * sacked_out > 0) -- */ -- - int lost_cnt_hint; - - u32 prior_ssthresh; /* ssthresh saved at recovery start */ -@@ -407,21 +442,6 @@ struct tcp_sock { - - u32 rcv_ooopack; /* Received out-of-order packets, for tcpinfo */ - --/* Receiver side RTT estimation */ -- u32 rcv_rtt_last_tsecr; -- struct { -- u32 rtt_us; -- u32 seq; -- u64 time; -- } rcv_rtt_est; -- --/* Receiver queue space */ -- struct { -- u32 space; -- u32 seq; -- u64 time; -- } rcvq_space; -- - /* TCP-specific MTU probe information. */ - struct { - u32 probe_seq_start; ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -4651,6 +4651,97 @@ static void __init tcp_init_mem(void) - sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2; /* 9.37 % */ - } - -+static void __init tcp_struct_check(void) -+{ -+ /* TX read-mostly hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, max_window); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, rcv_ssthresh); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, reordering); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, notsent_lowat); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, gso_segs); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, lost_skb_hint); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_tx, retransmit_skb_hint); -+ CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_tx, 40); -+ -+ /* TXRX read-mostly hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, tsoffset); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, snd_wnd); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, mss_cache); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, snd_cwnd); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, prr_out); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, lost_out); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, sacked_out); -+ CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 31); -+ -+ /* RX read-mostly hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, copied_seq); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, rcv_tstamp); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, snd_wl1); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, tlp_high_seq); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, rttvar_us); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, retrans_out); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, advmss); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, urg_data); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, lost); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, rtt_min); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, out_of_order_queue); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, snd_ssthresh); -+ CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_rx, 69); -+ -+ /* TX read-write hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, segs_out); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, data_segs_out); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, bytes_sent); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, snd_sml); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, chrono_start); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, chrono_stat); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, write_seq); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, pushed_seq); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, lsndtime); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, mdev_us); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tcp_wstamp_ns); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tcp_clock_cache); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tcp_mstamp); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, rtt_seq); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, tsorted_sent_queue); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, highest_sack); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_tx, ecn_flags); -+ CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_tx, 113); -+ -+ /* TXRX read-write hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, pred_flags); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, rcv_nxt); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, snd_nxt); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, snd_una); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, window_clamp); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, srtt_us); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, packets_out); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, snd_up); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, delivered); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, delivered_ce); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, app_limited); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, rcv_wnd); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_txrx, rx_opt); -+ CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_txrx, 76); -+ -+ /* RX read-write hotpath cache lines */ -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, bytes_received); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, segs_in); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, data_segs_in); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcv_wup); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, max_packets_out); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, cwnd_usage_seq); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rate_delivered); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rate_interval_us); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcv_rtt_last_tsecr); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, first_tx_mstamp); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, delivered_mstamp); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, bytes_acked); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcv_rtt_est); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_write_rx, rcvq_space); -+ CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_write_rx, 99); -+} -+ - void __init tcp_init(void) - { - int max_rshare, max_wshare, cnt; -@@ -4661,6 +4752,8 @@ void __init tcp_init(void) - BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > - sizeof_field(struct sk_buff, cb)); - -+ tcp_struct_check(); -+ - percpu_counter_init(&tcp_sockets_allocated, 0, GFP_KERNEL); - - timer_setup(&tcp_orphan_timer, tcp_orphan_update, TIMER_DEFERRABLE); diff --git a/openwrt/patch/kernel-6.6/backport/905-v6.8-tcp-move-tp-scaling_ratio-to-tcp_sock_read_txrx-grou.patch b/openwrt/patch/kernel-6.6/backport/905-v6.8-tcp-move-tp-scaling_ratio-to-tcp_sock_read_txrx-grou.patch deleted file mode 100644 index 507fed2ca..000000000 --- a/openwrt/patch/kernel-6.6/backport/905-v6.8-tcp-move-tp-scaling_ratio-to-tcp_sock_read_txrx-grou.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 119ff04864a24470b1e531bb53e5c141aa8fefb0 Mon Sep 17 00:00:00 2001 -From: Eric Dumazet -Date: Thu, 8 Feb 2024 14:43:21 +0000 -Subject: [PATCH] tcp: move tp->scaling_ratio to tcp_sock_read_txrx group - -tp->scaling_ratio is a read mostly field, used in rx and tx fast paths. - -Fixes: d5fed5addb2b ("tcp: reorganize tcp_sock fast path variables") -Signed-off-by: Eric Dumazet -Cc: Coco Li -Cc: Wei Wang -Reviewed-by: Simon Horman -Signed-off-by: David S. Miller ---- - include/linux/tcp.h | 2 +- - net/ipv4/tcp.c | 3 ++- - 2 files changed, 3 insertions(+), 2 deletions(-) - ---- a/include/linux/tcp.h -+++ b/include/linux/tcp.h -@@ -206,6 +206,7 @@ struct tcp_sock { - u32 lost_out; /* Lost packets */ - u32 sacked_out; /* SACK'd packets */ - u16 tcp_header_len; /* Bytes of tcp header to send */ -+ u8 scaling_ratio; /* see tcp_win_from_space() */ - u8 chrono_type : 2, /* current chronograph type */ - repair : 1, - is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ -@@ -337,7 +338,6 @@ struct tcp_sock { - u32 compressed_ack_rcv_nxt; - - struct list_head tsq_node; /* anchor in tsq_tasklet.head list */ -- u8 scaling_ratio; /* see tcp_win_from_space() */ - /* Information of the most recently (s)acked skb */ - struct tcp_rack { - u64 mstamp; /* (Re)sent time of the skb */ ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -4671,7 +4671,8 @@ static void __init tcp_struct_check(void - CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, prr_out); - CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, lost_out); - CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, sacked_out); -- CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 31); -+ CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_txrx, scaling_ratio); -+ CACHELINE_ASSERT_GROUP_SIZE(struct tcp_sock, tcp_sock_read_txrx, 32); - - /* RX read-mostly hotpath cache lines */ - CACHELINE_ASSERT_GROUP_MEMBER(struct tcp_sock, tcp_sock_read_rx, copied_seq); diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch deleted file mode 100644 index 69cce2a06..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ /dev/null @@ -1,52 +0,0 @@ -From eb92cc2649fa5e8b31fe0577a7d2f6820699a9cc Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Tue, 11 Jun 2019 12:26:55 -0400 -Subject: [PATCH 01/18] net-tcp_bbr: broaden app-limited rate sample detection - -This commit is a bug fix for the Linux TCP app-limited -(application-limited) logic that is used for collecting rate -(bandwidth) samples. - -Previously the app-limited logic only looked for "bubbles" of -silence in between application writes, by checking at the start -of each sendmsg. But "bubbles" of silence can also happen before -retransmits: e.g. bubbles can happen between an application write -and a retransmit, or between two retransmits. - -Retransmits are triggered by ACKs or timers. So this commit checks -for bubbles of app-limited silence upon ACKs or timers. - -Why does this commit check for app-limited state at the start of -ACKs and timer handling? Because at that point we know whether -inflight was fully using the cwnd. During processing the ACK or -timer event we often change the cwnd; after changing the cwnd we -can't know whether inflight was fully using the old cwnd. - -Origin-9xx-SHA1: 3fe9b53291e018407780fb8c356adb5666722cbc -Change-Id: I37221506f5166877c2b110753d39bb0757985e68 -Signed-off-by: Alexandre Frade ---- - net/ipv4/tcp_input.c | 1 + - net/ipv4/tcp_timer.c | 1 + - 2 files changed, 2 insertions(+) - ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -3874,6 +3874,7 @@ static int tcp_ack(struct sock *sk, cons - - prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; - rs.prior_in_flight = tcp_packets_in_flight(tp); -+ tcp_rate_check_app_limited(sk); - - /* ts_recent update must be made after we are sure that the packet - * is in window. ---- a/net/ipv4/tcp_timer.c -+++ b/net/ipv4/tcp_timer.c -@@ -664,6 +664,7 @@ void tcp_write_timer_handler(struct sock - return; - } - -+ tcp_rate_check_app_limited(sk); - tcp_mstamp_refresh(tcp_sk(sk)); - event = icsk->icsk_pending; - diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch deleted file mode 100644 index cd9eb0ac6..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 94abfc4e52198e003444ef5139df915514b8c207 Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Sun, 24 Jun 2018 21:55:59 -0400 -Subject: [PATCH 02/18] net-tcp_bbr: v2: shrink delivered_mstamp, - first_tx_mstamp to u32 to free up 8 bytes - -Free up some space for tracking inflight and losses for each -bw sample, in upcoming commits. - -These timestamps are in microseconds, and are now stored in 32 -bits. So they can only hold time intervals up to roughly 2^12 = 4096 -seconds. But Linux TCP RTT and RTO tracking has the same 32-bit -microsecond implementation approach and resulting deployment -limitations. So this is not introducing a new limit. And these should -not be a limitation for the foreseeable future. - -Effort: net-tcp_bbr -Origin-9xx-SHA1: 238a7e6b5d51625fef1ce7769826a7b21b02ae55 -Change-Id: I3b779603797263b52a61ad57c565eb91fe42680c -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 9 +++++++-- - net/ipv4/tcp_rate.c | 7 ++++--- - 2 files changed, 11 insertions(+), 5 deletions(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -822,6 +822,11 @@ static inline u32 tcp_stamp_us_delta(u64 - return max_t(s64, t1 - t0, 0); - } - -+static inline u32 tcp_stamp32_us_delta(u32 t1, u32 t0) -+{ -+ return max_t(s32, t1 - t0, 0); -+} -+ - static inline u32 tcp_skb_timestamp(const struct sk_buff *skb) - { - return tcp_ns_to_ts(skb->skb_mstamp_ns); -@@ -897,9 +902,9 @@ struct tcp_skb_cb { - /* pkts S/ACKed so far upon tx of skb, incl retrans: */ - __u32 delivered; - /* start of send pipeline phase */ -- u64 first_tx_mstamp; -+ u32 first_tx_mstamp; - /* when we reached the "delivered" count */ -- u64 delivered_mstamp; -+ u32 delivered_mstamp; - } tx; /* only used for outgoing skbs */ - union { - struct inet_skb_parm h4; ---- a/net/ipv4/tcp_rate.c -+++ b/net/ipv4/tcp_rate.c -@@ -101,8 +101,9 @@ void tcp_rate_skb_delivered(struct sock - /* Record send time of most recently ACKed packet: */ - tp->first_tx_mstamp = tx_tstamp; - /* Find the duration of the "send phase" of this window: */ -- rs->interval_us = tcp_stamp_us_delta(tp->first_tx_mstamp, -- scb->tx.first_tx_mstamp); -+ rs->interval_us = tcp_stamp32_us_delta( -+ tp->first_tx_mstamp, -+ scb->tx.first_tx_mstamp); - - } - /* Mark off the skb delivered once it's sacked to avoid being -@@ -155,7 +156,7 @@ void tcp_rate_gen(struct sock *sk, u32 d - * longer phase. - */ - snd_us = rs->interval_us; /* send phase */ -- ack_us = tcp_stamp_us_delta(tp->tcp_mstamp, -+ ack_us = tcp_stamp32_us_delta(tp->tcp_mstamp, - rs->prior_mstamp); /* ack phase */ - rs->interval_us = max(snd_us, ack_us); - diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch deleted file mode 100644 index 128f33ec5..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 497c9101c33baca0207cad3e7e328ccd72e3e62c Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Sat, 5 Aug 2017 11:49:50 -0400 -Subject: [PATCH 03/18] net-tcp_bbr: v2: snapshot packets in flight at transmit - time and pass in rate_sample - -CC algorithms may want to snapshot the number of packets in flight at -transmit time and pass in rate_sample, to understand the relationship -between inflight and losses or ECN signals, to try to find the highest -inflight value that has acceptable levels of loss/ECN marking. - -We split out the code to set an skb's tx.in_flight field into its own -function, so that this code can be used for the TCP_REPAIR "fake send" -code path that inserts skbs into the rtx queue without sending them. - -Effort: net-tcp_bbr -Origin-9xx-SHA1: b3eb4f2d20efab4ca001f32c9294739036c493ea -Origin-9xx-SHA1: e880fc907d06ea7354333f60f712748ebce9497b -Origin-9xx-SHA1: 330f825a08a6fe92cef74d799cc468864c479f63 -Change-Id: I7314047d0ff14dd261a04b1969a46dc658c8836a -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 6 ++++++ - net/ipv4/tcp_output.c | 1 + - net/ipv4/tcp_rate.c | 20 ++++++++++++++++++++ - 3 files changed, 27 insertions(+) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -905,6 +905,10 @@ struct tcp_skb_cb { - u32 first_tx_mstamp; - /* when we reached the "delivered" count */ - u32 delivered_mstamp; -+#define TCPCB_IN_FLIGHT_BITS 20 -+#define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) -+ u32 in_flight:20, /* packets in flight at transmit */ -+ unused2:12; - } tx; /* only used for outgoing skbs */ - union { - struct inet_skb_parm h4; -@@ -1052,6 +1056,7 @@ struct rate_sample { - u64 prior_mstamp; /* starting timestamp for interval */ - u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ - u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ -+ u32 tx_in_flight; /* packets in flight at starting timestamp */ - s32 delivered; /* number of packets delivered over interval */ - s32 delivered_ce; /* number of packets delivered w/ CE marks*/ - long interval_us; /* time for tp->delivered to incr "delivered" */ -@@ -1174,6 +1179,7 @@ static inline void tcp_ca_event(struct s - void tcp_set_ca_state(struct sock *sk, const u8 ca_state); - - /* From tcp_rate.c */ -+void tcp_set_tx_in_flight(struct sock *sk, struct sk_buff *skb); - void tcp_rate_skb_sent(struct sock *sk, struct sk_buff *skb); - void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb, - struct rate_sample *rs); ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -2703,6 +2703,7 @@ static bool tcp_write_xmit(struct sock * - skb_set_delivery_time(skb, tp->tcp_wstamp_ns, true); - list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); - tcp_init_tso_segs(skb, mss_now); -+ tcp_set_tx_in_flight(sk, skb); - goto repair; /* Skip network transmission */ - } - ---- a/net/ipv4/tcp_rate.c -+++ b/net/ipv4/tcp_rate.c -@@ -34,6 +34,24 @@ - * ready to send in the write queue. - */ - -+void tcp_set_tx_in_flight(struct sock *sk, struct sk_buff *skb) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ u32 in_flight; -+ -+ /* Check, sanitize, and record packets in flight after skb was sent. */ -+ in_flight = tcp_packets_in_flight(tp) + tcp_skb_pcount(skb); -+ if (WARN_ONCE(in_flight > TCPCB_IN_FLIGHT_MAX, -+ "insane in_flight %u cc %s mss %u " -+ "cwnd %u pif %u %u %u %u\n", -+ in_flight, inet_csk(sk)->icsk_ca_ops->name, -+ tp->mss_cache, tp->snd_cwnd, -+ tp->packets_out, tp->retrans_out, -+ tp->sacked_out, tp->lost_out)) -+ in_flight = TCPCB_IN_FLIGHT_MAX; -+ TCP_SKB_CB(skb)->tx.in_flight = in_flight; -+} -+ - /* Snapshot the current delivery information in the skb, to generate - * a rate sample later when the skb is (s)acked in tcp_rate_skb_delivered(). - */ -@@ -67,6 +85,7 @@ void tcp_rate_skb_sent(struct sock *sk, - TCP_SKB_CB(skb)->tx.delivered = tp->delivered; - TCP_SKB_CB(skb)->tx.delivered_ce = tp->delivered_ce; - TCP_SKB_CB(skb)->tx.is_app_limited = tp->app_limited ? 1 : 0; -+ tcp_set_tx_in_flight(sk, skb); - } - - /* When an skb is sacked or acked, we fill in the rate sample with the (prior) -@@ -96,6 +115,7 @@ void tcp_rate_skb_delivered(struct sock - rs->prior_mstamp = scb->tx.delivered_mstamp; - rs->is_app_limited = scb->tx.is_app_limited; - rs->is_retrans = scb->sacked & TCPCB_RETRANS; -+ rs->tx_in_flight = scb->tx.in_flight; - rs->last_end_seq = scb->end_seq; - - /* Record send time of most recently ACKed packet: */ diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch deleted file mode 100644 index d9d335594..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 9e07a8f79e42db42adcc961baabc6e142dd891ed Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Thu, 12 Oct 2017 23:44:27 -0400 -Subject: [PATCH 04/18] net-tcp_bbr: v2: count packets lost over TCP rate - sampling interval - -For understanding the relationship between inflight and packet loss -signals, to try to find the highest inflight value that has acceptable -levels of packet losses. - -Effort: net-tcp_bbr -Origin-9xx-SHA1: 4527e26b2bd7756a88b5b9ef1ada3da33dd609ab -Change-Id: I594c2500868d9c530770e7ddd68ffc87c57f4fd5 -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 5 ++++- - net/ipv4/tcp_rate.c | 3 +++ - 2 files changed, 7 insertions(+), 1 deletion(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -909,6 +909,7 @@ struct tcp_skb_cb { - #define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) - u32 in_flight:20, /* packets in flight at transmit */ - unused2:12; -+ u32 lost; /* packets lost so far upon tx of skb */ - } tx; /* only used for outgoing skbs */ - union { - struct inet_skb_parm h4; -@@ -1054,11 +1055,13 @@ struct ack_sample { - */ - struct rate_sample { - u64 prior_mstamp; /* starting timestamp for interval */ -+ u32 prior_lost; /* tp->lost at "prior_mstamp" */ - u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ - u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ - u32 tx_in_flight; /* packets in flight at starting timestamp */ -+ s32 lost; /* number of packets lost over interval */ - s32 delivered; /* number of packets delivered over interval */ -- s32 delivered_ce; /* number of packets delivered w/ CE marks*/ -+ s32 delivered_ce; /* packets delivered w/ CE mark over interval */ - long interval_us; /* time for tp->delivered to incr "delivered" */ - u32 snd_interval_us; /* snd interval for delivered packets */ - u32 rcv_interval_us; /* rcv interval for delivered packets */ ---- a/net/ipv4/tcp_rate.c -+++ b/net/ipv4/tcp_rate.c -@@ -84,6 +84,7 @@ void tcp_rate_skb_sent(struct sock *sk, - TCP_SKB_CB(skb)->tx.delivered_mstamp = tp->delivered_mstamp; - TCP_SKB_CB(skb)->tx.delivered = tp->delivered; - TCP_SKB_CB(skb)->tx.delivered_ce = tp->delivered_ce; -+ TCP_SKB_CB(skb)->tx.lost = tp->lost; - TCP_SKB_CB(skb)->tx.is_app_limited = tp->app_limited ? 1 : 0; - tcp_set_tx_in_flight(sk, skb); - } -@@ -110,6 +111,7 @@ void tcp_rate_skb_delivered(struct sock - if (!rs->prior_delivered || - tcp_skb_sent_after(tx_tstamp, tp->first_tx_mstamp, - scb->end_seq, rs->last_end_seq)) { -+ rs->prior_lost = scb->tx.lost; - rs->prior_delivered_ce = scb->tx.delivered_ce; - rs->prior_delivered = scb->tx.delivered; - rs->prior_mstamp = scb->tx.delivered_mstamp; -@@ -165,6 +167,7 @@ void tcp_rate_gen(struct sock *sk, u32 d - return; - } - rs->delivered = tp->delivered - rs->prior_delivered; -+ rs->lost = tp->lost - rs->prior_lost; - - rs->delivered_ce = tp->delivered_ce - rs->prior_delivered_ce; - /* delivered_ce occupies less than 32 bits in the skb control block */ diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch deleted file mode 100644 index 9aafb04f3..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 5f7df19fe56d5ddaa7d3ba34ded446e26a5725a1 Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Mon, 19 Nov 2018 13:48:36 -0500 -Subject: [PATCH 05/18] net-tcp_bbr: v2: export FLAG_ECE in rate_sample.is_ece - -For understanding the relationship between inflight and ECN signals, -to try to find the highest inflight value that has acceptable levels -ECN marking. - -Effort: net-tcp_bbr -Origin-9xx-SHA1: 3eba998f2898541406c2666781182200934965a8 -Change-Id: I3a964e04cee83e11649a54507043d2dfe769a3b3 -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 1 + - net/ipv4/tcp_input.c | 1 + - 2 files changed, 2 insertions(+) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1073,6 +1073,7 @@ struct rate_sample { - bool is_app_limited; /* is sample from packet with bubble in pipe? */ - bool is_retrans; /* is sample from retransmission? */ - bool is_ack_delayed; /* is this (likely) a delayed ACK? */ -+ bool is_ece; /* did this ACK have ECN marked? */ - }; - - struct tcp_congestion_ops { ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -3973,6 +3973,7 @@ static int tcp_ack(struct sock *sk, cons - delivered = tcp_newly_delivered(sk, delivered, flag); - lost = tp->lost - lost; /* freshly marked lost */ - rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); -+ rs.is_ece = !!(flag & FLAG_ECE); - tcp_rate_gen(sk, delivered, lost, is_sack_reneg, sack_state.rate); - tcp_cong_control(sk, ack, delivered, flag, sack_state.rate); - tcp_xmit_recovery(sk, rexmit); diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch deleted file mode 100644 index 04c29cdef..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 36f2ad7500c7fd665efbf38482fa838ba070acc0 Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Tue, 7 Aug 2018 21:52:06 -0400 -Subject: [PATCH 06/18] net-tcp_bbr: v2: introduce ca_ops->skb_marked_lost() CC - module callback API - -For connections experiencing reordering, RACK can mark packets lost -long after we receive the SACKs/ACKs hinting that the packets were -actually lost. - -This means that CC modules cannot easily learn the volume of inflight -data at which packet loss happens by looking at the current inflight -or even the packets in flight when the most recently SACKed packet was -sent. To learn this, CC modules need to know how many packets were in -flight at the time lost packets were sent. This new callback, combined -with TCP_SKB_CB(skb)->tx.in_flight, allows them to learn this. - -This also provides a consistent callback that is invoked whether -packets are marked lost upon ACK processing, using the RACK reordering -timer, or at RTO time. - -Effort: net-tcp_bbr -Origin-9xx-SHA1: afcbebe3374e4632ac6714d39e4dc8a8455956f4 -Change-Id: I54826ab53df636be537e5d3c618a46145d12d51a -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 3 +++ - net/ipv4/tcp_input.c | 5 +++++ - 2 files changed, 8 insertions(+) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1100,6 +1100,9 @@ struct tcp_congestion_ops { - /* override sysctl_tcp_min_tso_segs */ - u32 (*min_tso_segs)(struct sock *sk); - -+ /* react to a specific lost skb (optional) */ -+ void (*skb_marked_lost)(struct sock *sk, const struct sk_buff *skb); -+ - /* call when packets are delivered to update cwnd and pacing rate, - * after all the ca_state processing. (optional) - */ ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -1103,7 +1103,12 @@ static void tcp_verify_retransmit_hint(s - */ - static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) - { -+ struct sock *sk = (struct sock *)tp; -+ const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; -+ - tp->lost += tcp_skb_pcount(skb); -+ if (ca_ops->skb_marked_lost) -+ ca_ops->skb_marked_lost(sk, skb); - } - - void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb) diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch deleted file mode 100644 index cf3a0f0c5..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 8c74d21f1869f7bc7a5c8700172181b4a6e4f04d Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Wed, 1 May 2019 20:16:33 -0400 -Subject: [PATCH 07/18] net-tcp_bbr: v2: adjust skb tx.in_flight upon merge in - tcp_shifted_skb() - -When tcp_shifted_skb() updates state as adjacent SACKed skbs are -coalesced, previously the tx.in_flight was not adjusted, so we could -get contradictory state where the skb's recorded pcount was bigger -than the tx.in_flight (the number of segments that were in_flight -after sending the skb). - -Normally have a SACKed skb with contradictory pcount/tx.in_flight -would not matter. However, with SACK reneging, the SACKed bit is -removed, and an skb once again becomes eligible for retransmitting, -fragmenting, SACKing, etc. Packetdrill testing verified the following -sequence is possible in a kernel that does not have this commit: - - - skb N is SACKed - - skb N+1 is SACKed and combined with skb N using tcp_shifted_skb() - - tcp_shifted_skb() will increase the pcount of prev, - but leave tx.in_flight as-is - - so prev skb can have pcount > tx.in_flight - - RTO, tcp_timeout_mark_lost(), detect reneg, - remove "SACKed" bit, mark skb N as lost - - find pcount of skb N is greater than its tx.in_flight - -I suspect this issue iw what caused the bbr2_inflight_hi_from_lost_skb(): - WARN_ON_ONCE(inflight_prev < 0) -to fire in production machines using bbr2. - -Effort: net-tcp_bbr -Origin-9xx-SHA1: 1a3e997e613d2dcf32b947992882854ebe873715 -Change-Id: I1b0b75c27519953430c7db51c6f358f104c7af55 -Signed-off-by: Alexandre Frade ---- - net/ipv4/tcp_input.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -1489,6 +1489,17 @@ static bool tcp_shifted_skb(struct sock - WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); - tcp_skb_pcount_add(skb, -pcount); - -+ /* Adjust tx.in_flight as pcount is shifted from skb to prev. */ -+ if (WARN_ONCE(TCP_SKB_CB(skb)->tx.in_flight < pcount, -+ "prev in_flight: %u skb in_flight: %u pcount: %u", -+ TCP_SKB_CB(prev)->tx.in_flight, -+ TCP_SKB_CB(skb)->tx.in_flight, -+ pcount)) -+ TCP_SKB_CB(skb)->tx.in_flight = 0; -+ else -+ TCP_SKB_CB(skb)->tx.in_flight -= pcount; -+ TCP_SKB_CB(prev)->tx.in_flight += pcount; -+ - /* When we're adding to gso_segs == 1, gso_size will be zero, - * in theory this shouldn't be necessary but as long as DSACK - * code can come after this skb later on it's better to keep diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch deleted file mode 100644 index 202e536fa..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 545f96f640c4ff7f485ef4314b990b5a380aef2e Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Wed, 1 May 2019 20:16:25 -0400 -Subject: [PATCH 08/18] net-tcp_bbr: v2: adjust skb tx.in_flight upon split in - tcp_fragment() - -When we fragment an skb that has already been sent, we need to update -the tx.in_flight for the first skb in the resulting pair ("buff"). - -Because we were not updating the tx.in_flight, the tx.in_flight value -was inconsistent with the pcount of the "buff" skb (tx.in_flight would -be too high). That meant that if the "buff" skb was lost, then -bbr2_inflight_hi_from_lost_skb() would calculate an inflight_hi value -that is too high. This could result in longer queues and higher packet -loss. - -Packetdrill testing verified that without this commit, when the second -half of an skb is SACKed and then later the first half of that skb is -marked lost, the calculated inflight_hi was incorrect. - -Effort: net-tcp_bbr -Origin-9xx-SHA1: 385f1ddc610798fab2837f9f372857438b25f874 -Origin-9xx-SHA1: a0eb099690af net-tcp_bbr: v2: fix tcp_fragment() tx.in_flight recomputation [prod feb 8 2021; use as a fixup] -Origin-9xx-SHA1: 885503228153ff0c9114e net-tcp_bbr: v2: introduce tcp_skb_tx_in_flight_is_suspicious() helper for warnings -Change-Id: I617f8cab4e9be7a0b8e8d30b047bf8645393354d -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 15 +++++++++++++++ - net/ipv4/tcp_output.c | 26 +++++++++++++++++++++++++- - 2 files changed, 40 insertions(+), 1 deletion(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1199,6 +1199,21 @@ static inline bool tcp_skb_sent_after(u6 - return t1 > t2 || (t1 == t2 && after(seq1, seq2)); - } - -+/* If a retransmit failed due to local qdisc congestion or other local issues, -+ * then we may have called tcp_set_skb_tso_segs() to increase the number of -+ * segments in the skb without increasing the tx.in_flight. In all other cases, -+ * the tx.in_flight should be at least as big as the pcount of the sk_buff. We -+ * do not have the state to know whether a retransmit failed due to local qdisc -+ * congestion or other local issues, so to avoid spurious warnings we consider -+ * that any skb marked lost may have suffered that fate. -+ */ -+static inline bool tcp_skb_tx_in_flight_is_suspicious(u32 skb_pcount, -+ u32 skb_sacked_flags, -+ u32 tx_in_flight) -+{ -+ return (skb_pcount > tx_in_flight) && !(skb_sacked_flags & TCPCB_LOST); -+} -+ - /* These functions determine how the current flow behaves in respect of SACK - * handling. SACK is negotiated with the peer, and therefore it can vary - * between different flows. ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -1548,7 +1548,7 @@ int tcp_fragment(struct sock *sk, enum t - { - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *buff; -- int old_factor; -+ int old_factor, inflight_prev; - long limit; - int nlen; - u8 flags; -@@ -1623,6 +1623,30 @@ int tcp_fragment(struct sock *sk, enum t - - if (diff) - tcp_adjust_pcount(sk, skb, diff); -+ -+ inflight_prev = TCP_SKB_CB(skb)->tx.in_flight - old_factor; -+ if (inflight_prev < 0) { -+ WARN_ONCE(tcp_skb_tx_in_flight_is_suspicious( -+ old_factor, -+ TCP_SKB_CB(skb)->sacked, -+ TCP_SKB_CB(skb)->tx.in_flight), -+ "inconsistent: tx.in_flight: %u " -+ "old_factor: %d mss: %u sacked: %u " -+ "1st pcount: %d 2nd pcount: %d " -+ "1st len: %u 2nd len: %u ", -+ TCP_SKB_CB(skb)->tx.in_flight, old_factor, -+ mss_now, TCP_SKB_CB(skb)->sacked, -+ tcp_skb_pcount(skb), tcp_skb_pcount(buff), -+ skb->len, buff->len); -+ inflight_prev = 0; -+ } -+ /* Set 1st tx.in_flight as if 1st were sent by itself: */ -+ TCP_SKB_CB(skb)->tx.in_flight = inflight_prev + -+ tcp_skb_pcount(skb); -+ /* Set 2nd tx.in_flight with new 1st and 2nd pcounts: */ -+ TCP_SKB_CB(buff)->tx.in_flight = inflight_prev + -+ tcp_skb_pcount(skb) + -+ tcp_skb_pcount(buff); - } - - /* Link BUFF into the send queue. */ diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch deleted file mode 100644 index 898c976aa..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 4baad1b6a9c1e9f84e0e0a40d789382e0826e49a Mon Sep 17 00:00:00 2001 -From: Yousuk Seung -Date: Wed, 23 May 2018 17:55:54 -0700 -Subject: [PATCH 09/18] net-tcp: add new ca opts flag TCP_CONG_WANTS_CE_EVENTS - -Add a a new ca opts flag TCP_CONG_WANTS_CE_EVENTS that allows a -congestion control module to receive CE events. - -Currently congestion control modules have to set the TCP_CONG_NEEDS_ECN -bit in opts flag to receive CE events but this may incur changes in ECN -behavior elsewhere. This patch adds a new bit TCP_CONG_WANTS_CE_EVENTS -that allows congestion control modules to receive CE events -independently of TCP_CONG_NEEDS_ECN. - -Effort: net-tcp -Origin-9xx-SHA1: 9f7e14716cde760bc6c67ef8ef7e1ee48501d95b -Change-Id: I2255506985242f376d910c6fd37daabaf4744f24 -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 14 +++++++++++++- - net/ipv4/tcp_input.c | 4 ++-- - 2 files changed, 15 insertions(+), 3 deletions(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1035,7 +1035,11 @@ enum tcp_ca_ack_event_flags { - #define TCP_CONG_NON_RESTRICTED 0x1 - /* Requires ECN/ECT set on all packets */ - #define TCP_CONG_NEEDS_ECN 0x2 --#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN) -+/* Wants notification of CE events (CA_EVENT_ECN_IS_CE, CA_EVENT_ECN_NO_CE). */ -+#define TCP_CONG_WANTS_CE_EVENTS 0x4 -+#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | \ -+ TCP_CONG_NEEDS_ECN | \ -+ TCP_CONG_WANTS_CE_EVENTS) - - union tcp_cc_info; - -@@ -1167,6 +1171,14 @@ static inline char *tcp_ca_get_name_by_k - } - #endif - -+static inline bool tcp_ca_wants_ce_events(const struct sock *sk) -+{ -+ const struct inet_connection_sock *icsk = inet_csk(sk); -+ -+ return icsk->icsk_ca_ops->flags & (TCP_CONG_NEEDS_ECN | -+ TCP_CONG_WANTS_CE_EVENTS); -+} -+ - static inline bool tcp_ca_needs_ecn(const struct sock *sk) - { - const struct inet_connection_sock *icsk = inet_csk(sk); ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -376,7 +376,7 @@ static void __tcp_ecn_check_ce(struct so - tcp_enter_quickack_mode(sk, 2); - break; - case INET_ECN_CE: -- if (tcp_ca_needs_ecn(sk)) -+ if (tcp_ca_wants_ce_events(sk)) - tcp_ca_event(sk, CA_EVENT_ECN_IS_CE); - - if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { -@@ -387,7 +387,7 @@ static void __tcp_ecn_check_ce(struct so - tp->ecn_flags |= TCP_ECN_SEEN; - break; - default: -- if (tcp_ca_needs_ecn(sk)) -+ if (tcp_ca_wants_ce_events(sk)) - tcp_ca_event(sk, CA_EVENT_ECN_NO_CE); - tp->ecn_flags |= TCP_ECN_SEEN; - break; diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch deleted file mode 100644 index 4a7462ae4..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ /dev/null @@ -1,118 +0,0 @@ -From d703f42b8914209f615f18cd2ba296f4f25d66a3 Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Fri, 27 Sep 2019 17:10:26 -0400 -Subject: [PATCH 10/18] net-tcp: re-generalize TSO sizing in TCP CC module API - -Reorganize the API for CC modules so that the CC module once again -gets complete control of the TSO sizing decision. This is how the API -was set up around 2016 and the initial BBRv1 upstreaming. Later Eric -Dumazet simplified it. But with wider testing it now seems that to -avoid CPU regressions BBR needs to have a different TSO sizing -function. - -This is necessary to handle cases where there are many flows -bottlenecked on the sender host's NIC, in which case BBR's pacing rate -is much lower than CUBIC/Reno/DCTCP's. Why does this happen? Because -BBR's pacing rate adapts to the low bandwidth share each flow sees. By -contrast, CUBIC/Reno/DCTCP see no loss or ECN, so they grow a very -large cwnd, and thus large pacing rate and large TSO burst size. - -Change-Id: Ic8ccfdbe4010ee8d4bf6a6334c48a2fceb2171ea -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 4 ++-- - net/ipv4/tcp_bbr.c | 37 ++++++++++++++++++++++++++----------- - net/ipv4/tcp_output.c | 11 +++++------ - 3 files changed, 33 insertions(+), 19 deletions(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1101,8 +1101,8 @@ struct tcp_congestion_ops { - /* hook for packet ack accounting (optional) */ - void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); - -- /* override sysctl_tcp_min_tso_segs */ -- u32 (*min_tso_segs)(struct sock *sk); -+ /* pick target number of segments per TSO/GSO skb (optional): */ -+ u32 (*tso_segs)(struct sock *sk, unsigned int mss_now); - - /* react to a specific lost skb (optional) */ - void (*skb_marked_lost)(struct sock *sk, const struct sk_buff *skb); ---- a/net/ipv4/tcp_bbr.c -+++ b/net/ipv4/tcp_bbr.c -@@ -300,20 +300,35 @@ __bpf_kfunc static u32 bbr_min_tso_segs( - return sk->sk_pacing_rate < (bbr_min_tso_rate >> 3) ? 1 : 2; - } - -+/* Return the number of segments BBR would like in a TSO/GSO skb, given -+ * a particular max gso size as a constraint. -+ */ -+static u32 bbr_tso_segs_generic(struct sock *sk, unsigned int mss_now, -+ u32 gso_max_size) -+{ -+ u32 segs; -+ u64 bytes; -+ -+ /* Budget a TSO/GSO burst size allowance based on bw (pacing_rate). */ -+ bytes = sk->sk_pacing_rate >> sk->sk_pacing_shift; -+ -+ bytes = min_t(u32, bytes, gso_max_size - 1 - MAX_TCP_HEADER); -+ segs = max_t(u32, bytes / mss_now, bbr_min_tso_segs(sk)); -+ return segs; -+} -+ -+/* Custom tcp_tso_autosize() for BBR, used at transmit time to cap skb size. */ -+static u32 bbr_tso_segs(struct sock *sk, unsigned int mss_now) -+{ -+ return bbr_tso_segs_generic(sk, mss_now, sk->sk_gso_max_size); -+} -+ -+/* Like bbr_tso_segs(), using mss_cache, ignoring driver's sk_gso_max_size. */ - static u32 bbr_tso_segs_goal(struct sock *sk) - { - struct tcp_sock *tp = tcp_sk(sk); -- u32 segs, bytes; -- -- /* Sort of tcp_tso_autosize() but ignoring -- * driver provided sk_gso_max_size. -- */ -- bytes = min_t(unsigned long, -- sk->sk_pacing_rate >> READ_ONCE(sk->sk_pacing_shift), -- GSO_LEGACY_MAX_SIZE - 1 - MAX_TCP_HEADER); -- segs = max_t(u32, bytes / tp->mss_cache, bbr_min_tso_segs(sk)); - -- return min(segs, 0x7FU); -+ return bbr_tso_segs_generic(sk, tp->mss_cache, GSO_MAX_SIZE); - } - - /* Save "last known good" cwnd so we can restore it after losses or PROBE_RTT */ -@@ -1149,7 +1164,7 @@ static struct tcp_congestion_ops tcp_bbr - .undo_cwnd = bbr_undo_cwnd, - .cwnd_event = bbr_cwnd_event, - .ssthresh = bbr_ssthresh, -- .min_tso_segs = bbr_min_tso_segs, -+ .tso_segs = bbr_tso_segs, - .get_info = bbr_get_info, - .set_state = bbr_set_state, - }; ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -2022,13 +2022,12 @@ static u32 tcp_tso_autosize(const struct - static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) - { - const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; -- u32 min_tso, tso_segs; -+ u32 tso_segs; - -- min_tso = ca_ops->min_tso_segs ? -- ca_ops->min_tso_segs(sk) : -- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); -- -- tso_segs = tcp_tso_autosize(sk, mss_now, min_tso); -+ tso_segs = ca_ops->tso_segs ? -+ ca_ops->tso_segs(sk, mss_now) : -+ tcp_tso_autosize(sk, mss_now, -+ sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); - return min_t(u32, tso_segs, sk->sk_gso_max_segs); - } - diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch deleted file mode 100644 index 949a1d99f..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ /dev/null @@ -1,72 +0,0 @@ -From d40e81b25a4ebe05eee16c335e9698c09a9dfb14 Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Sat, 16 Nov 2019 13:16:25 -0500 -Subject: [PATCH 11/18] net-tcp: add fast_ack_mode=1: skip rwin check in - tcp_fast_ack_mode__tcp_ack_snd_check() - -Add logic for an experimental TCP connection behavior, enabled with -tp->fast_ack_mode = 1, which disables checking the receive window -before sending an ack in __tcp_ack_snd_check(). If this behavior is -enabled, the data receiver sends an ACK if the amount of data is > -RCV.MSS. - -Change-Id: Iaa0a0fd7108221f883137a79d5bfa724f1b096d4 -Signed-off-by: Alexandre Frade ---- - include/linux/tcp.h | 3 ++- - net/ipv4/tcp.c | 1 + - net/ipv4/tcp_cong.c | 1 + - net/ipv4/tcp_input.c | 5 +++-- - 4 files changed, 7 insertions(+), 3 deletions(-) - ---- a/include/linux/tcp.h -+++ b/include/linux/tcp.h -@@ -257,7 +257,8 @@ struct tcp_sock { - u8 compressed_ack; - u8 dup_ack_counter:2, - tlp_retrans:1, /* TLP is a retransmission */ -- unused:5; -+ fast_ack_mode:2, /* which fast ack mode ? */ -+ unused:3; - u32 chrono_start; /* Start time in jiffies of a TCP chrono */ - u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ - u8 chrono_type:2, /* current chronograph type */ ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -3099,6 +3099,7 @@ int tcp_disconnect(struct sock *sk, int - tp->rx_opt.dsack = 0; - tp->rx_opt.num_sacks = 0; - tp->rcv_ooopack = 0; -+ tp->fast_ack_mode = 0; - - - /* Clean up fastopen related fields */ ---- a/net/ipv4/tcp_cong.c -+++ b/net/ipv4/tcp_cong.c -@@ -240,6 +240,7 @@ void tcp_init_congestion_control(struct - struct inet_connection_sock *icsk = inet_csk(sk); - - tcp_sk(sk)->prior_ssthresh = 0; -+ tcp_sk(sk)->fast_ack_mode = 0; - if (icsk->icsk_ca_ops->init) - icsk->icsk_ca_ops->init(sk); - if (tcp_ca_needs_ecn(sk)) ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -5621,13 +5621,14 @@ static void __tcp_ack_snd_check(struct s - - /* More than one full frame received... */ - if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && -+ (tp->fast_ack_mode == 1 || - /* ... and right edge of window advances far enough. - * (tcp_recvmsg() will send ACK otherwise). - * If application uses SO_RCVLOWAT, we want send ack now if - * we have not received enough bytes to satisfy the condition. - */ -- (tp->rcv_nxt - tp->copied_seq < sk->sk_rcvlowat || -- __tcp_select_window(sk) >= tp->rcv_wnd)) || -+ (tp->rcv_nxt - tp->copied_seq < sk->sk_rcvlowat || -+ __tcp_select_window(sk) >= tp->rcv_wnd))) || - /* We ACK each frame or... */ - tcp_in_quickack_mode(sk) || - /* Protocol state mandates a one-time immediate ACK */ diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch deleted file mode 100644 index 1a5b4e1e9..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ /dev/null @@ -1,45 +0,0 @@ -From f59611bea9c062fb44ecb9040f074cac359e2993 Mon Sep 17 00:00:00 2001 -From: Jianfeng Wang -Date: Fri, 19 Jun 2020 17:33:45 +0000 -Subject: [PATCH 12/18] net-tcp_bbr: v2: record app-limited status of - TLP-repaired flight - -When sending a TLP retransmit, record whether the outstanding flight -of data is application limited. This is important for congestion -control modules that want to respond to losses repaired by TLP -retransmits. This is important because the following scenarios convey -very different information: - (1) a packet loss with a small number of packets in flight; - (2) a packet loss with the maximum amount of data in flight allowed - by the CC module; - -Effort: net-tcp_bbr -Change-Id: Ic8ae567caa4e4bfd5fd82c3d4be12a5d9171655e -Signed-off-by: Alexandre Frade ---- - include/linux/tcp.h | 3 ++- - net/ipv4/tcp_output.c | 1 + - 2 files changed, 3 insertions(+), 1 deletion(-) - ---- a/include/linux/tcp.h -+++ b/include/linux/tcp.h -@@ -258,7 +258,8 @@ struct tcp_sock { - u8 dup_ack_counter:2, - tlp_retrans:1, /* TLP is a retransmission */ - fast_ack_mode:2, /* which fast ack mode ? */ -- unused:3; -+ tlp_orig_data_app_limited:1, /* app-limited before TLP rtx? */ -+ unused:2; - u32 chrono_start; /* Start time in jiffies of a TCP chrono */ - u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ - u8 chrono_type:2, /* current chronograph type */ ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -2940,6 +2940,7 @@ void tcp_send_loss_probe(struct sock *sk - if (WARN_ON(!skb || !tcp_skb_pcount(skb))) - goto rearm_timer; - -+ tp->tlp_orig_data_app_limited = TCP_SKB_CB(skb)->tx.is_app_limited; - if (__tcp_retransmit_skb(sk, skb, 1)) - goto rearm_timer; - diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch deleted file mode 100644 index 034ff70e4..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 46024649ecd254cf303f2104406c6ffff3dce343 Mon Sep 17 00:00:00 2001 -From: Jianfeng Wang -Date: Tue, 16 Jun 2020 17:41:19 +0000 -Subject: [PATCH 13/18] net-tcp_bbr: v2: inform CC module of losses repaired by - TLP probe - -Before this commit, when there is a packet loss that creates a sequence -hole that is filled by a TLP loss probe, then tcp_process_tlp_ack() -only informs the congestion control (CC) module via a back-to-back entry -and exit of CWR. But some congestion control modules (e.g. BBR) do not -respond to CWR events. - -This commit adds a new CA event with which the core TCP stack notifies -the CC module when a loss is repaired by a TLP. This will allow CC -modules that do not use the CWR mechanism to have a custom handler for -such TLP recoveries. - -Effort: net-tcp_bbr -Change-Id: Ieba72332b401b329bff5a641d2b2043a3fb8f632 -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 1 + - net/ipv4/tcp_input.c | 1 + - 2 files changed, 2 insertions(+) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1013,6 +1013,7 @@ enum tcp_ca_event { - CA_EVENT_LOSS, /* loss timeout */ - CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ - CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ -+ CA_EVENT_TLP_RECOVERY, /* a lost segment was repaired by TLP probe */ - }; - - /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -3772,6 +3772,7 @@ static void tcp_process_tlp_ack(struct s - /* ACK advances: there was a loss, so reduce cwnd. Reset - * tlp_high_seq in tcp_init_cwnd_reduction() - */ -+ tcp_ca_event(sk, CA_EVENT_TLP_RECOVERY); - tcp_init_cwnd_reduction(sk); - tcp_set_ca_state(sk, TCP_CA_CWR); - tcp_end_cwnd_reduction(sk); diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch deleted file mode 100644 index 0a3016365..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 3996591ce3544d9defec725579123f5d4867524c Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Mon, 21 Sep 2020 14:46:26 -0400 -Subject: [PATCH 14/18] net-tcp_bbr: v2: introduce is_acking_tlp_retrans_seq - into rate_sample - -Introduce is_acking_tlp_retrans_seq into rate_sample. This bool will -export to the CC module the knowledge of whether the current ACK -matched a TLP retransmit. - -Note that when this bool is true, we cannot yet tell (in general) whether -this ACK is for the original or the TLP retransmit. - -Effort: net-tcp_bbr -Change-Id: I2e6494332167e75efcbdc99bd5c119034e9c39b4 -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 1 + - net/ipv4/tcp_input.c | 12 +++++++++--- - 2 files changed, 10 insertions(+), 3 deletions(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1077,6 +1077,7 @@ struct rate_sample { - u32 last_end_seq; /* end_seq of most recently ACKed packet */ - bool is_app_limited; /* is sample from packet with bubble in pipe? */ - bool is_retrans; /* is sample from retransmission? */ -+ bool is_acking_tlp_retrans_seq; /* ACKed a TLP retransmit sequence? */ - bool is_ack_delayed; /* is this (likely) a delayed ACK? */ - bool is_ece; /* did this ACK have ECN marked? */ - }; ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -3755,7 +3755,8 @@ static void tcp_replace_ts_recent(struct - /* This routine deals with acks during a TLP episode and ends an episode by - * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack - */ --static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) -+static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag, -+ struct rate_sample *rs) - { - struct tcp_sock *tp = tcp_sk(sk); - -@@ -3783,6 +3784,11 @@ static void tcp_process_tlp_ack(struct s - FLAG_NOT_DUP | FLAG_DATA_SACKED))) { - /* Pure dupack: original and TLP probe arrived; no loss */ - tp->tlp_high_seq = 0; -+ } else { -+ /* This ACK matches a TLP retransmit. We cannot yet tell if -+ * this ACK is for the original or the TLP retransmit. -+ */ -+ rs->is_acking_tlp_retrans_seq = 1; - } - } - -@@ -3966,7 +3972,7 @@ static int tcp_ack(struct sock *sk, cons - tcp_rack_update_reo_wnd(sk, &rs); - - if (tp->tlp_high_seq) -- tcp_process_tlp_ack(sk, ack, flag); -+ tcp_process_tlp_ack(sk, ack, flag, &rs); - - if (tcp_ack_is_dubious(sk, flag)) { - if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4010,7 +4016,7 @@ no_queue: - tcp_ack_probe(sk); - - if (tp->tlp_high_seq) -- tcp_process_tlp_ack(sk, ack, flag); -+ tcp_process_tlp_ack(sk, ack, flag, &rs); - return 1; - - old_ack: diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch deleted file mode 100644 index 8c0149819..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch +++ /dev/null @@ -1,109 +0,0 @@ -From bcdadb3893c94dfde67954ec71eb983b6bdb08c1 Mon Sep 17 00:00:00 2001 -From: David Morley -Date: Fri, 14 Jul 2023 11:07:56 -0400 -Subject: [PATCH 15/18] tcp: introduce per-route feature RTAX_FEATURE_ECN_LOW - -Define and implement a new per-route feature, RTAX_FEATURE_ECN_LOW. - -This feature indicates that the given destination network is a -low-latency ECN environment, meaning both that ECN CE marks are -applied by the network using a low-latency marking threshold and also -that TCP endpoints provide precise per-data-segment ECN feedback in -ACKs (where the ACK ECE flag echoes the received CE status of all -newly-acknowledged data segments). This feature indication can be used -by congestion control algorithms to decide how to interpret ECN -signals over the given destination network. - -This feature is appropriate for datacenter-style ECN marking, such as -the ECN marking approach expected by DCTCP or BBR congestion control -modules. - -Signed-off-by: David Morley -Signed-off-by: Neal Cardwell -Signed-off-by: Yuchung Cheng -Tested-by: David Morley -Change-Id: I6bc06e9c6cb426fbae7243fc71c9a8c18175f5d3 -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 10 ++++++++++ - include/uapi/linux/rtnetlink.h | 4 +++- - net/ipv4/tcp_minisocks.c | 2 ++ - net/ipv4/tcp_output.c | 6 ++++-- - 4 files changed, 19 insertions(+), 3 deletions(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -372,6 +372,7 @@ static inline void tcp_dec_quickack_mode - #define TCP_ECN_QUEUE_CWR 2 - #define TCP_ECN_DEMAND_CWR 4 - #define TCP_ECN_SEEN 8 -+#define TCP_ECN_LOW 16 - - enum tcp_tw_status { - TCP_TW_SUCCESS = 0, -@@ -726,6 +727,15 @@ static inline void tcp_fast_path_check(s - - u32 tcp_delack_max(const struct sock *sk); - -+static inline void tcp_set_ecn_low_from_dst(struct sock *sk, -+ const struct dst_entry *dst) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ -+ if (dst_feature(dst, RTAX_FEATURE_ECN_LOW)) -+ tp->ecn_flags |= TCP_ECN_LOW; -+} -+ - /* Compute the actual rto_min value */ - static inline u32 tcp_rto_min(struct sock *sk) - { ---- a/include/uapi/linux/rtnetlink.h -+++ b/include/uapi/linux/rtnetlink.h -@@ -506,9 +506,11 @@ enum { - #define RTAX_FEATURE_SACK (1 << 1) - #define RTAX_FEATURE_TIMESTAMP (1 << 2) - #define RTAX_FEATURE_ALLFRAG (1 << 3) -+#define RTAX_FEATURE_ECN_LOW (1 << 4) - - #define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | \ -- RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG) -+ RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG \ -+ | RTAX_FEATURE_ECN_LOW) - - struct rta_session { - __u8 proto; ---- a/net/ipv4/tcp_minisocks.c -+++ b/net/ipv4/tcp_minisocks.c -@@ -434,6 +434,8 @@ void tcp_ca_openreq_child(struct sock *s - u32 ca_key = dst_metric(dst, RTAX_CC_ALGO); - bool ca_got_dst = false; - -+ tcp_set_ecn_low_from_dst(sk, dst); -+ - if (ca_key != TCP_CA_UNSPEC) { - const struct tcp_congestion_ops *ca; - ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -334,10 +334,9 @@ static void tcp_ecn_send_syn(struct sock - bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk); - bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 || - tcp_ca_needs_ecn(sk) || bpf_needs_ecn; -+ const struct dst_entry *dst = __sk_dst_get(sk); - - if (!use_ecn) { -- const struct dst_entry *dst = __sk_dst_get(sk); -- - if (dst && dst_feature(dst, RTAX_FEATURE_ECN)) - use_ecn = true; - } -@@ -349,6 +348,9 @@ static void tcp_ecn_send_syn(struct sock - tp->ecn_flags = TCP_ECN_OK; - if (tcp_ca_needs_ecn(sk) || bpf_needs_ecn) - INET_ECN_xmit(sk); -+ -+ if (dst) -+ tcp_set_ecn_low_from_dst(sk, dst); - } - } - diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch deleted file mode 100644 index ddd23a2d9..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ /dev/null @@ -1,2823 +0,0 @@ -From 6caa9d6b181856844e351866f186a1da3321c2b3 Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Tue, 11 Jun 2019 12:54:22 -0400 -Subject: [PATCH 16/18] net-tcp_bbr: v3: update TCP "bbr" congestion control - module to BBRv3 - -BBR v3 is an enhacement to the BBR v1 algorithm. It's designed to aim for lower -queues, lower loss, and better Reno/CUBIC coexistence than BBR v1. - -BBR v3 maintains the core of BBR v1: an explicit model of the network -path that is two-dimensional, adapting to estimate the (a) maximum -available bandwidth and (b) maximum safe volume of data a flow can -keep in-flight in the network. It maintains the estimated BDP as a -core guide for estimating an appropriate level of in-flight data. - -BBR v3 makes several key enhancements: - -o Its bandwidth-probing time scale is adapted, within bounds, to allow improved -coexistence with Reno and CUBIC. The bandwidth-probing time scale is (a) -extended dynamically based on estimated BDP to improve coexistence with -Reno/CUBIC; (b) bounded by an interactive wall-clock time-scale to be more -scalable and responsive than Reno and CUBIC. - -o Rather than being largely agnostic to loss and ECN marks, it explicitly uses -loss and (DCTCP-style) ECN signals to maintain its model. - -o It aims for lower losses than v1 by adjusting its model to attempt to stay -within loss rate and ECN mark rate bounds (loss_thresh and ecn_thresh, -respectively). - -o It adapts to loss/ECN signals even when the application is running out of -data ("application-limited"), in case the "application-limited" flow is also -"network-limited" (the bw and/or inflight available to this flow is lower than -previously estimated when the flow ran out of data). - -o It has a three-part model: the model explicit three tracks operating points, -where an operating point is a tuple: (bandwidth, inflight). The three operating -points are: - - o latest: the latest measurement from the current round trip - o upper bound: robust, optimistic, long-term upper bound - o lower bound: robust, conservative, short-term lower bound - -These are stored in the following state variables: - - o latest: bw_latest, inflight_latest - o lo: bw_lo, inflight_lo - o hi: bw_hi[2], inflight_hi - -To gain intuition about the meaning of the three operating points, it -may help to consider the analogs in CUBIC, which has a somewhat -analogous three-part model used by its probing state machine: - - BBR param CUBIC param - ----------- ------------- - latest ~ cwnd - lo ~ ssthresh - hi ~ last_max_cwnd - -The analogy is only a loose one, though, since the BBR operating -points are calculated differently, and are 2-dimensional (bw,inflight) -rather than CUBIC's one-dimensional notion of operating point -(inflight). - -o It uses the three-part model to adapt the magnitude of its bandwidth -to match the estimated space available in the buffer, rather than (as -in BBR v1) assuming that it was always acceptable to place 0.25*BDP in -the bottleneck buffer when probing (commodity datacenter switches -commonly do not have that much buffer for WAN flows). When BBR v3 -estimates it hit a buffer limit during probing, its bandwidth probing -then starts gently in case little space is still available in the -buffer, and the accelerates, slowly at first and then rapidly if it -can grow inflight without seeing congestion signals. In such cases, -probing is bounded by inflight_hi + inflight_probe, where -inflight_probe grows as: [0, 1, 2, 4, 8, 16,...]. This allows BBR to -keep losses low and bounded if a bottleneck remains congested, while -rapidly/scalably utilizing free bandwidth when it becomes available. - -o It has a slightly revised state machine, to achieve the goals above. - BBR_BW_PROBE_UP: pushes up inflight to probe for bw/vol - BBR_BW_PROBE_DOWN: drain excess inflight from the queue - BBR_BW_PROBE_CRUISE: use pipe, w/ headroom in queue/pipe - BBR_BW_PROBE_REFILL: try refill the pipe again to 100%, leaving queue empty - -o The estimated BDP: BBR v3 continues to maintain an estimate of the -path's two-way propagation delay, by tracking a windowed min_rtt, and -coordinating (on an as-ndeeded basis) to try to expose the two-way -propagation delay by draining the bottleneck queue. - -BBR v3 continues to use its min_rtt and (currently-applicable) bandwidth -estimate to estimate the current bandwidth-delay product. The estimated BDP -still provides one important guideline for bounding inflight data. However, -because any min-filtered RTT and max-filtered bw inherently tend to both -overestimate, the estimated BDP is often too high; in this case loss or ECN -marks can ensue, in which case BBR v3 adjusts inflight_hi and inflight_lo to -adapt its sending rate and inflight down to match the available capacity of the -path. - -o Space: Note that ICSK_CA_PRIV_SIZE increased. This is because BBR v3 -requires more space. Note that much of the space is due to support for -per-socket parameterization and debugging in this release for research -and debugging. With that state removed, the full "struct bbr" is 140 -bytes, or 144 with padding. This is an increase of 40 bytes over the -existing ca_priv space. - -o Code: BBR v3 reuses many pieces from BBR v1. But it omits the following - significant pieces: - - o "packet conservation" (bbr_set_cwnd_to_recover_or_restore(), - bbr_can_grow_inflight()) - o long-term bandwidth estimator ("policer mode") - - The code layout tries to keep BBR v3 code near the bottom of the - file, so that v1-applicable code in the top does not accidentally - refer to v3 code. - -o Docs: - See the following docs for more details and diagrams decsribing the BBR v3 - algorithm: - https://datatracker.ietf.org/meeting/104/materials/slides-104-iccrg-an-update-on-bbr-00 - https://datatracker.ietf.org/meeting/102/materials/slides-102-iccrg-an-update-on-bbr-work-at-google-00 - -o Internal notes: - For this upstream rebase, Neal started from: - git show fed518041ac6:net/ipv4/tcp_bbr.c > net/ipv4/tcp_bbr.c - then removed dev instrumentation (dynamic get/set for parameters) - and code that was only used by BBRv1 - -Effort: net-tcp_bbr -Origin-9xx-SHA1: 2c84098e60bed6d67dde23cd7538c51dee273102 -Change-Id: I125cf26ba2a7a686f2fa5e87f4c2afceb65f7a05 -Signed-off-by: Alexandre Frade ---- - include/net/inet_connection_sock.h | 4 +- - include/net/tcp.h | 2 +- - include/uapi/linux/inet_diag.h | 23 + - net/ipv4/Kconfig | 21 +- - net/ipv4/tcp_bbr.c | 2217 +++++++++++++++++++++------- - 5 files changed, 1742 insertions(+), 525 deletions(-) - ---- a/include/net/inet_connection_sock.h -+++ b/include/net/inet_connection_sock.h -@@ -135,8 +135,8 @@ struct inet_connection_sock { - u32 icsk_probes_tstamp; - u32 icsk_user_timeout; - -- u64 icsk_ca_priv[104 / sizeof(u64)]; --#define ICSK_CA_PRIV_SIZE sizeof_field(struct inet_connection_sock, icsk_ca_priv) -+#define ICSK_CA_PRIV_SIZE (144) -+ u64 icsk_ca_priv[ICSK_CA_PRIV_SIZE / sizeof(u64)]; - }; - - #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -2269,7 +2269,7 @@ struct tcp_plb_state { - u8 consec_cong_rounds:5, /* consecutive congested rounds */ - unused:3; - u32 pause_until; /* jiffies32 when PLB can resume rerouting */ --}; -+} __attribute__ ((__packed__)); - - static inline void tcp_plb_init(const struct sock *sk, - struct tcp_plb_state *plb) ---- a/include/uapi/linux/inet_diag.h -+++ b/include/uapi/linux/inet_diag.h -@@ -229,6 +229,29 @@ struct tcp_bbr_info { - __u32 bbr_min_rtt; /* min-filtered RTT in uSec */ - __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */ - __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */ -+ __u32 bbr_bw_hi_lsb; /* lower 32 bits of bw_hi */ -+ __u32 bbr_bw_hi_msb; /* upper 32 bits of bw_hi */ -+ __u32 bbr_bw_lo_lsb; /* lower 32 bits of bw_lo */ -+ __u32 bbr_bw_lo_msb; /* upper 32 bits of bw_lo */ -+ __u8 bbr_mode; /* current bbr_mode in state machine */ -+ __u8 bbr_phase; /* current state machine phase */ -+ __u8 unused1; /* alignment padding; not used yet */ -+ __u8 bbr_version; /* BBR algorithm version */ -+ __u32 bbr_inflight_lo; /* lower short-term data volume bound */ -+ __u32 bbr_inflight_hi; /* higher long-term data volume bound */ -+ __u32 bbr_extra_acked; /* max excess packets ACKed in epoch */ -+}; -+ -+/* TCP BBR congestion control bbr_phase as reported in netlink/ss stats. */ -+enum tcp_bbr_phase { -+ BBR_PHASE_INVALID = 0, -+ BBR_PHASE_STARTUP = 1, -+ BBR_PHASE_DRAIN = 2, -+ BBR_PHASE_PROBE_RTT = 3, -+ BBR_PHASE_PROBE_BW_UP = 4, -+ BBR_PHASE_PROBE_BW_DOWN = 5, -+ BBR_PHASE_PROBE_BW_CRUISE = 6, -+ BBR_PHASE_PROBE_BW_REFILL = 7, - }; - - union tcp_cc_info { ---- a/net/ipv4/Kconfig -+++ b/net/ipv4/Kconfig -@@ -668,15 +668,18 @@ config TCP_CONG_BBR - default n - help - -- BBR (Bottleneck Bandwidth and RTT) TCP congestion control aims to -- maximize network utilization and minimize queues. It builds an explicit -- model of the bottleneck delivery rate and path round-trip propagation -- delay. It tolerates packet loss and delay unrelated to congestion. It -- can operate over LAN, WAN, cellular, wifi, or cable modem links. It can -- coexist with flows that use loss-based congestion control, and can -- operate with shallow buffers, deep buffers, bufferbloat, policers, or -- AQM schemes that do not provide a delay signal. It requires the fq -- ("Fair Queue") pacing packet scheduler. -+ BBR (Bottleneck Bandwidth and RTT) TCP congestion control is a -+ model-based congestion control algorithm that aims to maximize -+ network utilization, keep queues and retransmit rates low, and to be -+ able to coexist with Reno/CUBIC in common scenarios. It builds an -+ explicit model of the network path. It tolerates a targeted degree -+ of random packet loss and delay. It can operate over LAN, WAN, -+ cellular, wifi, or cable modem links, and can use shallow-threshold -+ ECN signals. It can coexist to some degree with flows that use -+ loss-based congestion control, and can operate with shallow buffers, -+ deep buffers, bufferbloat, policers, or AQM schemes that do not -+ provide a delay signal. It requires pacing, using either TCP internal -+ pacing or the fq ("Fair Queue") pacing packet scheduler. - - choice - prompt "Default TCP congestion control" ---- a/net/ipv4/tcp_bbr.c -+++ b/net/ipv4/tcp_bbr.c -@@ -1,18 +1,19 @@ --/* Bottleneck Bandwidth and RTT (BBR) congestion control -+/* BBR (Bottleneck Bandwidth and RTT) congestion control - * -- * BBR congestion control computes the sending rate based on the delivery -- * rate (throughput) estimated from ACKs. In a nutshell: -+ * BBR is a model-based congestion control algorithm that aims for low queues, -+ * low loss, and (bounded) Reno/CUBIC coexistence. To maintain a model of the -+ * network path, it uses measurements of bandwidth and RTT, as well as (if they -+ * occur) packet loss and/or shallow-threshold ECN signals. Note that although -+ * it can use ECN or loss signals explicitly, it does not require either; it -+ * can bound its in-flight data based on its estimate of the BDP. - * -- * On each ACK, update our model of the network path: -- * bottleneck_bandwidth = windowed_max(delivered / elapsed, 10 round trips) -- * min_rtt = windowed_min(rtt, 10 seconds) -- * pacing_rate = pacing_gain * bottleneck_bandwidth -- * cwnd = max(cwnd_gain * bottleneck_bandwidth * min_rtt, 4) -- * -- * The core algorithm does not react directly to packet losses or delays, -- * although BBR may adjust the size of next send per ACK when loss is -- * observed, or adjust the sending rate if it estimates there is a -- * traffic policer, in order to keep the drop rate reasonable. -+ * The model has both higher and lower bounds for the operating range: -+ * lo: bw_lo, inflight_lo: conservative short-term lower bound -+ * hi: bw_hi, inflight_hi: robust long-term upper bound -+ * The bandwidth-probing time scale is (a) extended dynamically based on -+ * estimated BDP to improve coexistence with Reno/CUBIC; (b) bounded by -+ * an interactive wall-clock time-scale to be more scalable and responsive -+ * than Reno and CUBIC. - * - * Here is a state transition diagram for BBR: - * -@@ -65,6 +66,13 @@ - #include - #include - -+#include -+#include "tcp_dctcp.h" -+ -+#define BBR_VERSION 3 -+ -+#define bbr_param(sk,name) (bbr_ ## name) -+ - /* Scale factor for rate in pkt/uSec unit to avoid truncation in bandwidth - * estimation. The rate unit ~= (1500 bytes / 1 usec / 2^24) ~= 715 bps. - * This handles bandwidths from 0.06pps (715bps) to 256Mpps (3Tbps) in a u32. -@@ -85,36 +93,41 @@ enum bbr_mode { - BBR_PROBE_RTT, /* cut inflight to min to probe min_rtt */ - }; - -+/* How does the incoming ACK stream relate to our bandwidth probing? */ -+enum bbr_ack_phase { -+ BBR_ACKS_INIT, /* not probing; not getting probe feedback */ -+ BBR_ACKS_REFILLING, /* sending at est. bw to fill pipe */ -+ BBR_ACKS_PROBE_STARTING, /* inflight rising to probe bw */ -+ BBR_ACKS_PROBE_FEEDBACK, /* getting feedback from bw probing */ -+ BBR_ACKS_PROBE_STOPPING, /* stopped probing; still getting feedback */ -+}; -+ - /* BBR congestion control block */ - struct bbr { - u32 min_rtt_us; /* min RTT in min_rtt_win_sec window */ - u32 min_rtt_stamp; /* timestamp of min_rtt_us */ - u32 probe_rtt_done_stamp; /* end time for BBR_PROBE_RTT mode */ -- struct minmax bw; /* Max recent delivery rate in pkts/uS << 24 */ -- u32 rtt_cnt; /* count of packet-timed rounds elapsed */ -+ u32 probe_rtt_min_us; /* min RTT in probe_rtt_win_ms win */ -+ u32 probe_rtt_min_stamp; /* timestamp of probe_rtt_min_us*/ - u32 next_rtt_delivered; /* scb->tx.delivered at end of round */ - u64 cycle_mstamp; /* time of this cycle phase start */ -- u32 mode:3, /* current bbr_mode in state machine */ -+ u32 mode:2, /* current bbr_mode in state machine */ - prev_ca_state:3, /* CA state on previous ACK */ -- packet_conservation:1, /* use packet conservation? */ - round_start:1, /* start of packet-timed tx->ack round? */ -+ ce_state:1, /* If most recent data has CE bit set */ -+ bw_probe_up_rounds:5, /* cwnd-limited rounds in PROBE_UP */ -+ try_fast_path:1, /* can we take fast path? */ - idle_restart:1, /* restarting after idle? */ - probe_rtt_round_done:1, /* a BBR_PROBE_RTT round at 4 pkts? */ -- unused:13, -- lt_is_sampling:1, /* taking long-term ("LT") samples now? */ -- lt_rtt_cnt:7, /* round trips in long-term interval */ -- lt_use_bw:1; /* use lt_bw as our bw estimate? */ -- u32 lt_bw; /* LT est delivery rate in pkts/uS << 24 */ -- u32 lt_last_delivered; /* LT intvl start: tp->delivered */ -- u32 lt_last_stamp; /* LT intvl start: tp->delivered_mstamp */ -- u32 lt_last_lost; /* LT intvl start: tp->lost */ -+ init_cwnd:7, /* initial cwnd */ -+ unused_1:10; - u32 pacing_gain:10, /* current gain for setting pacing rate */ - cwnd_gain:10, /* current gain for setting cwnd */ - full_bw_reached:1, /* reached full bw in Startup? */ - full_bw_cnt:2, /* number of rounds without large bw gains */ -- cycle_idx:3, /* current index in pacing_gain cycle array */ -+ cycle_idx:2, /* current index in pacing_gain cycle array */ - has_seen_rtt:1, /* have we seen an RTT sample yet? */ -- unused_b:5; -+ unused_2:6; - u32 prior_cwnd; /* prior cwnd upon entering loss recovery */ - u32 full_bw; /* recent bw, to estimate if pipe is full */ - -@@ -124,19 +137,67 @@ struct bbr { - u32 ack_epoch_acked:20, /* packets (S)ACKed in sampling epoch */ - extra_acked_win_rtts:5, /* age of extra_acked, in round trips */ - extra_acked_win_idx:1, /* current index in extra_acked array */ -- unused_c:6; -+ /* BBR v3 state: */ -+ full_bw_now:1, /* recently reached full bw plateau? */ -+ startup_ecn_rounds:2, /* consecutive hi ECN STARTUP rounds */ -+ loss_in_cycle:1, /* packet loss in this cycle? */ -+ ecn_in_cycle:1, /* ECN in this cycle? */ -+ unused_3:1; -+ u32 loss_round_delivered; /* scb->tx.delivered ending loss round */ -+ u32 undo_bw_lo; /* bw_lo before latest losses */ -+ u32 undo_inflight_lo; /* inflight_lo before latest losses */ -+ u32 undo_inflight_hi; /* inflight_hi before latest losses */ -+ u32 bw_latest; /* max delivered bw in last round trip */ -+ u32 bw_lo; /* lower bound on sending bandwidth */ -+ u32 bw_hi[2]; /* max recent measured bw sample */ -+ u32 inflight_latest; /* max delivered data in last round trip */ -+ u32 inflight_lo; /* lower bound of inflight data range */ -+ u32 inflight_hi; /* upper bound of inflight data range */ -+ u32 bw_probe_up_cnt; /* packets delivered per inflight_hi incr */ -+ u32 bw_probe_up_acks; /* packets (S)ACKed since inflight_hi incr */ -+ u32 probe_wait_us; /* PROBE_DOWN until next clock-driven probe */ -+ u32 prior_rcv_nxt; /* tp->rcv_nxt when CE state last changed */ -+ u32 ecn_eligible:1, /* sender can use ECN (RTT, handshake)? */ -+ ecn_alpha:9, /* EWMA delivered_ce/delivered; 0..256 */ -+ bw_probe_samples:1, /* rate samples reflect bw probing? */ -+ prev_probe_too_high:1, /* did last PROBE_UP go too high? */ -+ stopped_risky_probe:1, /* last PROBE_UP stopped due to risk? */ -+ rounds_since_probe:8, /* packet-timed rounds since probed bw */ -+ loss_round_start:1, /* loss_round_delivered round trip? */ -+ loss_in_round:1, /* loss marked in this round trip? */ -+ ecn_in_round:1, /* ECN marked in this round trip? */ -+ ack_phase:3, /* bbr_ack_phase: meaning of ACKs */ -+ loss_events_in_round:4,/* losses in STARTUP round */ -+ initialized:1; /* has bbr_init() been called? */ -+ u32 alpha_last_delivered; /* tp->delivered at alpha update */ -+ u32 alpha_last_delivered_ce; /* tp->delivered_ce at alpha update */ -+ -+ u8 unused_4; /* to preserve alignment */ -+ struct tcp_plb_state plb; - }; - --#define CYCLE_LEN 8 /* number of phases in a pacing gain cycle */ -+struct bbr_context { -+ u32 sample_bw; -+}; - --/* Window length of bw filter (in rounds): */ --static const int bbr_bw_rtts = CYCLE_LEN + 2; - /* Window length of min_rtt filter (in sec): */ - static const u32 bbr_min_rtt_win_sec = 10; - /* Minimum time (in ms) spent at bbr_cwnd_min_target in BBR_PROBE_RTT mode: */ - static const u32 bbr_probe_rtt_mode_ms = 200; --/* Skip TSO below the following bandwidth (bits/sec): */ --static const int bbr_min_tso_rate = 1200000; -+/* Window length of probe_rtt_min_us filter (in ms), and consequently the -+ * typical interval between PROBE_RTT mode entries. The default is 5000ms. -+ * Note that bbr_probe_rtt_win_ms must be <= bbr_min_rtt_win_sec * MSEC_PER_SEC -+ */ -+static const u32 bbr_probe_rtt_win_ms = 5000; -+/* Proportion of cwnd to estimated BDP in PROBE_RTT, in units of BBR_UNIT: */ -+static const u32 bbr_probe_rtt_cwnd_gain = BBR_UNIT * 1 / 2; -+ -+/* Use min_rtt to help adapt TSO burst size, with smaller min_rtt resulting -+ * in bigger TSO bursts. We cut the RTT-based allowance in half -+ * for every 2^9 usec (aka 512 us) of RTT, so that the RTT-based allowance -+ * is below 1500 bytes after 6 * ~500 usec = 3ms. -+ */ -+static const u32 bbr_tso_rtt_shift = 9; - - /* Pace at ~1% below estimated bw, on average, to reduce queue at bottleneck. - * In order to help drive the network toward lower queues and low latency while -@@ -146,13 +207,15 @@ static const int bbr_min_tso_rate = 1200 - */ - static const int bbr_pacing_margin_percent = 1; - --/* We use a high_gain value of 2/ln(2) because it's the smallest pacing gain -+/* We use a startup_pacing_gain of 4*ln(2) because it's the smallest value - * that will allow a smoothly increasing pacing rate that will double each RTT - * and send the same number of packets per RTT that an un-paced, slow-starting - * Reno or CUBIC flow would: - */ --static const int bbr_high_gain = BBR_UNIT * 2885 / 1000 + 1; --/* The pacing gain of 1/high_gain in BBR_DRAIN is calculated to typically drain -+static const int bbr_startup_pacing_gain = BBR_UNIT * 277 / 100 + 1; -+/* The gain for deriving startup cwnd: */ -+static const int bbr_startup_cwnd_gain = BBR_UNIT * 2; -+/* The pacing gain in BBR_DRAIN is calculated to typically drain - * the queue created in BBR_STARTUP in a single round: - */ - static const int bbr_drain_gain = BBR_UNIT * 1000 / 2885; -@@ -160,13 +223,17 @@ static const int bbr_drain_gain = BBR_UN - static const int bbr_cwnd_gain = BBR_UNIT * 2; - /* The pacing_gain values for the PROBE_BW gain cycle, to discover/share bw: */ - static const int bbr_pacing_gain[] = { -- BBR_UNIT * 5 / 4, /* probe for more available bw */ -- BBR_UNIT * 3 / 4, /* drain queue and/or yield bw to other flows */ -- BBR_UNIT, BBR_UNIT, BBR_UNIT, /* cruise at 1.0*bw to utilize pipe, */ -- BBR_UNIT, BBR_UNIT, BBR_UNIT /* without creating excess queue... */ -+ BBR_UNIT * 5 / 4, /* UP: probe for more available bw */ -+ BBR_UNIT * 91 / 100, /* DOWN: drain queue and/or yield bw */ -+ BBR_UNIT, /* CRUISE: try to use pipe w/ some headroom */ -+ BBR_UNIT, /* REFILL: refill pipe to estimated 100% */ -+}; -+enum bbr_pacing_gain_phase { -+ BBR_BW_PROBE_UP = 0, /* push up inflight to probe for bw/vol */ -+ BBR_BW_PROBE_DOWN = 1, /* drain excess inflight from the queue */ -+ BBR_BW_PROBE_CRUISE = 2, /* use pipe, w/ headroom in queue/pipe */ -+ BBR_BW_PROBE_REFILL = 3, /* v2: refill the pipe again to 100% */ - }; --/* Randomize the starting gain cycling phase over N phases: */ --static const u32 bbr_cycle_rand = 7; - - /* Try to keep at least this many packets in flight, if things go smoothly. For - * smooth functioning, a sliding window protocol ACKing every other packet -@@ -174,24 +241,12 @@ static const u32 bbr_cycle_rand = 7; - */ - static const u32 bbr_cwnd_min_target = 4; - --/* To estimate if BBR_STARTUP mode (i.e. high_gain) has filled pipe... */ -+/* To estimate if BBR_STARTUP or BBR_BW_PROBE_UP has filled pipe... */ - /* If bw has increased significantly (1.25x), there may be more bw available: */ - static const u32 bbr_full_bw_thresh = BBR_UNIT * 5 / 4; - /* But after 3 rounds w/o significant bw growth, estimate pipe is full: */ - static const u32 bbr_full_bw_cnt = 3; - --/* "long-term" ("LT") bandwidth estimator parameters... */ --/* The minimum number of rounds in an LT bw sampling interval: */ --static const u32 bbr_lt_intvl_min_rtts = 4; --/* If lost/delivered ratio > 20%, interval is "lossy" and we may be policed: */ --static const u32 bbr_lt_loss_thresh = 50; --/* If 2 intervals have a bw ratio <= 1/8, their bw is "consistent": */ --static const u32 bbr_lt_bw_ratio = BBR_UNIT / 8; --/* If 2 intervals have a bw diff <= 4 Kbit/sec their bw is "consistent": */ --static const u32 bbr_lt_bw_diff = 4000 / 8; --/* If we estimate we're policed, use lt_bw for this many round trips: */ --static const u32 bbr_lt_bw_max_rtts = 48; -- - /* Gain factor for adding extra_acked to target cwnd: */ - static const int bbr_extra_acked_gain = BBR_UNIT; - /* Window length of extra_acked window. */ -@@ -201,8 +256,121 @@ static const u32 bbr_ack_epoch_acked_res - /* Time period for clamping cwnd increment due to ack aggregation */ - static const u32 bbr_extra_acked_max_us = 100 * 1000; - -+/* Flags to control BBR ECN-related behavior... */ -+ -+/* Ensure ACKs only ACK packets with consistent ECN CE status? */ -+static const bool bbr_precise_ece_ack = true; -+ -+/* Max RTT (in usec) at which to use sender-side ECN logic. -+ * Disabled when 0 (ECN allowed at any RTT). -+ */ -+static const u32 bbr_ecn_max_rtt_us = 5000; -+ -+/* On losses, scale down inflight and pacing rate by beta scaled by BBR_SCALE. -+ * No loss response when 0. -+ */ -+static const u32 bbr_beta = BBR_UNIT * 30 / 100; -+ -+/* Gain factor for ECN mark ratio samples, scaled by BBR_SCALE (1/16 = 6.25%) */ -+static const u32 bbr_ecn_alpha_gain = BBR_UNIT * 1 / 16; -+ -+/* The initial value for ecn_alpha; 1.0 allows a flow to respond quickly -+ * to congestion if the bottleneck is congested when the flow starts up. -+ */ -+static const u32 bbr_ecn_alpha_init = BBR_UNIT; -+ -+/* On ECN, cut inflight_lo to (1 - ecn_factor * ecn_alpha) scaled by BBR_SCALE. -+ * No ECN based bounding when 0. -+ */ -+static const u32 bbr_ecn_factor = BBR_UNIT * 1 / 3; /* 1/3 = 33% */ -+ -+/* Estimate bw probing has gone too far if CE ratio exceeds this threshold. -+ * Scaled by BBR_SCALE. Disabled when 0. -+ */ -+static const u32 bbr_ecn_thresh = BBR_UNIT * 1 / 2; /* 1/2 = 50% */ -+ -+/* If non-zero, if in a cycle with no losses but some ECN marks, after ECN -+ * clears then make the first round's increment to inflight_hi the following -+ * fraction of inflight_hi. -+ */ -+static const u32 bbr_ecn_reprobe_gain = BBR_UNIT * 1 / 2; -+ -+/* Estimate bw probing has gone too far if loss rate exceeds this level. */ -+static const u32 bbr_loss_thresh = BBR_UNIT * 2 / 100; /* 2% loss */ -+ -+/* Slow down for a packet loss recovered by TLP? */ -+static const bool bbr_loss_probe_recovery = true; -+ -+/* Exit STARTUP if number of loss marking events in a Recovery round is >= N, -+ * and loss rate is higher than bbr_loss_thresh. -+ * Disabled if 0. -+ */ -+static const u32 bbr_full_loss_cnt = 6; -+ -+/* Exit STARTUP if number of round trips with ECN mark rate above ecn_thresh -+ * meets this count. -+ */ -+static const u32 bbr_full_ecn_cnt = 2; -+ -+/* Fraction of unutilized headroom to try to leave in path upon high loss. */ -+static const u32 bbr_inflight_headroom = BBR_UNIT * 15 / 100; -+ -+/* How much do we increase cwnd_gain when probing for bandwidth in -+ * BBR_BW_PROBE_UP? This specifies the increment in units of -+ * BBR_UNIT/4. The default is 1, meaning 0.25. -+ * The min value is 0 (meaning 0.0); max is 3 (meaning 0.75). -+ */ -+static const u32 bbr_bw_probe_cwnd_gain = 1; -+ -+/* Max number of packet-timed rounds to wait before probing for bandwidth. If -+ * we want to tolerate 1% random loss per round, and not have this cut our -+ * inflight too much, we must probe for bw periodically on roughly this scale. -+ * If low, limits Reno/CUBIC coexistence; if high, limits loss tolerance. -+ * We aim to be fair with Reno/CUBIC up to a BDP of at least: -+ * BDP = 25Mbps * .030sec /(1514bytes) = 61.9 packets -+ */ -+static const u32 bbr_bw_probe_max_rounds = 63; -+ -+/* Max amount of randomness to inject in round counting for Reno-coexistence. -+ */ -+static const u32 bbr_bw_probe_rand_rounds = 2; -+ -+/* Use BBR-native probe time scale starting at this many usec. -+ * We aim to be fair with Reno/CUBIC up to an inter-loss time epoch of at least: -+ * BDP*RTT = 25Mbps * .030sec /(1514bytes) * 0.030sec = 1.9 secs -+ */ -+static const u32 bbr_bw_probe_base_us = 2 * USEC_PER_SEC; /* 2 secs */ -+ -+/* Use BBR-native probes spread over this many usec: */ -+static const u32 bbr_bw_probe_rand_us = 1 * USEC_PER_SEC; /* 1 secs */ -+ -+/* Use fast path if app-limited, no loss/ECN, and target cwnd was reached? */ -+static const bool bbr_fast_path = true; -+ -+/* Use fast ack mode? */ -+static const bool bbr_fast_ack_mode = true; -+ -+static u32 bbr_max_bw(const struct sock *sk); -+static u32 bbr_bw(const struct sock *sk); -+static void bbr_exit_probe_rtt(struct sock *sk); -+static void bbr_reset_congestion_signals(struct sock *sk); -+static void bbr_run_loss_probe_recovery(struct sock *sk); -+ - static void bbr_check_probe_rtt_done(struct sock *sk); - -+/* This connection can use ECN if both endpoints have signaled ECN support in -+ * the handshake and the per-route settings indicated this is a -+ * shallow-threshold ECN environment, meaning both: -+ * (a) ECN CE marks indicate low-latency/shallow-threshold congestion, and -+ * (b) TCP endpoints provide precise ACKs that only ACK data segments -+ * with consistent ECN CE status -+ */ -+static bool bbr_can_use_ecn(const struct sock *sk) -+{ -+ return (tcp_sk(sk)->ecn_flags & TCP_ECN_OK) && -+ (tcp_sk(sk)->ecn_flags & TCP_ECN_LOW); -+} -+ - /* Do we estimate that STARTUP filled the pipe? */ - static bool bbr_full_bw_reached(const struct sock *sk) - { -@@ -214,17 +382,17 @@ static bool bbr_full_bw_reached(const st - /* Return the windowed max recent bandwidth sample, in pkts/uS << BW_SCALE. */ - static u32 bbr_max_bw(const struct sock *sk) - { -- struct bbr *bbr = inet_csk_ca(sk); -+ const struct bbr *bbr = inet_csk_ca(sk); - -- return minmax_get(&bbr->bw); -+ return max(bbr->bw_hi[0], bbr->bw_hi[1]); - } - - /* Return the estimated bandwidth of the path, in pkts/uS << BW_SCALE. */ - static u32 bbr_bw(const struct sock *sk) - { -- struct bbr *bbr = inet_csk_ca(sk); -+ const struct bbr *bbr = inet_csk_ca(sk); - -- return bbr->lt_use_bw ? bbr->lt_bw : bbr_max_bw(sk); -+ return min(bbr_max_bw(sk), bbr->bw_lo); - } - - /* Return maximum extra acked in past k-2k round trips, -@@ -241,15 +409,23 @@ static u16 bbr_extra_acked(const struct - * The order here is chosen carefully to avoid overflow of u64. This should - * work for input rates of up to 2.9Tbit/sec and gain of 2.89x. - */ --static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain) -+static u64 bbr_rate_bytes_per_sec(struct sock *sk, u64 rate, int gain, -+ int margin) - { - unsigned int mss = tcp_sk(sk)->mss_cache; - - rate *= mss; - rate *= gain; - rate >>= BBR_SCALE; -- rate *= USEC_PER_SEC / 100 * (100 - bbr_pacing_margin_percent); -- return rate >> BW_SCALE; -+ rate *= USEC_PER_SEC / 100 * (100 - margin); -+ rate >>= BW_SCALE; -+ rate = max(rate, 1ULL); -+ return rate; -+} -+ -+static u64 bbr_bw_bytes_per_sec(struct sock *sk, u64 rate) -+{ -+ return bbr_rate_bytes_per_sec(sk, rate, BBR_UNIT, 0); - } - - /* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */ -@@ -257,12 +433,13 @@ static unsigned long bbr_bw_to_pacing_ra - { - u64 rate = bw; - -- rate = bbr_rate_bytes_per_sec(sk, rate, gain); -+ rate = bbr_rate_bytes_per_sec(sk, rate, gain, -+ bbr_pacing_margin_percent); - rate = min_t(u64, rate, sk->sk_max_pacing_rate); - return rate; - } - --/* Initialize pacing rate to: high_gain * init_cwnd / RTT. */ -+/* Initialize pacing rate to: startup_pacing_gain * init_cwnd / RTT. */ - static void bbr_init_pacing_rate_from_rtt(struct sock *sk) - { - struct tcp_sock *tp = tcp_sk(sk); -@@ -278,7 +455,8 @@ static void bbr_init_pacing_rate_from_rt - } - bw = (u64)tcp_snd_cwnd(tp) * BW_UNIT; - do_div(bw, rtt_us); -- sk->sk_pacing_rate = bbr_bw_to_pacing_rate(sk, bw, bbr_high_gain); -+ sk->sk_pacing_rate = -+ bbr_bw_to_pacing_rate(sk, bw, bbr_param(sk, startup_pacing_gain)); - } - - /* Pace using current bw estimate and a gain factor. */ -@@ -294,31 +472,38 @@ static void bbr_set_pacing_rate(struct s - sk->sk_pacing_rate = rate; - } - --/* override sysctl_tcp_min_tso_segs */ --__bpf_kfunc static u32 bbr_min_tso_segs(struct sock *sk) --{ -- return sk->sk_pacing_rate < (bbr_min_tso_rate >> 3) ? 1 : 2; --} -- --/* Return the number of segments BBR would like in a TSO/GSO skb, given -- * a particular max gso size as a constraint. -+/* Return the number of segments BBR would like in a TSO/GSO skb, given a -+ * particular max gso size as a constraint. TODO: make this simpler and more -+ * consistent by switching bbr to just call tcp_tso_autosize(). - */ - static u32 bbr_tso_segs_generic(struct sock *sk, unsigned int mss_now, - u32 gso_max_size) - { -- u32 segs; -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 segs, r; - u64 bytes; - - /* Budget a TSO/GSO burst size allowance based on bw (pacing_rate). */ - bytes = sk->sk_pacing_rate >> sk->sk_pacing_shift; - -+ /* Budget a TSO/GSO burst size allowance based on min_rtt. For every -+ * K = 2^tso_rtt_shift microseconds of min_rtt, halve the burst. -+ * The min_rtt-based burst allowance is: 64 KBytes / 2^(min_rtt/K) -+ */ -+ if (bbr_param(sk, tso_rtt_shift)) { -+ r = bbr->min_rtt_us >> bbr_param(sk, tso_rtt_shift); -+ if (r < BITS_PER_TYPE(u32)) /* prevent undefined behavior */ -+ bytes += GSO_LEGACY_MAX_SIZE >> r; -+ } -+ - bytes = min_t(u32, bytes, gso_max_size - 1 - MAX_TCP_HEADER); -- segs = max_t(u32, bytes / mss_now, bbr_min_tso_segs(sk)); -+ segs = max_t(u32, div_u64(bytes, mss_now), -+ sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); - return segs; - } - - /* Custom tcp_tso_autosize() for BBR, used at transmit time to cap skb size. */ --static u32 bbr_tso_segs(struct sock *sk, unsigned int mss_now) -+__bpf_kfunc static u32 bbr_tso_segs(struct sock *sk, unsigned int mss_now) - { - return bbr_tso_segs_generic(sk, mss_now, sk->sk_gso_max_size); - } -@@ -328,7 +513,7 @@ static u32 bbr_tso_segs_goal(struct sock - { - struct tcp_sock *tp = tcp_sk(sk); - -- return bbr_tso_segs_generic(sk, tp->mss_cache, GSO_MAX_SIZE); -+ return bbr_tso_segs_generic(sk, tp->mss_cache, GSO_LEGACY_MAX_SIZE); - } - - /* Save "last known good" cwnd so we can restore it after losses or PROBE_RTT */ -@@ -348,7 +533,9 @@ __bpf_kfunc static void bbr_cwnd_event(s - struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); - -- if (event == CA_EVENT_TX_START && tp->app_limited) { -+ if (event == CA_EVENT_TX_START) { -+ if (!tp->app_limited) -+ return; - bbr->idle_restart = 1; - bbr->ack_epoch_mstamp = tp->tcp_mstamp; - bbr->ack_epoch_acked = 0; -@@ -359,6 +546,16 @@ __bpf_kfunc static void bbr_cwnd_event(s - bbr_set_pacing_rate(sk, bbr_bw(sk), BBR_UNIT); - else if (bbr->mode == BBR_PROBE_RTT) - bbr_check_probe_rtt_done(sk); -+ } else if ((event == CA_EVENT_ECN_IS_CE || -+ event == CA_EVENT_ECN_NO_CE) && -+ bbr_can_use_ecn(sk) && -+ bbr_param(sk, precise_ece_ack)) { -+ u32 state = bbr->ce_state; -+ dctcp_ece_ack_update(sk, event, &bbr->prior_rcv_nxt, &state); -+ bbr->ce_state = state; -+ } else if (event == CA_EVENT_TLP_RECOVERY && -+ bbr_param(sk, loss_probe_recovery)) { -+ bbr_run_loss_probe_recovery(sk); - } - } - -@@ -381,10 +578,10 @@ static u32 bbr_bdp(struct sock *sk, u32 - * default. This should only happen when the connection is not using TCP - * timestamps and has retransmitted all of the SYN/SYNACK/data packets - * ACKed so far. In this case, an RTO can cut cwnd to 1, in which -- * case we need to slow-start up toward something safe: TCP_INIT_CWND. -+ * case we need to slow-start up toward something safe: initial cwnd. - */ - if (unlikely(bbr->min_rtt_us == ~0U)) /* no valid RTT samples yet? */ -- return TCP_INIT_CWND; /* be safe: cap at default initial cwnd*/ -+ return bbr->init_cwnd; /* be safe: cap at initial cwnd */ - - w = (u64)bw * bbr->min_rtt_us; - -@@ -401,23 +598,23 @@ static u32 bbr_bdp(struct sock *sk, u32 - * - one skb in sending host Qdisc, - * - one skb in sending host TSO/GSO engine - * - one skb being received by receiver host LRO/GRO/delayed-ACK engine -- * Don't worry, at low rates (bbr_min_tso_rate) this won't bloat cwnd because -- * in such cases tso_segs_goal is 1. The minimum cwnd is 4 packets, -+ * Don't worry, at low rates this won't bloat cwnd because -+ * in such cases tso_segs_goal is small. The minimum cwnd is 4 packets, - * which allows 2 outstanding 2-packet sequences, to try to keep pipe - * full even with ACK-every-other-packet delayed ACKs. - */ - static u32 bbr_quantization_budget(struct sock *sk, u32 cwnd) - { - struct bbr *bbr = inet_csk_ca(sk); -+ u32 tso_segs_goal; - -- /* Allow enough full-sized skbs in flight to utilize end systems. */ -- cwnd += 3 * bbr_tso_segs_goal(sk); -- -- /* Reduce delayed ACKs by rounding up cwnd to the next even number. */ -- cwnd = (cwnd + 1) & ~1U; -+ tso_segs_goal = 3 * bbr_tso_segs_goal(sk); - -+ /* Allow enough full-sized skbs in flight to utilize end systems. */ -+ cwnd = max_t(u32, cwnd, tso_segs_goal); -+ cwnd = max_t(u32, cwnd, bbr_param(sk, cwnd_min_target)); - /* Ensure gain cycling gets inflight above BDP even for small BDPs. */ -- if (bbr->mode == BBR_PROBE_BW && bbr->cycle_idx == 0) -+ if (bbr->mode == BBR_PROBE_BW && bbr->cycle_idx == BBR_BW_PROBE_UP) - cwnd += 2; - - return cwnd; -@@ -472,10 +669,10 @@ static u32 bbr_ack_aggregation_cwnd(stru - { - u32 max_aggr_cwnd, aggr_cwnd = 0; - -- if (bbr_extra_acked_gain && bbr_full_bw_reached(sk)) { -+ if (bbr_param(sk, extra_acked_gain)) { - max_aggr_cwnd = ((u64)bbr_bw(sk) * bbr_extra_acked_max_us) - / BW_UNIT; -- aggr_cwnd = (bbr_extra_acked_gain * bbr_extra_acked(sk)) -+ aggr_cwnd = (bbr_param(sk, extra_acked_gain) * bbr_extra_acked(sk)) - >> BBR_SCALE; - aggr_cwnd = min(aggr_cwnd, max_aggr_cwnd); - } -@@ -483,66 +680,27 @@ static u32 bbr_ack_aggregation_cwnd(stru - return aggr_cwnd; - } - --/* An optimization in BBR to reduce losses: On the first round of recovery, we -- * follow the packet conservation principle: send P packets per P packets acked. -- * After that, we slow-start and send at most 2*P packets per P packets acked. -- * After recovery finishes, or upon undo, we restore the cwnd we had when -- * recovery started (capped by the target cwnd based on estimated BDP). -- * -- * TODO(ycheng/ncardwell): implement a rate-based approach. -- */ --static bool bbr_set_cwnd_to_recover_or_restore( -- struct sock *sk, const struct rate_sample *rs, u32 acked, u32 *new_cwnd) -+/* Returns the cwnd for PROBE_RTT mode. */ -+static u32 bbr_probe_rtt_cwnd(struct sock *sk) - { -- struct tcp_sock *tp = tcp_sk(sk); -- struct bbr *bbr = inet_csk_ca(sk); -- u8 prev_state = bbr->prev_ca_state, state = inet_csk(sk)->icsk_ca_state; -- u32 cwnd = tcp_snd_cwnd(tp); -- -- /* An ACK for P pkts should release at most 2*P packets. We do this -- * in two steps. First, here we deduct the number of lost packets. -- * Then, in bbr_set_cwnd() we slow start up toward the target cwnd. -- */ -- if (rs->losses > 0) -- cwnd = max_t(s32, cwnd - rs->losses, 1); -- -- if (state == TCP_CA_Recovery && prev_state != TCP_CA_Recovery) { -- /* Starting 1st round of Recovery, so do packet conservation. */ -- bbr->packet_conservation = 1; -- bbr->next_rtt_delivered = tp->delivered; /* start round now */ -- /* Cut unused cwnd from app behavior, TSQ, or TSO deferral: */ -- cwnd = tcp_packets_in_flight(tp) + acked; -- } else if (prev_state >= TCP_CA_Recovery && state < TCP_CA_Recovery) { -- /* Exiting loss recovery; restore cwnd saved before recovery. */ -- cwnd = max(cwnd, bbr->prior_cwnd); -- bbr->packet_conservation = 0; -- } -- bbr->prev_ca_state = state; -- -- if (bbr->packet_conservation) { -- *new_cwnd = max(cwnd, tcp_packets_in_flight(tp) + acked); -- return true; /* yes, using packet conservation */ -- } -- *new_cwnd = cwnd; -- return false; -+ return max_t(u32, bbr_param(sk, cwnd_min_target), -+ bbr_bdp(sk, bbr_bw(sk), bbr_param(sk, probe_rtt_cwnd_gain))); - } - - /* Slow-start up toward target cwnd (if bw estimate is growing, or packet loss - * has drawn us down below target), or snap down to target if we're above it. - */ - static void bbr_set_cwnd(struct sock *sk, const struct rate_sample *rs, -- u32 acked, u32 bw, int gain) -+ u32 acked, u32 bw, int gain, u32 cwnd, -+ struct bbr_context *ctx) - { - struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); -- u32 cwnd = tcp_snd_cwnd(tp), target_cwnd = 0; -+ u32 target_cwnd = 0; - - if (!acked) - goto done; /* no packet fully ACKed; just apply caps */ - -- if (bbr_set_cwnd_to_recover_or_restore(sk, rs, acked, &cwnd)) -- goto done; -- - target_cwnd = bbr_bdp(sk, bw, gain); - - /* Increment the cwnd to account for excess ACKed data that seems -@@ -551,74 +709,26 @@ static void bbr_set_cwnd(struct sock *sk - target_cwnd += bbr_ack_aggregation_cwnd(sk); - target_cwnd = bbr_quantization_budget(sk, target_cwnd); - -- /* If we're below target cwnd, slow start cwnd toward target cwnd. */ -- if (bbr_full_bw_reached(sk)) /* only cut cwnd if we filled the pipe */ -- cwnd = min(cwnd + acked, target_cwnd); -- else if (cwnd < target_cwnd || tp->delivered < TCP_INIT_CWND) -- cwnd = cwnd + acked; -- cwnd = max(cwnd, bbr_cwnd_min_target); -+ /* Update cwnd and enable fast path if cwnd reaches target_cwnd. */ -+ bbr->try_fast_path = 0; -+ if (bbr_full_bw_reached(sk)) { /* only cut cwnd if we filled the pipe */ -+ cwnd += acked; -+ if (cwnd >= target_cwnd) { -+ cwnd = target_cwnd; -+ bbr->try_fast_path = 1; -+ } -+ } else if (cwnd < target_cwnd || cwnd < 2 * bbr->init_cwnd) { -+ cwnd += acked; -+ } else { -+ bbr->try_fast_path = 1; -+ } - -+ cwnd = max_t(u32, cwnd, bbr_param(sk, cwnd_min_target)); - done: -- tcp_snd_cwnd_set(tp, min(cwnd, tp->snd_cwnd_clamp)); /* apply global cap */ -+ tcp_snd_cwnd_set(tp, min(cwnd, tp->snd_cwnd_clamp)); /* global cap */ - if (bbr->mode == BBR_PROBE_RTT) /* drain queue, refresh min_rtt */ -- tcp_snd_cwnd_set(tp, min(tcp_snd_cwnd(tp), bbr_cwnd_min_target)); --} -- --/* End cycle phase if it's time and/or we hit the phase's in-flight target. */ --static bool bbr_is_next_cycle_phase(struct sock *sk, -- const struct rate_sample *rs) --{ -- struct tcp_sock *tp = tcp_sk(sk); -- struct bbr *bbr = inet_csk_ca(sk); -- bool is_full_length = -- tcp_stamp_us_delta(tp->delivered_mstamp, bbr->cycle_mstamp) > -- bbr->min_rtt_us; -- u32 inflight, bw; -- -- /* The pacing_gain of 1.0 paces at the estimated bw to try to fully -- * use the pipe without increasing the queue. -- */ -- if (bbr->pacing_gain == BBR_UNIT) -- return is_full_length; /* just use wall clock time */ -- -- inflight = bbr_packets_in_net_at_edt(sk, rs->prior_in_flight); -- bw = bbr_max_bw(sk); -- -- /* A pacing_gain > 1.0 probes for bw by trying to raise inflight to at -- * least pacing_gain*BDP; this may take more than min_rtt if min_rtt is -- * small (e.g. on a LAN). We do not persist if packets are lost, since -- * a path with small buffers may not hold that much. -- */ -- if (bbr->pacing_gain > BBR_UNIT) -- return is_full_length && -- (rs->losses || /* perhaps pacing_gain*BDP won't fit */ -- inflight >= bbr_inflight(sk, bw, bbr->pacing_gain)); -- -- /* A pacing_gain < 1.0 tries to drain extra queue we added if bw -- * probing didn't find more bw. If inflight falls to match BDP then we -- * estimate queue is drained; persisting would underutilize the pipe. -- */ -- return is_full_length || -- inflight <= bbr_inflight(sk, bw, BBR_UNIT); --} -- --static void bbr_advance_cycle_phase(struct sock *sk) --{ -- struct tcp_sock *tp = tcp_sk(sk); -- struct bbr *bbr = inet_csk_ca(sk); -- -- bbr->cycle_idx = (bbr->cycle_idx + 1) & (CYCLE_LEN - 1); -- bbr->cycle_mstamp = tp->delivered_mstamp; --} -- --/* Gain cycling: cycle pacing gain to converge to fair share of available bw. */ --static void bbr_update_cycle_phase(struct sock *sk, -- const struct rate_sample *rs) --{ -- struct bbr *bbr = inet_csk_ca(sk); -- -- if (bbr->mode == BBR_PROBE_BW && bbr_is_next_cycle_phase(sk, rs)) -- bbr_advance_cycle_phase(sk); -+ tcp_snd_cwnd_set(tp, min_t(u32, tcp_snd_cwnd(tp), -+ bbr_probe_rtt_cwnd(sk))); - } - - static void bbr_reset_startup_mode(struct sock *sk) -@@ -628,191 +738,49 @@ static void bbr_reset_startup_mode(struc - bbr->mode = BBR_STARTUP; - } - --static void bbr_reset_probe_bw_mode(struct sock *sk) --{ -- struct bbr *bbr = inet_csk_ca(sk); -- -- bbr->mode = BBR_PROBE_BW; -- bbr->cycle_idx = CYCLE_LEN - 1 - get_random_u32_below(bbr_cycle_rand); -- bbr_advance_cycle_phase(sk); /* flip to next phase of gain cycle */ --} -- --static void bbr_reset_mode(struct sock *sk) --{ -- if (!bbr_full_bw_reached(sk)) -- bbr_reset_startup_mode(sk); -- else -- bbr_reset_probe_bw_mode(sk); --} -- --/* Start a new long-term sampling interval. */ --static void bbr_reset_lt_bw_sampling_interval(struct sock *sk) --{ -- struct tcp_sock *tp = tcp_sk(sk); -- struct bbr *bbr = inet_csk_ca(sk); -- -- bbr->lt_last_stamp = div_u64(tp->delivered_mstamp, USEC_PER_MSEC); -- bbr->lt_last_delivered = tp->delivered; -- bbr->lt_last_lost = tp->lost; -- bbr->lt_rtt_cnt = 0; --} -- --/* Completely reset long-term bandwidth sampling. */ --static void bbr_reset_lt_bw_sampling(struct sock *sk) --{ -- struct bbr *bbr = inet_csk_ca(sk); -- -- bbr->lt_bw = 0; -- bbr->lt_use_bw = 0; -- bbr->lt_is_sampling = false; -- bbr_reset_lt_bw_sampling_interval(sk); --} -- --/* Long-term bw sampling interval is done. Estimate whether we're policed. */ --static void bbr_lt_bw_interval_done(struct sock *sk, u32 bw) --{ -- struct bbr *bbr = inet_csk_ca(sk); -- u32 diff; -- -- if (bbr->lt_bw) { /* do we have bw from a previous interval? */ -- /* Is new bw close to the lt_bw from the previous interval? */ -- diff = abs(bw - bbr->lt_bw); -- if ((diff * BBR_UNIT <= bbr_lt_bw_ratio * bbr->lt_bw) || -- (bbr_rate_bytes_per_sec(sk, diff, BBR_UNIT) <= -- bbr_lt_bw_diff)) { -- /* All criteria are met; estimate we're policed. */ -- bbr->lt_bw = (bw + bbr->lt_bw) >> 1; /* avg 2 intvls */ -- bbr->lt_use_bw = 1; -- bbr->pacing_gain = BBR_UNIT; /* try to avoid drops */ -- bbr->lt_rtt_cnt = 0; -- return; -- } -- } -- bbr->lt_bw = bw; -- bbr_reset_lt_bw_sampling_interval(sk); --} -- --/* Token-bucket traffic policers are common (see "An Internet-Wide Analysis of -- * Traffic Policing", SIGCOMM 2016). BBR detects token-bucket policers and -- * explicitly models their policed rate, to reduce unnecessary losses. We -- * estimate that we're policed if we see 2 consecutive sampling intervals with -- * consistent throughput and high packet loss. If we think we're being policed, -- * set lt_bw to the "long-term" average delivery rate from those 2 intervals. -+/* See if we have reached next round trip. Upon start of the new round, -+ * returns packets delivered since previous round start plus this ACK. - */ --static void bbr_lt_bw_sampling(struct sock *sk, const struct rate_sample *rs) -+static u32 bbr_update_round_start(struct sock *sk, -+ const struct rate_sample *rs, struct bbr_context *ctx) - { - struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); -- u32 lost, delivered; -- u64 bw; -- u32 t; -- -- if (bbr->lt_use_bw) { /* already using long-term rate, lt_bw? */ -- if (bbr->mode == BBR_PROBE_BW && bbr->round_start && -- ++bbr->lt_rtt_cnt >= bbr_lt_bw_max_rtts) { -- bbr_reset_lt_bw_sampling(sk); /* stop using lt_bw */ -- bbr_reset_probe_bw_mode(sk); /* restart gain cycling */ -- } -- return; -- } -- -- /* Wait for the first loss before sampling, to let the policer exhaust -- * its tokens and estimate the steady-state rate allowed by the policer. -- * Starting samples earlier includes bursts that over-estimate the bw. -- */ -- if (!bbr->lt_is_sampling) { -- if (!rs->losses) -- return; -- bbr_reset_lt_bw_sampling_interval(sk); -- bbr->lt_is_sampling = true; -- } -- -- /* To avoid underestimates, reset sampling if we run out of data. */ -- if (rs->is_app_limited) { -- bbr_reset_lt_bw_sampling(sk); -- return; -- } -- -- if (bbr->round_start) -- bbr->lt_rtt_cnt++; /* count round trips in this interval */ -- if (bbr->lt_rtt_cnt < bbr_lt_intvl_min_rtts) -- return; /* sampling interval needs to be longer */ -- if (bbr->lt_rtt_cnt > 4 * bbr_lt_intvl_min_rtts) { -- bbr_reset_lt_bw_sampling(sk); /* interval is too long */ -- return; -- } -- -- /* End sampling interval when a packet is lost, so we estimate the -- * policer tokens were exhausted. Stopping the sampling before the -- * tokens are exhausted under-estimates the policed rate. -- */ -- if (!rs->losses) -- return; -- -- /* Calculate packets lost and delivered in sampling interval. */ -- lost = tp->lost - bbr->lt_last_lost; -- delivered = tp->delivered - bbr->lt_last_delivered; -- /* Is loss rate (lost/delivered) >= lt_loss_thresh? If not, wait. */ -- if (!delivered || (lost << BBR_SCALE) < bbr_lt_loss_thresh * delivered) -- return; -- -- /* Find average delivery rate in this sampling interval. */ -- t = div_u64(tp->delivered_mstamp, USEC_PER_MSEC) - bbr->lt_last_stamp; -- if ((s32)t < 1) -- return; /* interval is less than one ms, so wait */ -- /* Check if can multiply without overflow */ -- if (t >= ~0U / USEC_PER_MSEC) { -- bbr_reset_lt_bw_sampling(sk); /* interval too long; reset */ -- return; -- } -- t *= USEC_PER_MSEC; -- bw = (u64)delivered * BW_UNIT; -- do_div(bw, t); -- bbr_lt_bw_interval_done(sk, bw); --} -- --/* Estimate the bandwidth based on how fast packets are delivered */ --static void bbr_update_bw(struct sock *sk, const struct rate_sample *rs) --{ -- struct tcp_sock *tp = tcp_sk(sk); -- struct bbr *bbr = inet_csk_ca(sk); -- u64 bw; -+ u32 round_delivered = 0; - - bbr->round_start = 0; -- if (rs->delivered < 0 || rs->interval_us <= 0) -- return; /* Not a valid observation */ - - /* See if we've reached the next RTT */ -- if (!before(rs->prior_delivered, bbr->next_rtt_delivered)) { -+ if (rs->interval_us > 0 && -+ !before(rs->prior_delivered, bbr->next_rtt_delivered)) { -+ round_delivered = tp->delivered - bbr->next_rtt_delivered; - bbr->next_rtt_delivered = tp->delivered; -- bbr->rtt_cnt++; - bbr->round_start = 1; -- bbr->packet_conservation = 0; - } -+ return round_delivered; -+} - -- bbr_lt_bw_sampling(sk, rs); -+/* Calculate the bandwidth based on how fast packets are delivered */ -+static void bbr_calculate_bw_sample(struct sock *sk, -+ const struct rate_sample *rs, struct bbr_context *ctx) -+{ -+ u64 bw = 0; - - /* Divide delivered by the interval to find a (lower bound) bottleneck - * bandwidth sample. Delivered is in packets and interval_us in uS and - * ratio will be <<1 for most connections. So delivered is first scaled. -+ * Round up to allow growth at low rates, even with integer division. - */ -- bw = div64_long((u64)rs->delivered * BW_UNIT, rs->interval_us); -+ if (rs->interval_us > 0) { -+ if (WARN_ONCE(rs->delivered < 0, -+ "negative delivered: %d interval_us: %ld\n", -+ rs->delivered, rs->interval_us)) -+ return; - -- /* If this sample is application-limited, it is likely to have a very -- * low delivered count that represents application behavior rather than -- * the available network rate. Such a sample could drag down estimated -- * bw, causing needless slow-down. Thus, to continue to send at the -- * last measured network rate, we filter out app-limited samples unless -- * they describe the path bw at least as well as our bw model. -- * -- * So the goal during app-limited phase is to proceed with the best -- * network rate no matter how long. We automatically leave this -- * phase when app writes faster than the network can deliver :) -- */ -- if (!rs->is_app_limited || bw >= bbr_max_bw(sk)) { -- /* Incorporate new sample into our max bw filter. */ -- minmax_running_max(&bbr->bw, bbr_bw_rtts, bbr->rtt_cnt, bw); -+ bw = DIV_ROUND_UP_ULL((u64)rs->delivered * BW_UNIT, rs->interval_us); - } -+ -+ ctx->sample_bw = bw; - } - - /* Estimates the windowed max degree of ack aggregation. -@@ -826,7 +794,7 @@ static void bbr_update_bw(struct sock *s - * - * Max extra_acked is clamped by cwnd and bw * bbr_extra_acked_max_us (100 ms). - * Max filter is an approximate sliding window of 5-10 (packet timed) round -- * trips. -+ * trips for non-startup phase, and 1-2 round trips for startup. - */ - static void bbr_update_ack_aggregation(struct sock *sk, - const struct rate_sample *rs) -@@ -834,15 +802,19 @@ static void bbr_update_ack_aggregation(s - u32 epoch_us, expected_acked, extra_acked; - struct bbr *bbr = inet_csk_ca(sk); - struct tcp_sock *tp = tcp_sk(sk); -+ u32 extra_acked_win_rtts_thresh = bbr_param(sk, extra_acked_win_rtts); - -- if (!bbr_extra_acked_gain || rs->acked_sacked <= 0 || -+ if (!bbr_param(sk, extra_acked_gain) || rs->acked_sacked <= 0 || - rs->delivered < 0 || rs->interval_us <= 0) - return; - - if (bbr->round_start) { - bbr->extra_acked_win_rtts = min(0x1F, - bbr->extra_acked_win_rtts + 1); -- if (bbr->extra_acked_win_rtts >= bbr_extra_acked_win_rtts) { -+ if (!bbr_full_bw_reached(sk)) -+ extra_acked_win_rtts_thresh = 1; -+ if (bbr->extra_acked_win_rtts >= -+ extra_acked_win_rtts_thresh) { - bbr->extra_acked_win_rtts = 0; - bbr->extra_acked_win_idx = bbr->extra_acked_win_idx ? - 0 : 1; -@@ -876,49 +848,6 @@ static void bbr_update_ack_aggregation(s - bbr->extra_acked[bbr->extra_acked_win_idx] = extra_acked; - } - --/* Estimate when the pipe is full, using the change in delivery rate: BBR -- * estimates that STARTUP filled the pipe if the estimated bw hasn't changed by -- * at least bbr_full_bw_thresh (25%) after bbr_full_bw_cnt (3) non-app-limited -- * rounds. Why 3 rounds: 1: rwin autotuning grows the rwin, 2: we fill the -- * higher rwin, 3: we get higher delivery rate samples. Or transient -- * cross-traffic or radio noise can go away. CUBIC Hystart shares a similar -- * design goal, but uses delay and inter-ACK spacing instead of bandwidth. -- */ --static void bbr_check_full_bw_reached(struct sock *sk, -- const struct rate_sample *rs) --{ -- struct bbr *bbr = inet_csk_ca(sk); -- u32 bw_thresh; -- -- if (bbr_full_bw_reached(sk) || !bbr->round_start || rs->is_app_limited) -- return; -- -- bw_thresh = (u64)bbr->full_bw * bbr_full_bw_thresh >> BBR_SCALE; -- if (bbr_max_bw(sk) >= bw_thresh) { -- bbr->full_bw = bbr_max_bw(sk); -- bbr->full_bw_cnt = 0; -- return; -- } -- ++bbr->full_bw_cnt; -- bbr->full_bw_reached = bbr->full_bw_cnt >= bbr_full_bw_cnt; --} -- --/* If pipe is probably full, drain the queue and then enter steady-state. */ --static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) --{ -- struct bbr *bbr = inet_csk_ca(sk); -- -- if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { -- bbr->mode = BBR_DRAIN; /* drain queue we created */ -- tcp_sk(sk)->snd_ssthresh = -- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); -- } /* fall through to check if in-flight is already small: */ -- if (bbr->mode == BBR_DRAIN && -- bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= -- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT)) -- bbr_reset_probe_bw_mode(sk); /* we estimate queue is drained */ --} -- - static void bbr_check_probe_rtt_done(struct sock *sk) - { - struct tcp_sock *tp = tcp_sk(sk); -@@ -928,9 +857,9 @@ static void bbr_check_probe_rtt_done(str - after(tcp_jiffies32, bbr->probe_rtt_done_stamp))) - return; - -- bbr->min_rtt_stamp = tcp_jiffies32; /* wait a while until PROBE_RTT */ -+ bbr->probe_rtt_min_stamp = tcp_jiffies32; /* schedule next PROBE_RTT */ - tcp_snd_cwnd_set(tp, max(tcp_snd_cwnd(tp), bbr->prior_cwnd)); -- bbr_reset_mode(sk); -+ bbr_exit_probe_rtt(sk); - } - - /* The goal of PROBE_RTT mode is to have BBR flows cooperatively and -@@ -956,23 +885,35 @@ static void bbr_update_min_rtt(struct so - { - struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); -- bool filter_expired; -+ bool probe_rtt_expired, min_rtt_expired; -+ u32 expire; - -- /* Track min RTT seen in the min_rtt_win_sec filter window: */ -- filter_expired = after(tcp_jiffies32, -- bbr->min_rtt_stamp + bbr_min_rtt_win_sec * HZ); -+ /* Track min RTT in probe_rtt_win_ms to time next PROBE_RTT state. */ -+ expire = bbr->probe_rtt_min_stamp + -+ msecs_to_jiffies(bbr_param(sk, probe_rtt_win_ms)); -+ probe_rtt_expired = after(tcp_jiffies32, expire); - if (rs->rtt_us >= 0 && -- (rs->rtt_us < bbr->min_rtt_us || -- (filter_expired && !rs->is_ack_delayed))) { -- bbr->min_rtt_us = rs->rtt_us; -- bbr->min_rtt_stamp = tcp_jiffies32; -+ (rs->rtt_us < bbr->probe_rtt_min_us || -+ (probe_rtt_expired && !rs->is_ack_delayed))) { -+ bbr->probe_rtt_min_us = rs->rtt_us; -+ bbr->probe_rtt_min_stamp = tcp_jiffies32; -+ } -+ /* Track min RTT seen in the min_rtt_win_sec filter window: */ -+ expire = bbr->min_rtt_stamp + bbr_param(sk, min_rtt_win_sec) * HZ; -+ min_rtt_expired = after(tcp_jiffies32, expire); -+ if (bbr->probe_rtt_min_us <= bbr->min_rtt_us || -+ min_rtt_expired) { -+ bbr->min_rtt_us = bbr->probe_rtt_min_us; -+ bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp; - } - -- if (bbr_probe_rtt_mode_ms > 0 && filter_expired && -+ if (bbr_param(sk, probe_rtt_mode_ms) > 0 && probe_rtt_expired && - !bbr->idle_restart && bbr->mode != BBR_PROBE_RTT) { - bbr->mode = BBR_PROBE_RTT; /* dip, drain queue */ - bbr_save_cwnd(sk); /* note cwnd so we can restore it */ - bbr->probe_rtt_done_stamp = 0; -+ bbr->ack_phase = BBR_ACKS_PROBE_STOPPING; -+ bbr->next_rtt_delivered = tp->delivered; - } - - if (bbr->mode == BBR_PROBE_RTT) { -@@ -981,9 +922,9 @@ static void bbr_update_min_rtt(struct so - (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; - /* Maintain min packets in flight for max(200 ms, 1 round). */ - if (!bbr->probe_rtt_done_stamp && -- tcp_packets_in_flight(tp) <= bbr_cwnd_min_target) { -+ tcp_packets_in_flight(tp) <= bbr_probe_rtt_cwnd(sk)) { - bbr->probe_rtt_done_stamp = tcp_jiffies32 + -- msecs_to_jiffies(bbr_probe_rtt_mode_ms); -+ msecs_to_jiffies(bbr_param(sk, probe_rtt_mode_ms)); - bbr->probe_rtt_round_done = 0; - bbr->next_rtt_delivered = tp->delivered; - } else if (bbr->probe_rtt_done_stamp) { -@@ -1004,18 +945,20 @@ static void bbr_update_gains(struct sock - - switch (bbr->mode) { - case BBR_STARTUP: -- bbr->pacing_gain = bbr_high_gain; -- bbr->cwnd_gain = bbr_high_gain; -+ bbr->pacing_gain = bbr_param(sk, startup_pacing_gain); -+ bbr->cwnd_gain = bbr_param(sk, startup_cwnd_gain); - break; - case BBR_DRAIN: -- bbr->pacing_gain = bbr_drain_gain; /* slow, to drain */ -- bbr->cwnd_gain = bbr_high_gain; /* keep cwnd */ -+ bbr->pacing_gain = bbr_param(sk, drain_gain); /* slow, to drain */ -+ bbr->cwnd_gain = bbr_param(sk, startup_cwnd_gain); /* keep cwnd */ - break; - case BBR_PROBE_BW: -- bbr->pacing_gain = (bbr->lt_use_bw ? -- BBR_UNIT : -- bbr_pacing_gain[bbr->cycle_idx]); -- bbr->cwnd_gain = bbr_cwnd_gain; -+ bbr->pacing_gain = bbr_pacing_gain[bbr->cycle_idx]; -+ bbr->cwnd_gain = bbr_param(sk, cwnd_gain); -+ if (bbr_param(sk, bw_probe_cwnd_gain) && -+ bbr->cycle_idx == BBR_BW_PROBE_UP) -+ bbr->cwnd_gain += -+ BBR_UNIT * bbr_param(sk, bw_probe_cwnd_gain) / 4; - break; - case BBR_PROBE_RTT: - bbr->pacing_gain = BBR_UNIT; -@@ -1027,27 +970,1108 @@ static void bbr_update_gains(struct sock - } - } - --static void bbr_update_model(struct sock *sk, const struct rate_sample *rs) -+__bpf_kfunc static u32 bbr_sndbuf_expand(struct sock *sk) -+{ -+ /* Provision 3 * cwnd since BBR may slow-start even during recovery. */ -+ return 3; -+} -+ -+/* Incorporate a new bw sample into the current window of our max filter. */ -+static void bbr_take_max_bw_sample(struct sock *sk, u32 bw) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr->bw_hi[1] = max(bw, bbr->bw_hi[1]); -+} -+ -+/* Keep max of last 1-2 cycles. Each PROBE_BW cycle, flip filter window. */ -+static void bbr_advance_max_bw_filter(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ if (!bbr->bw_hi[1]) -+ return; /* no samples in this window; remember old window */ -+ bbr->bw_hi[0] = bbr->bw_hi[1]; -+ bbr->bw_hi[1] = 0; -+} -+ -+/* Reset the estimator for reaching full bandwidth based on bw plateau. */ -+static void bbr_reset_full_bw(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr->full_bw = 0; -+ bbr->full_bw_cnt = 0; -+ bbr->full_bw_now = 0; -+} -+ -+/* How much do we want in flight? Our BDP, unless congestion cut cwnd. */ -+static u32 bbr_target_inflight(struct sock *sk) -+{ -+ u32 bdp = bbr_inflight(sk, bbr_bw(sk), BBR_UNIT); -+ -+ return min(bdp, tcp_sk(sk)->snd_cwnd); -+} -+ -+static bool bbr_is_probing_bandwidth(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ return (bbr->mode == BBR_STARTUP) || -+ (bbr->mode == BBR_PROBE_BW && -+ (bbr->cycle_idx == BBR_BW_PROBE_REFILL || -+ bbr->cycle_idx == BBR_BW_PROBE_UP)); -+} -+ -+/* Has the given amount of time elapsed since we marked the phase start? */ -+static bool bbr_has_elapsed_in_phase(const struct sock *sk, u32 interval_us) -+{ -+ const struct tcp_sock *tp = tcp_sk(sk); -+ const struct bbr *bbr = inet_csk_ca(sk); -+ -+ return tcp_stamp_us_delta(tp->tcp_mstamp, -+ bbr->cycle_mstamp + interval_us) > 0; -+} -+ -+static void bbr_handle_queue_too_high_in_startup(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 bdp; /* estimated BDP in packets, with quantization budget */ -+ -+ bbr->full_bw_reached = 1; -+ -+ bdp = bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); -+ bbr->inflight_hi = max(bdp, bbr->inflight_latest); -+} -+ -+/* Exit STARTUP upon N consecutive rounds with ECN mark rate > ecn_thresh. */ -+static void bbr_check_ecn_too_high_in_startup(struct sock *sk, u32 ce_ratio) - { -- bbr_update_bw(sk, rs); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ if (bbr_full_bw_reached(sk) || !bbr->ecn_eligible || -+ !bbr_param(sk, full_ecn_cnt) || !bbr_param(sk, ecn_thresh)) -+ return; -+ -+ if (ce_ratio >= bbr_param(sk, ecn_thresh)) -+ bbr->startup_ecn_rounds++; -+ else -+ bbr->startup_ecn_rounds = 0; -+ -+ if (bbr->startup_ecn_rounds >= bbr_param(sk, full_ecn_cnt)) { -+ bbr_handle_queue_too_high_in_startup(sk); -+ return; -+ } -+} -+ -+/* Updates ecn_alpha and returns ce_ratio. -1 if not available. */ -+static int bbr_update_ecn_alpha(struct sock *sk) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct net *net = sock_net(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ s32 delivered, delivered_ce; -+ u64 alpha, ce_ratio; -+ u32 gain; -+ bool want_ecn_alpha; -+ -+ /* See if we should use ECN sender logic for this connection. */ -+ if (!bbr->ecn_eligible && bbr_can_use_ecn(sk) && -+ bbr_param(sk, ecn_factor) && -+ (bbr->min_rtt_us <= bbr_ecn_max_rtt_us || -+ !bbr_ecn_max_rtt_us)) -+ bbr->ecn_eligible = 1; -+ -+ /* Skip updating alpha only if not ECN-eligible and PLB is disabled. */ -+ want_ecn_alpha = (bbr->ecn_eligible || -+ (bbr_can_use_ecn(sk) && -+ READ_ONCE(net->ipv4.sysctl_tcp_plb_enabled))); -+ if (!want_ecn_alpha) -+ return -1; -+ -+ delivered = tp->delivered - bbr->alpha_last_delivered; -+ delivered_ce = tp->delivered_ce - bbr->alpha_last_delivered_ce; -+ -+ if (delivered == 0 || /* avoid divide by zero */ -+ WARN_ON_ONCE(delivered < 0 || delivered_ce < 0)) /* backwards? */ -+ return -1; -+ -+ BUILD_BUG_ON(BBR_SCALE != TCP_PLB_SCALE); -+ ce_ratio = (u64)delivered_ce << BBR_SCALE; -+ do_div(ce_ratio, delivered); -+ -+ gain = bbr_param(sk, ecn_alpha_gain); -+ alpha = ((BBR_UNIT - gain) * bbr->ecn_alpha) >> BBR_SCALE; -+ alpha += (gain * ce_ratio) >> BBR_SCALE; -+ bbr->ecn_alpha = min_t(u32, alpha, BBR_UNIT); -+ -+ bbr->alpha_last_delivered = tp->delivered; -+ bbr->alpha_last_delivered_ce = tp->delivered_ce; -+ -+ bbr_check_ecn_too_high_in_startup(sk, ce_ratio); -+ return (int)ce_ratio; -+} -+ -+/* Protective Load Balancing (PLB). PLB rehashes outgoing data (to a new IPv6 -+ * flow label) if it encounters sustained congestion in the form of ECN marks. -+ */ -+static void bbr_plb(struct sock *sk, const struct rate_sample *rs, int ce_ratio) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ if (bbr->round_start && ce_ratio >= 0) -+ tcp_plb_update_state(sk, &bbr->plb, ce_ratio); -+ -+ tcp_plb_check_rehash(sk, &bbr->plb); -+} -+ -+/* Each round trip of BBR_BW_PROBE_UP, double volume of probing data. */ -+static void bbr_raise_inflight_hi_slope(struct sock *sk) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 growth_this_round, cnt; -+ -+ /* Calculate "slope": packets S/Acked per inflight_hi increment. */ -+ growth_this_round = 1 << bbr->bw_probe_up_rounds; -+ bbr->bw_probe_up_rounds = min(bbr->bw_probe_up_rounds + 1, 30); -+ cnt = tcp_snd_cwnd(tp) / growth_this_round; -+ cnt = max(cnt, 1U); -+ bbr->bw_probe_up_cnt = cnt; -+} -+ -+/* In BBR_BW_PROBE_UP, not seeing high loss/ECN/queue, so raise inflight_hi. */ -+static void bbr_probe_inflight_hi_upward(struct sock *sk, -+ const struct rate_sample *rs) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 delta; -+ -+ if (!tp->is_cwnd_limited || tcp_snd_cwnd(tp) < bbr->inflight_hi) -+ return; /* not fully using inflight_hi, so don't grow it */ -+ -+ /* For each bw_probe_up_cnt packets ACKed, increase inflight_hi by 1. */ -+ bbr->bw_probe_up_acks += rs->acked_sacked; -+ if (bbr->bw_probe_up_acks >= bbr->bw_probe_up_cnt) { -+ delta = bbr->bw_probe_up_acks / bbr->bw_probe_up_cnt; -+ bbr->bw_probe_up_acks -= delta * bbr->bw_probe_up_cnt; -+ bbr->inflight_hi += delta; -+ bbr->try_fast_path = 0; /* Need to update cwnd */ -+ } -+ -+ if (bbr->round_start) -+ bbr_raise_inflight_hi_slope(sk); -+} -+ -+/* Does loss/ECN rate for this sample say inflight is "too high"? -+ * This is used by both the bbr_check_loss_too_high_in_startup() function, -+ * which can be used in either v1 or v2, and the PROBE_UP phase of v2, which -+ * uses it to notice when loss/ECN rates suggest inflight is too high. -+ */ -+static bool bbr_is_inflight_too_high(const struct sock *sk, -+ const struct rate_sample *rs) -+{ -+ const struct bbr *bbr = inet_csk_ca(sk); -+ u32 loss_thresh, ecn_thresh; -+ -+ if (rs->lost > 0 && rs->tx_in_flight) { -+ loss_thresh = (u64)rs->tx_in_flight * bbr_param(sk, loss_thresh) >> -+ BBR_SCALE; -+ if (rs->lost > loss_thresh) { -+ return true; -+ } -+ } -+ -+ if (rs->delivered_ce > 0 && rs->delivered > 0 && -+ bbr->ecn_eligible && bbr_param(sk, ecn_thresh)) { -+ ecn_thresh = (u64)rs->delivered * bbr_param(sk, ecn_thresh) >> -+ BBR_SCALE; -+ if (rs->delivered_ce > ecn_thresh) { -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+/* Calculate the tx_in_flight level that corresponded to excessive loss. -+ * We find "lost_prefix" segs of the skb where loss rate went too high, -+ * by solving for "lost_prefix" in the following equation: -+ * lost / inflight >= loss_thresh -+ * (lost_prev + lost_prefix) / (inflight_prev + lost_prefix) >= loss_thresh -+ * Then we take that equation, convert it to fixed point, and -+ * round up to the nearest packet. -+ */ -+static u32 bbr_inflight_hi_from_lost_skb(const struct sock *sk, -+ const struct rate_sample *rs, -+ const struct sk_buff *skb) -+{ -+ const struct tcp_sock *tp = tcp_sk(sk); -+ u32 loss_thresh = bbr_param(sk, loss_thresh); -+ u32 pcount, divisor, inflight_hi; -+ s32 inflight_prev, lost_prev; -+ u64 loss_budget, lost_prefix; -+ -+ pcount = tcp_skb_pcount(skb); -+ -+ /* How much data was in flight before this skb? */ -+ inflight_prev = rs->tx_in_flight - pcount; -+ if (inflight_prev < 0) { -+ WARN_ONCE(tcp_skb_tx_in_flight_is_suspicious( -+ pcount, -+ TCP_SKB_CB(skb)->sacked, -+ rs->tx_in_flight), -+ "tx_in_flight: %u pcount: %u reneg: %u", -+ rs->tx_in_flight, pcount, tcp_sk(sk)->is_sack_reneg); -+ return ~0U; -+ } -+ -+ /* How much inflight data was marked lost before this skb? */ -+ lost_prev = rs->lost - pcount; -+ if (WARN_ONCE(lost_prev < 0, -+ "cwnd: %u ca: %d out: %u lost: %u pif: %u " -+ "tx_in_flight: %u tx.lost: %u tp->lost: %u rs->lost: %d " -+ "lost_prev: %d pcount: %d seq: %u end_seq: %u reneg: %u", -+ tcp_snd_cwnd(tp), inet_csk(sk)->icsk_ca_state, -+ tp->packets_out, tp->lost_out, tcp_packets_in_flight(tp), -+ rs->tx_in_flight, TCP_SKB_CB(skb)->tx.lost, tp->lost, -+ rs->lost, lost_prev, pcount, -+ TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, -+ tp->is_sack_reneg)) -+ return ~0U; -+ -+ /* At what prefix of this lost skb did losss rate exceed loss_thresh? */ -+ loss_budget = (u64)inflight_prev * loss_thresh + BBR_UNIT - 1; -+ loss_budget >>= BBR_SCALE; -+ if (lost_prev >= loss_budget) { -+ lost_prefix = 0; /* previous losses crossed loss_thresh */ -+ } else { -+ lost_prefix = loss_budget - lost_prev; -+ lost_prefix <<= BBR_SCALE; -+ divisor = BBR_UNIT - loss_thresh; -+ if (WARN_ON_ONCE(!divisor)) /* loss_thresh is 8 bits */ -+ return ~0U; -+ do_div(lost_prefix, divisor); -+ } -+ -+ inflight_hi = inflight_prev + lost_prefix; -+ return inflight_hi; -+} -+ -+/* If loss/ECN rates during probing indicated we may have overfilled a -+ * buffer, return an operating point that tries to leave unutilized headroom in -+ * the path for other flows, for fairness convergence and lower RTTs and loss. -+ */ -+static u32 bbr_inflight_with_headroom(const struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 headroom, headroom_fraction; -+ -+ if (bbr->inflight_hi == ~0U) -+ return ~0U; -+ -+ headroom_fraction = bbr_param(sk, inflight_headroom); -+ headroom = ((u64)bbr->inflight_hi * headroom_fraction) >> BBR_SCALE; -+ headroom = max(headroom, 1U); -+ return max_t(s32, bbr->inflight_hi - headroom, -+ bbr_param(sk, cwnd_min_target)); -+} -+ -+/* Bound cwnd to a sensible level, based on our current probing state -+ * machine phase and model of a good inflight level (inflight_lo, inflight_hi). -+ */ -+static void bbr_bound_cwnd_for_inflight_model(struct sock *sk) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 cap; -+ -+ /* tcp_rcv_synsent_state_process() currently calls tcp_ack() -+ * and thus cong_control() without first initializing us(!). -+ */ -+ if (!bbr->initialized) -+ return; -+ -+ cap = ~0U; -+ if (bbr->mode == BBR_PROBE_BW && -+ bbr->cycle_idx != BBR_BW_PROBE_CRUISE) { -+ /* Probe to see if more packets fit in the path. */ -+ cap = bbr->inflight_hi; -+ } else { -+ if (bbr->mode == BBR_PROBE_RTT || -+ (bbr->mode == BBR_PROBE_BW && -+ bbr->cycle_idx == BBR_BW_PROBE_CRUISE)) -+ cap = bbr_inflight_with_headroom(sk); -+ } -+ /* Adapt to any loss/ECN since our last bw probe. */ -+ cap = min(cap, bbr->inflight_lo); -+ -+ cap = max_t(u32, cap, bbr_param(sk, cwnd_min_target)); -+ tcp_snd_cwnd_set(tp, min(cap, tcp_snd_cwnd(tp))); -+} -+ -+/* How should we multiplicatively cut bw or inflight limits based on ECN? */ -+u32 bbr_ecn_cut(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ return BBR_UNIT - -+ ((bbr->ecn_alpha * bbr_param(sk, ecn_factor)) >> BBR_SCALE); -+} -+ -+/* Init lower bounds if have not inited yet. */ -+static void bbr_init_lower_bounds(struct sock *sk, bool init_bw) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ if (init_bw && bbr->bw_lo == ~0U) -+ bbr->bw_lo = bbr_max_bw(sk); -+ if (bbr->inflight_lo == ~0U) -+ bbr->inflight_lo = tcp_snd_cwnd(tp); -+} -+ -+/* Reduce bw and inflight to (1 - beta). */ -+static void bbr_loss_lower_bounds(struct sock *sk, u32 *bw, u32 *inflight) -+{ -+ struct bbr* bbr = inet_csk_ca(sk); -+ u32 loss_cut = BBR_UNIT - bbr_param(sk, beta); -+ -+ *bw = max_t(u32, bbr->bw_latest, -+ (u64)bbr->bw_lo * loss_cut >> BBR_SCALE); -+ *inflight = max_t(u32, bbr->inflight_latest, -+ (u64)bbr->inflight_lo * loss_cut >> BBR_SCALE); -+} -+ -+/* Reduce inflight to (1 - alpha*ecn_factor). */ -+static void bbr_ecn_lower_bounds(struct sock *sk, u32 *inflight) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 ecn_cut = bbr_ecn_cut(sk); -+ -+ *inflight = (u64)bbr->inflight_lo * ecn_cut >> BBR_SCALE; -+} -+ -+/* Estimate a short-term lower bound on the capacity available now, based -+ * on measurements of the current delivery process and recent history. When we -+ * are seeing loss/ECN at times when we are not probing bw, then conservatively -+ * move toward flow balance by multiplicatively cutting our short-term -+ * estimated safe rate and volume of data (bw_lo and inflight_lo). We use a -+ * multiplicative decrease in order to converge to a lower capacity in time -+ * logarithmic in the magnitude of the decrease. -+ * -+ * However, we do not cut our short-term estimates lower than the current rate -+ * and volume of delivered data from this round trip, since from the current -+ * delivery process we can estimate the measured capacity available now. -+ * -+ * Anything faster than that approach would knowingly risk high loss, which can -+ * cause low bw for Reno/CUBIC and high loss recovery latency for -+ * request/response flows using any congestion control. -+ */ -+static void bbr_adapt_lower_bounds(struct sock *sk, -+ const struct rate_sample *rs) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 ecn_inflight_lo = ~0U; -+ -+ /* We only use lower-bound estimates when not probing bw. -+ * When probing we need to push inflight higher to probe bw. -+ */ -+ if (bbr_is_probing_bandwidth(sk)) -+ return; -+ -+ /* ECN response. */ -+ if (bbr->ecn_in_round && bbr_param(sk, ecn_factor)) { -+ bbr_init_lower_bounds(sk, false); -+ bbr_ecn_lower_bounds(sk, &ecn_inflight_lo); -+ } -+ -+ /* Loss response. */ -+ if (bbr->loss_in_round) { -+ bbr_init_lower_bounds(sk, true); -+ bbr_loss_lower_bounds(sk, &bbr->bw_lo, &bbr->inflight_lo); -+ } -+ -+ /* Adjust to the lower of the levels implied by loss/ECN. */ -+ bbr->inflight_lo = min(bbr->inflight_lo, ecn_inflight_lo); -+ bbr->bw_lo = max(1U, bbr->bw_lo); -+} -+ -+/* Reset any short-term lower-bound adaptation to congestion, so that we can -+ * push our inflight up. -+ */ -+static void bbr_reset_lower_bounds(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr->bw_lo = ~0U; -+ bbr->inflight_lo = ~0U; -+} -+ -+/* After bw probing (STARTUP/PROBE_UP), reset signals before entering a state -+ * machine phase where we adapt our lower bound based on congestion signals. -+ */ -+static void bbr_reset_congestion_signals(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr->loss_in_round = 0; -+ bbr->ecn_in_round = 0; -+ bbr->loss_in_cycle = 0; -+ bbr->ecn_in_cycle = 0; -+ bbr->bw_latest = 0; -+ bbr->inflight_latest = 0; -+} -+ -+static void bbr_exit_loss_recovery(struct sock *sk) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ tcp_snd_cwnd_set(tp, max(tcp_snd_cwnd(tp), bbr->prior_cwnd)); -+ bbr->try_fast_path = 0; /* bound cwnd using latest model */ -+} -+ -+/* Update rate and volume of delivered data from latest round trip. */ -+static void bbr_update_latest_delivery_signals( -+ struct sock *sk, const struct rate_sample *rs, struct bbr_context *ctx) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr->loss_round_start = 0; -+ if (rs->interval_us <= 0 || !rs->acked_sacked) -+ return; /* Not a valid observation */ -+ -+ bbr->bw_latest = max_t(u32, bbr->bw_latest, ctx->sample_bw); -+ bbr->inflight_latest = max_t(u32, bbr->inflight_latest, rs->delivered); -+ -+ if (!before(rs->prior_delivered, bbr->loss_round_delivered)) { -+ bbr->loss_round_delivered = tp->delivered; -+ bbr->loss_round_start = 1; /* mark start of new round trip */ -+ } -+} -+ -+/* Once per round, reset filter for latest rate and volume of delivered data. */ -+static void bbr_advance_latest_delivery_signals( -+ struct sock *sk, const struct rate_sample *rs, struct bbr_context *ctx) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ /* If ACK matches a TLP retransmit, persist the filter. If we detect -+ * that a TLP retransmit plugged a tail loss, we'll want to remember -+ * how much data the path delivered before the tail loss. -+ */ -+ if (bbr->loss_round_start && !rs->is_acking_tlp_retrans_seq) { -+ bbr->bw_latest = ctx->sample_bw; -+ bbr->inflight_latest = rs->delivered; -+ } -+} -+ -+/* Update (most of) our congestion signals: track the recent rate and volume of -+ * delivered data, presence of loss, and EWMA degree of ECN marking. -+ */ -+static void bbr_update_congestion_signals( -+ struct sock *sk, const struct rate_sample *rs, struct bbr_context *ctx) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u64 bw; -+ -+ if (rs->interval_us <= 0 || !rs->acked_sacked) -+ return; /* Not a valid observation */ -+ bw = ctx->sample_bw; -+ -+ if (!rs->is_app_limited || bw >= bbr_max_bw(sk)) -+ bbr_take_max_bw_sample(sk, bw); -+ -+ bbr->loss_in_round |= (rs->losses > 0); -+ -+ if (!bbr->loss_round_start) -+ return; /* skip the per-round-trip updates */ -+ /* Now do per-round-trip updates. */ -+ bbr_adapt_lower_bounds(sk, rs); -+ -+ bbr->loss_in_round = 0; -+ bbr->ecn_in_round = 0; -+} -+ -+/* Bandwidth probing can cause loss. To help coexistence with loss-based -+ * congestion control we spread out our probing in a Reno-conscious way. Due to -+ * the shape of the Reno sawtooth, the time required between loss epochs for an -+ * idealized Reno flow is a number of round trips that is the BDP of that -+ * flow. We count packet-timed round trips directly, since measured RTT can -+ * vary widely, and Reno is driven by packet-timed round trips. -+ */ -+static bool bbr_is_reno_coexistence_probe_time(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 rounds; -+ -+ /* Random loss can shave some small percentage off of our inflight -+ * in each round. To survive this, flows need robust periodic probes. -+ */ -+ rounds = min_t(u32, bbr_param(sk, bw_probe_max_rounds), bbr_target_inflight(sk)); -+ return bbr->rounds_since_probe >= rounds; -+} -+ -+/* How long do we want to wait before probing for bandwidth (and risking -+ * loss)? We randomize the wait, for better mixing and fairness convergence. -+ * -+ * We bound the Reno-coexistence inter-bw-probe time to be 62-63 round trips. -+ * This is calculated to allow fairness with a 25Mbps, 30ms Reno flow, -+ * (eg 4K video to a broadband user): -+ * BDP = 25Mbps * .030sec /(1514bytes) = 61.9 packets -+ * -+ * We bound the BBR-native inter-bw-probe wall clock time to be: -+ * (a) higher than 2 sec: to try to avoid causing loss for a long enough time -+ * to allow Reno at 30ms to get 4K video bw, the inter-bw-probe time must -+ * be at least: 25Mbps * .030sec / (1514bytes) * 0.030sec = 1.9secs -+ * (b) lower than 3 sec: to ensure flows can start probing in a reasonable -+ * amount of time to discover unutilized bw on human-scale interactive -+ * time-scales (e.g. perhaps traffic from a web page download that we -+ * were competing with is now complete). -+ */ -+static void bbr_pick_probe_wait(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ /* Decide the random round-trip bound for wait until probe: */ -+ bbr->rounds_since_probe = -+ get_random_u32_below(bbr_param(sk, bw_probe_rand_rounds)); -+ /* Decide the random wall clock bound for wait until probe: */ -+ bbr->probe_wait_us = bbr_param(sk, bw_probe_base_us) + -+ get_random_u32_below(bbr_param(sk, bw_probe_rand_us)); -+} -+ -+static void bbr_set_cycle_idx(struct sock *sk, int cycle_idx) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr->cycle_idx = cycle_idx; -+ /* New phase, so need to update cwnd and pacing rate. */ -+ bbr->try_fast_path = 0; -+} -+ -+/* Send at estimated bw to fill the pipe, but not queue. We need this phase -+ * before PROBE_UP, because as soon as we send faster than the available bw -+ * we will start building a queue, and if the buffer is shallow we can cause -+ * loss. If we do not fill the pipe before we cause this loss, our bw_hi and -+ * inflight_hi estimates will underestimate. -+ */ -+static void bbr_start_bw_probe_refill(struct sock *sk, u32 bw_probe_up_rounds) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr_reset_lower_bounds(sk); -+ bbr->bw_probe_up_rounds = bw_probe_up_rounds; -+ bbr->bw_probe_up_acks = 0; -+ bbr->stopped_risky_probe = 0; -+ bbr->ack_phase = BBR_ACKS_REFILLING; -+ bbr->next_rtt_delivered = tp->delivered; -+ bbr_set_cycle_idx(sk, BBR_BW_PROBE_REFILL); -+} -+ -+/* Now probe max deliverable data rate and volume. */ -+static void bbr_start_bw_probe_up(struct sock *sk, struct bbr_context *ctx) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr->ack_phase = BBR_ACKS_PROBE_STARTING; -+ bbr->next_rtt_delivered = tp->delivered; -+ bbr->cycle_mstamp = tp->tcp_mstamp; -+ bbr_reset_full_bw(sk); -+ bbr->full_bw = ctx->sample_bw; -+ bbr_set_cycle_idx(sk, BBR_BW_PROBE_UP); -+ bbr_raise_inflight_hi_slope(sk); -+} -+ -+/* Start a new PROBE_BW probing cycle of some wall clock length. Pick a wall -+ * clock time at which to probe beyond an inflight that we think to be -+ * safe. This will knowingly risk packet loss, so we want to do this rarely, to -+ * keep packet loss rates low. Also start a round-trip counter, to probe faster -+ * if we estimate a Reno flow at our BDP would probe faster. -+ */ -+static void bbr_start_bw_probe_down(struct sock *sk) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr_reset_congestion_signals(sk); -+ bbr->bw_probe_up_cnt = ~0U; /* not growing inflight_hi any more */ -+ bbr_pick_probe_wait(sk); -+ bbr->cycle_mstamp = tp->tcp_mstamp; /* start wall clock */ -+ bbr->ack_phase = BBR_ACKS_PROBE_STOPPING; -+ bbr->next_rtt_delivered = tp->delivered; -+ bbr_set_cycle_idx(sk, BBR_BW_PROBE_DOWN); -+} -+ -+/* Cruise: maintain what we estimate to be a neutral, conservative -+ * operating point, without attempting to probe up for bandwidth or down for -+ * RTT, and only reducing inflight in response to loss/ECN signals. -+ */ -+static void bbr_start_bw_probe_cruise(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ if (bbr->inflight_lo != ~0U) -+ bbr->inflight_lo = min(bbr->inflight_lo, bbr->inflight_hi); -+ -+ bbr_set_cycle_idx(sk, BBR_BW_PROBE_CRUISE); -+} -+ -+/* Loss and/or ECN rate is too high while probing. -+ * Adapt (once per bw probe) by cutting inflight_hi and then restarting cycle. -+ */ -+static void bbr_handle_inflight_too_high(struct sock *sk, -+ const struct rate_sample *rs) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ const u32 beta = bbr_param(sk, beta); -+ -+ bbr->prev_probe_too_high = 1; -+ bbr->bw_probe_samples = 0; /* only react once per probe */ -+ /* If we are app-limited then we are not robustly -+ * probing the max volume of inflight data we think -+ * might be safe (analogous to how app-limited bw -+ * samples are not known to be robustly probing bw). -+ */ -+ if (!rs->is_app_limited) { -+ bbr->inflight_hi = max_t(u32, rs->tx_in_flight, -+ (u64)bbr_target_inflight(sk) * -+ (BBR_UNIT - beta) >> BBR_SCALE); -+ } -+ if (bbr->mode == BBR_PROBE_BW && bbr->cycle_idx == BBR_BW_PROBE_UP) -+ bbr_start_bw_probe_down(sk); -+} -+ -+/* If we're seeing bw and loss samples reflecting our bw probing, adapt -+ * using the signals we see. If loss or ECN mark rate gets too high, then adapt -+ * inflight_hi downward. If we're able to push inflight higher without such -+ * signals, push higher: adapt inflight_hi upward. -+ */ -+static bool bbr_adapt_upper_bounds(struct sock *sk, -+ const struct rate_sample *rs, -+ struct bbr_context *ctx) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ /* Track when we'll see bw/loss samples resulting from our bw probes. */ -+ if (bbr->ack_phase == BBR_ACKS_PROBE_STARTING && bbr->round_start) -+ bbr->ack_phase = BBR_ACKS_PROBE_FEEDBACK; -+ if (bbr->ack_phase == BBR_ACKS_PROBE_STOPPING && bbr->round_start) { -+ /* End of samples from bw probing phase. */ -+ bbr->bw_probe_samples = 0; -+ bbr->ack_phase = BBR_ACKS_INIT; -+ /* At this point in the cycle, our current bw sample is also -+ * our best recent chance at finding the highest available bw -+ * for this flow. So now is the best time to forget the bw -+ * samples from the previous cycle, by advancing the window. -+ */ -+ if (bbr->mode == BBR_PROBE_BW && !rs->is_app_limited) -+ bbr_advance_max_bw_filter(sk); -+ /* If we had an inflight_hi, then probed and pushed inflight all -+ * the way up to hit that inflight_hi without seeing any -+ * high loss/ECN in all the resulting ACKs from that probing, -+ * then probe up again, this time letting inflight persist at -+ * inflight_hi for a round trip, then accelerating beyond. -+ */ -+ if (bbr->mode == BBR_PROBE_BW && -+ bbr->stopped_risky_probe && !bbr->prev_probe_too_high) { -+ bbr_start_bw_probe_refill(sk, 0); -+ return true; /* yes, decided state transition */ -+ } -+ } -+ if (bbr_is_inflight_too_high(sk, rs)) { -+ if (bbr->bw_probe_samples) /* sample is from bw probing? */ -+ bbr_handle_inflight_too_high(sk, rs); -+ } else { -+ /* Loss/ECN rate is declared safe. Adjust upper bound upward. */ -+ -+ if (bbr->inflight_hi == ~0U) -+ return false; /* no excess queue signals yet */ -+ -+ /* To be resilient to random loss, we must raise bw/inflight_hi -+ * if we observe in any phase that a higher level is safe. -+ */ -+ if (rs->tx_in_flight > bbr->inflight_hi) { -+ bbr->inflight_hi = rs->tx_in_flight; -+ } -+ -+ if (bbr->mode == BBR_PROBE_BW && -+ bbr->cycle_idx == BBR_BW_PROBE_UP) -+ bbr_probe_inflight_hi_upward(sk, rs); -+ } -+ -+ return false; -+} -+ -+/* Check if it's time to probe for bandwidth now, and if so, kick it off. */ -+static bool bbr_check_time_to_probe_bw(struct sock *sk, -+ const struct rate_sample *rs) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 n; -+ -+ /* If we seem to be at an operating point where we are not seeing loss -+ * but we are seeing ECN marks, then when the ECN marks cease we reprobe -+ * quickly (in case cross-traffic has ceased and freed up bw). -+ */ -+ if (bbr_param(sk, ecn_reprobe_gain) && bbr->ecn_eligible && -+ bbr->ecn_in_cycle && !bbr->loss_in_cycle && -+ inet_csk(sk)->icsk_ca_state == TCP_CA_Open) { -+ /* Calculate n so that when bbr_raise_inflight_hi_slope() -+ * computes growth_this_round as 2^n it will be roughly the -+ * desired volume of data (inflight_hi*ecn_reprobe_gain). -+ */ -+ n = ilog2((((u64)bbr->inflight_hi * -+ bbr_param(sk, ecn_reprobe_gain)) >> BBR_SCALE)); -+ bbr_start_bw_probe_refill(sk, n); -+ return true; -+ } -+ -+ if (bbr_has_elapsed_in_phase(sk, bbr->probe_wait_us) || -+ bbr_is_reno_coexistence_probe_time(sk)) { -+ bbr_start_bw_probe_refill(sk, 0); -+ return true; -+ } -+ return false; -+} -+ -+/* Is it time to transition from PROBE_DOWN to PROBE_CRUISE? */ -+static bool bbr_check_time_to_cruise(struct sock *sk, u32 inflight, u32 bw) -+{ -+ /* Always need to pull inflight down to leave headroom in queue. */ -+ if (inflight > bbr_inflight_with_headroom(sk)) -+ return false; -+ -+ return inflight <= bbr_inflight(sk, bw, BBR_UNIT); -+} -+ -+/* PROBE_BW state machine: cruise, refill, probe for bw, or drain? */ -+static void bbr_update_cycle_phase(struct sock *sk, -+ const struct rate_sample *rs, -+ struct bbr_context *ctx) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ bool is_bw_probe_done = false; -+ u32 inflight, bw; -+ -+ if (!bbr_full_bw_reached(sk)) -+ return; -+ -+ /* In DRAIN, PROBE_BW, or PROBE_RTT, adjust upper bounds. */ -+ if (bbr_adapt_upper_bounds(sk, rs, ctx)) -+ return; /* already decided state transition */ -+ -+ if (bbr->mode != BBR_PROBE_BW) -+ return; -+ -+ inflight = bbr_packets_in_net_at_edt(sk, rs->prior_in_flight); -+ bw = bbr_max_bw(sk); -+ -+ switch (bbr->cycle_idx) { -+ /* First we spend most of our time cruising with a pacing_gain of 1.0, -+ * which paces at the estimated bw, to try to fully use the pipe -+ * without building queue. If we encounter loss/ECN marks, we adapt -+ * by slowing down. -+ */ -+ case BBR_BW_PROBE_CRUISE: -+ if (bbr_check_time_to_probe_bw(sk, rs)) -+ return; /* already decided state transition */ -+ break; -+ -+ /* After cruising, when it's time to probe, we first "refill": we send -+ * at the estimated bw to fill the pipe, before probing higher and -+ * knowingly risking overflowing the bottleneck buffer (causing loss). -+ */ -+ case BBR_BW_PROBE_REFILL: -+ if (bbr->round_start) { -+ /* After one full round trip of sending in REFILL, we -+ * start to see bw samples reflecting our REFILL, which -+ * may be putting too much data in flight. -+ */ -+ bbr->bw_probe_samples = 1; -+ bbr_start_bw_probe_up(sk, ctx); -+ } -+ break; -+ -+ /* After we refill the pipe, we probe by using a pacing_gain > 1.0, to -+ * probe for bw. If we have not seen loss/ECN, we try to raise inflight -+ * to at least pacing_gain*BDP; note that this may take more than -+ * min_rtt if min_rtt is small (e.g. on a LAN). -+ * -+ * We terminate PROBE_UP bandwidth probing upon any of the following: -+ * -+ * (1) We've pushed inflight up to hit the inflight_hi target set in the -+ * most recent previous bw probe phase. Thus we want to start -+ * draining the queue immediately because it's very likely the most -+ * recently sent packets will fill the queue and cause drops. -+ * (2) If inflight_hi has not limited bandwidth growth recently, and -+ * yet delivered bandwidth has not increased much recently -+ * (bbr->full_bw_now). -+ * (3) Loss filter says loss rate is "too high". -+ * (4) ECN filter says ECN mark rate is "too high". -+ * -+ * (1) (2) checked here, (3) (4) checked in bbr_is_inflight_too_high() -+ */ -+ case BBR_BW_PROBE_UP: -+ if (bbr->prev_probe_too_high && -+ inflight >= bbr->inflight_hi) { -+ bbr->stopped_risky_probe = 1; -+ is_bw_probe_done = true; -+ } else { -+ if (tp->is_cwnd_limited && -+ tcp_snd_cwnd(tp) >= bbr->inflight_hi) { -+ /* inflight_hi is limiting bw growth */ -+ bbr_reset_full_bw(sk); -+ bbr->full_bw = ctx->sample_bw; -+ } else if (bbr->full_bw_now) { -+ /* Plateau in estimated bw. Pipe looks full. */ -+ is_bw_probe_done = true; -+ } -+ } -+ if (is_bw_probe_done) { -+ bbr->prev_probe_too_high = 0; /* no loss/ECN (yet) */ -+ bbr_start_bw_probe_down(sk); /* restart w/ down */ -+ } -+ break; -+ -+ /* After probing in PROBE_UP, we have usually accumulated some data in -+ * the bottleneck buffer (if bw probing didn't find more bw). We next -+ * enter PROBE_DOWN to try to drain any excess data from the queue. To -+ * do this, we use a pacing_gain < 1.0. We hold this pacing gain until -+ * our inflight is less then that target cruising point, which is the -+ * minimum of (a) the amount needed to leave headroom, and (b) the -+ * estimated BDP. Once inflight falls to match the target, we estimate -+ * the queue is drained; persisting would underutilize the pipe. -+ */ -+ case BBR_BW_PROBE_DOWN: -+ if (bbr_check_time_to_probe_bw(sk, rs)) -+ return; /* already decided state transition */ -+ if (bbr_check_time_to_cruise(sk, inflight, bw)) -+ bbr_start_bw_probe_cruise(sk); -+ break; -+ -+ default: -+ WARN_ONCE(1, "BBR invalid cycle index %u\n", bbr->cycle_idx); -+ } -+} -+ -+/* Exiting PROBE_RTT, so return to bandwidth probing in STARTUP or PROBE_BW. */ -+static void bbr_exit_probe_rtt(struct sock *sk) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ bbr_reset_lower_bounds(sk); -+ if (bbr_full_bw_reached(sk)) { -+ bbr->mode = BBR_PROBE_BW; -+ /* Raising inflight after PROBE_RTT may cause loss, so reset -+ * the PROBE_BW clock and schedule the next bandwidth probe for -+ * a friendly and randomized future point in time. -+ */ -+ bbr_start_bw_probe_down(sk); -+ /* Since we are exiting PROBE_RTT, we know inflight is -+ * below our estimated BDP, so it is reasonable to cruise. -+ */ -+ bbr_start_bw_probe_cruise(sk); -+ } else { -+ bbr->mode = BBR_STARTUP; -+ } -+} -+ -+/* Exit STARTUP based on loss rate > 1% and loss gaps in round >= N. Wait until -+ * the end of the round in recovery to get a good estimate of how many packets -+ * have been lost, and how many we need to drain with a low pacing rate. -+ */ -+static void bbr_check_loss_too_high_in_startup(struct sock *sk, -+ const struct rate_sample *rs) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ if (bbr_full_bw_reached(sk)) -+ return; -+ -+ /* For STARTUP exit, check the loss rate at the end of each round trip -+ * of Recovery episodes in STARTUP. We check the loss rate at the end -+ * of the round trip to filter out noisy/low loss and have a better -+ * sense of inflight (extent of loss), so we can drain more accurately. -+ */ -+ if (rs->losses && bbr->loss_events_in_round < 0xf) -+ bbr->loss_events_in_round++; /* update saturating counter */ -+ if (bbr_param(sk, full_loss_cnt) && bbr->loss_round_start && -+ inet_csk(sk)->icsk_ca_state == TCP_CA_Recovery && -+ bbr->loss_events_in_round >= bbr_param(sk, full_loss_cnt) && -+ bbr_is_inflight_too_high(sk, rs)) { -+ bbr_handle_queue_too_high_in_startup(sk); -+ return; -+ } -+ if (bbr->loss_round_start) -+ bbr->loss_events_in_round = 0; -+} -+ -+/* Estimate when the pipe is full, using the change in delivery rate: BBR -+ * estimates bw probing filled the pipe if the estimated bw hasn't changed by -+ * at least bbr_full_bw_thresh (25%) after bbr_full_bw_cnt (3) non-app-limited -+ * rounds. Why 3 rounds: 1: rwin autotuning grows the rwin, 2: we fill the -+ * higher rwin, 3: we get higher delivery rate samples. Or transient -+ * cross-traffic or radio noise can go away. CUBIC Hystart shares a similar -+ * design goal, but uses delay and inter-ACK spacing instead of bandwidth. -+ */ -+static void bbr_check_full_bw_reached(struct sock *sk, -+ const struct rate_sample *rs, -+ struct bbr_context *ctx) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 bw_thresh, full_cnt, thresh; -+ -+ if (bbr->full_bw_now || rs->is_app_limited) -+ return; -+ -+ thresh = bbr_param(sk, full_bw_thresh); -+ full_cnt = bbr_param(sk, full_bw_cnt); -+ bw_thresh = (u64)bbr->full_bw * thresh >> BBR_SCALE; -+ if (ctx->sample_bw >= bw_thresh) { -+ bbr_reset_full_bw(sk); -+ bbr->full_bw = ctx->sample_bw; -+ return; -+ } -+ if (!bbr->round_start) -+ return; -+ ++bbr->full_bw_cnt; -+ bbr->full_bw_now = bbr->full_bw_cnt >= full_cnt; -+ bbr->full_bw_reached |= bbr->full_bw_now; -+} -+ -+/* If pipe is probably full, drain the queue and then enter steady-state. */ -+static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs, -+ struct bbr_context *ctx) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { -+ bbr->mode = BBR_DRAIN; /* drain queue we created */ -+ /* Set ssthresh to export purely for monitoring, to signal -+ * completion of initial STARTUP by setting to a non- -+ * TCP_INFINITE_SSTHRESH value (ssthresh is not used by BBR). -+ */ -+ tcp_sk(sk)->snd_ssthresh = -+ bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); -+ bbr_reset_congestion_signals(sk); -+ } /* fall through to check if in-flight is already small: */ -+ if (bbr->mode == BBR_DRAIN && -+ bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= -+ bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT)) { -+ bbr->mode = BBR_PROBE_BW; -+ bbr_start_bw_probe_down(sk); -+ } -+} -+ -+static void bbr_update_model(struct sock *sk, const struct rate_sample *rs, -+ struct bbr_context *ctx) -+{ -+ bbr_update_congestion_signals(sk, rs, ctx); - bbr_update_ack_aggregation(sk, rs); -- bbr_update_cycle_phase(sk, rs); -- bbr_check_full_bw_reached(sk, rs); -- bbr_check_drain(sk, rs); -+ bbr_check_loss_too_high_in_startup(sk, rs); -+ bbr_check_full_bw_reached(sk, rs, ctx); -+ bbr_check_drain(sk, rs, ctx); -+ bbr_update_cycle_phase(sk, rs, ctx); - bbr_update_min_rtt(sk, rs); -- bbr_update_gains(sk); - } - --__bpf_kfunc static void bbr_main(struct sock *sk, const struct rate_sample *rs) -+/* Fast path for app-limited case. -+ * -+ * On each ack, we execute bbr state machine, which primarily consists of: -+ * 1) update model based on new rate sample, and -+ * 2) update control based on updated model or state change. -+ * -+ * There are certain workload/scenarios, e.g. app-limited case, where -+ * either we can skip updating model or we can skip update of both model -+ * as well as control. This provides signifcant softirq cpu savings for -+ * processing incoming acks. -+ * -+ * In case of app-limited, if there is no congestion (loss/ecn) and -+ * if observed bw sample is less than current estimated bw, then we can -+ * skip some of the computation in bbr state processing: -+ * -+ * - if there is no rtt/mode/phase change: In this case, since all the -+ * parameters of the network model are constant, we can skip model -+ * as well control update. -+ * -+ * - else we can skip rest of the model update. But we still need to -+ * update the control to account for the new rtt/mode/phase. -+ * -+ * Returns whether we can take fast path or not. -+ */ -+static bool bbr_run_fast_path(struct sock *sk, bool *update_model, -+ const struct rate_sample *rs, struct bbr_context *ctx) -+{ -+ struct bbr *bbr = inet_csk_ca(sk); -+ u32 prev_min_rtt_us, prev_mode; -+ -+ if (bbr_param(sk, fast_path) && bbr->try_fast_path && -+ rs->is_app_limited && ctx->sample_bw < bbr_max_bw(sk) && -+ !bbr->loss_in_round && !bbr->ecn_in_round ) { -+ prev_mode = bbr->mode; -+ prev_min_rtt_us = bbr->min_rtt_us; -+ bbr_check_drain(sk, rs, ctx); -+ bbr_update_cycle_phase(sk, rs, ctx); -+ bbr_update_min_rtt(sk, rs); -+ -+ if (bbr->mode == prev_mode && -+ bbr->min_rtt_us == prev_min_rtt_us && -+ bbr->try_fast_path) { -+ return true; -+ } -+ -+ /* Skip model update, but control still needs to be updated */ -+ *update_model = false; -+ } -+ return false; -+} -+ -+__bpf_kfunc void bbr_main(struct sock *sk, const struct rate_sample *rs) - { -+ struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); -- u32 bw; -+ struct bbr_context ctx = { 0 }; -+ bool update_model = true; -+ u32 bw, round_delivered; -+ int ce_ratio = -1; -+ -+ round_delivered = bbr_update_round_start(sk, rs, &ctx); -+ if (bbr->round_start) { -+ bbr->rounds_since_probe = -+ min_t(s32, bbr->rounds_since_probe + 1, 0xFF); -+ ce_ratio = bbr_update_ecn_alpha(sk); -+ } -+ bbr_plb(sk, rs, ce_ratio); -+ -+ bbr->ecn_in_round |= (bbr->ecn_eligible && rs->is_ece); -+ bbr_calculate_bw_sample(sk, rs, &ctx); -+ bbr_update_latest_delivery_signals(sk, rs, &ctx); - -- bbr_update_model(sk, rs); -+ if (bbr_run_fast_path(sk, &update_model, rs, &ctx)) -+ goto out; - -+ if (update_model) -+ bbr_update_model(sk, rs, &ctx); -+ -+ bbr_update_gains(sk); - bw = bbr_bw(sk); - bbr_set_pacing_rate(sk, bw, bbr->pacing_gain); -- bbr_set_cwnd(sk, rs, rs->acked_sacked, bw, bbr->cwnd_gain); -+ bbr_set_cwnd(sk, rs, rs->acked_sacked, bw, bbr->cwnd_gain, -+ tcp_snd_cwnd(tp), &ctx); -+ bbr_bound_cwnd_for_inflight_model(sk); -+ -+out: -+ bbr_advance_latest_delivery_signals(sk, rs, &ctx); -+ bbr->prev_ca_state = inet_csk(sk)->icsk_ca_state; -+ bbr->loss_in_cycle |= rs->lost > 0; -+ bbr->ecn_in_cycle |= rs->delivered_ce > 0; - } - - __bpf_kfunc static void bbr_init(struct sock *sk) -@@ -1055,20 +2079,21 @@ __bpf_kfunc static void bbr_init(struct - struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); - -- bbr->prior_cwnd = 0; -+ bbr->initialized = 1; -+ -+ bbr->init_cwnd = min(0x7FU, tcp_snd_cwnd(tp)); -+ bbr->prior_cwnd = tp->prior_cwnd; - tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; -- bbr->rtt_cnt = 0; - bbr->next_rtt_delivered = tp->delivered; - bbr->prev_ca_state = TCP_CA_Open; -- bbr->packet_conservation = 0; - - bbr->probe_rtt_done_stamp = 0; - bbr->probe_rtt_round_done = 0; -+ bbr->probe_rtt_min_us = tcp_min_rtt(tp); -+ bbr->probe_rtt_min_stamp = tcp_jiffies32; - bbr->min_rtt_us = tcp_min_rtt(tp); - bbr->min_rtt_stamp = tcp_jiffies32; - -- minmax_reset(&bbr->bw, bbr->rtt_cnt, 0); /* init max bw to 0 */ -- - bbr->has_seen_rtt = 0; - bbr_init_pacing_rate_from_rtt(sk); - -@@ -1079,7 +2104,7 @@ __bpf_kfunc static void bbr_init(struct - bbr->full_bw_cnt = 0; - bbr->cycle_mstamp = 0; - bbr->cycle_idx = 0; -- bbr_reset_lt_bw_sampling(sk); -+ - bbr_reset_startup_mode(sk); - - bbr->ack_epoch_mstamp = tp->tcp_mstamp; -@@ -1089,78 +2114,236 @@ __bpf_kfunc static void bbr_init(struct - bbr->extra_acked[0] = 0; - bbr->extra_acked[1] = 0; - -+ bbr->ce_state = 0; -+ bbr->prior_rcv_nxt = tp->rcv_nxt; -+ bbr->try_fast_path = 0; -+ - cmpxchg(&sk->sk_pacing_status, SK_PACING_NONE, SK_PACING_NEEDED); -+ -+ /* Start sampling ECN mark rate after first full flight is ACKed: */ -+ bbr->loss_round_delivered = tp->delivered + 1; -+ bbr->loss_round_start = 0; -+ bbr->undo_bw_lo = 0; -+ bbr->undo_inflight_lo = 0; -+ bbr->undo_inflight_hi = 0; -+ bbr->loss_events_in_round = 0; -+ bbr->startup_ecn_rounds = 0; -+ bbr_reset_congestion_signals(sk); -+ bbr->bw_lo = ~0U; -+ bbr->bw_hi[0] = 0; -+ bbr->bw_hi[1] = 0; -+ bbr->inflight_lo = ~0U; -+ bbr->inflight_hi = ~0U; -+ bbr_reset_full_bw(sk); -+ bbr->bw_probe_up_cnt = ~0U; -+ bbr->bw_probe_up_acks = 0; -+ bbr->bw_probe_up_rounds = 0; -+ bbr->probe_wait_us = 0; -+ bbr->stopped_risky_probe = 0; -+ bbr->ack_phase = BBR_ACKS_INIT; -+ bbr->rounds_since_probe = 0; -+ bbr->bw_probe_samples = 0; -+ bbr->prev_probe_too_high = 0; -+ bbr->ecn_eligible = 0; -+ bbr->ecn_alpha = bbr_param(sk, ecn_alpha_init); -+ bbr->alpha_last_delivered = 0; -+ bbr->alpha_last_delivered_ce = 0; -+ bbr->plb.pause_until = 0; -+ -+ tp->fast_ack_mode = bbr_fast_ack_mode ? 1 : 0; - } - --__bpf_kfunc static u32 bbr_sndbuf_expand(struct sock *sk) -+/* BBR marks the current round trip as a loss round. */ -+static void bbr_note_loss(struct sock *sk) - { -- /* Provision 3 * cwnd since BBR may slow-start even during recovery. */ -- return 3; -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ -+ /* Capture "current" data over the full round trip of loss, to -+ * have a better chance of observing the full capacity of the path. -+ */ -+ if (!bbr->loss_in_round) /* first loss in this round trip? */ -+ bbr->loss_round_delivered = tp->delivered; /* set round trip */ -+ bbr->loss_in_round = 1; -+ bbr->loss_in_cycle = 1; - } - --/* In theory BBR does not need to undo the cwnd since it does not -- * always reduce cwnd on losses (see bbr_main()). Keep it for now. -- */ -+/* Core TCP stack informs us that the given skb was just marked lost. */ -+__bpf_kfunc static void bbr_skb_marked_lost(struct sock *sk, -+ const struct sk_buff *skb) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ struct tcp_skb_cb *scb = TCP_SKB_CB(skb); -+ struct rate_sample rs = {}; -+ -+ bbr_note_loss(sk); -+ -+ if (!bbr->bw_probe_samples) -+ return; /* not an skb sent while probing for bandwidth */ -+ if (unlikely(!scb->tx.delivered_mstamp)) -+ return; /* skb was SACKed, reneged, marked lost; ignore it */ -+ /* We are probing for bandwidth. Construct a rate sample that -+ * estimates what happened in the flight leading up to this lost skb, -+ * then see if the loss rate went too high, and if so at which packet. -+ */ -+ rs.tx_in_flight = scb->tx.in_flight; -+ rs.lost = tp->lost - scb->tx.lost; -+ rs.is_app_limited = scb->tx.is_app_limited; -+ if (bbr_is_inflight_too_high(sk, &rs)) { -+ rs.tx_in_flight = bbr_inflight_hi_from_lost_skb(sk, &rs, skb); -+ bbr_handle_inflight_too_high(sk, &rs); -+ } -+} -+ -+static void bbr_run_loss_probe_recovery(struct sock *sk) -+{ -+ struct tcp_sock *tp = tcp_sk(sk); -+ struct bbr *bbr = inet_csk_ca(sk); -+ struct rate_sample rs = {0}; -+ -+ bbr_note_loss(sk); -+ -+ if (!bbr->bw_probe_samples) -+ return; /* not sent while probing for bandwidth */ -+ /* We are probing for bandwidth. Construct a rate sample that -+ * estimates what happened in the flight leading up to this -+ * loss, then see if the loss rate went too high. -+ */ -+ rs.lost = 1; /* TLP probe repaired loss of a single segment */ -+ rs.tx_in_flight = bbr->inflight_latest + rs.lost; -+ rs.is_app_limited = tp->tlp_orig_data_app_limited; -+ if (bbr_is_inflight_too_high(sk, &rs)) -+ bbr_handle_inflight_too_high(sk, &rs); -+} -+ -+/* Revert short-term model if current loss recovery event was spurious. */ - __bpf_kfunc static u32 bbr_undo_cwnd(struct sock *sk) - { - struct bbr *bbr = inet_csk_ca(sk); - -- bbr->full_bw = 0; /* spurious slow-down; reset full pipe detection */ -- bbr->full_bw_cnt = 0; -- bbr_reset_lt_bw_sampling(sk); -- return tcp_snd_cwnd(tcp_sk(sk)); -+ bbr_reset_full_bw(sk); /* spurious slow-down; reset full bw detector */ -+ bbr->loss_in_round = 0; -+ -+ /* Revert to cwnd and other state saved before loss episode. */ -+ bbr->bw_lo = max(bbr->bw_lo, bbr->undo_bw_lo); -+ bbr->inflight_lo = max(bbr->inflight_lo, bbr->undo_inflight_lo); -+ bbr->inflight_hi = max(bbr->inflight_hi, bbr->undo_inflight_hi); -+ bbr->try_fast_path = 0; /* take slow path to set proper cwnd, pacing */ -+ return bbr->prior_cwnd; - } - --/* Entering loss recovery, so save cwnd for when we exit or undo recovery. */ -+/* Entering loss recovery, so save state for when we undo recovery. */ - __bpf_kfunc static u32 bbr_ssthresh(struct sock *sk) - { -+ struct bbr *bbr = inet_csk_ca(sk); -+ - bbr_save_cwnd(sk); -+ /* For undo, save state that adapts based on loss signal. */ -+ bbr->undo_bw_lo = bbr->bw_lo; -+ bbr->undo_inflight_lo = bbr->inflight_lo; -+ bbr->undo_inflight_hi = bbr->inflight_hi; - return tcp_sk(sk)->snd_ssthresh; - } - -+static enum tcp_bbr_phase bbr_get_phase(struct bbr *bbr) -+{ -+ switch (bbr->mode) { -+ case BBR_STARTUP: -+ return BBR_PHASE_STARTUP; -+ case BBR_DRAIN: -+ return BBR_PHASE_DRAIN; -+ case BBR_PROBE_BW: -+ break; -+ case BBR_PROBE_RTT: -+ return BBR_PHASE_PROBE_RTT; -+ default: -+ return BBR_PHASE_INVALID; -+ } -+ switch (bbr->cycle_idx) { -+ case BBR_BW_PROBE_UP: -+ return BBR_PHASE_PROBE_BW_UP; -+ case BBR_BW_PROBE_DOWN: -+ return BBR_PHASE_PROBE_BW_DOWN; -+ case BBR_BW_PROBE_CRUISE: -+ return BBR_PHASE_PROBE_BW_CRUISE; -+ case BBR_BW_PROBE_REFILL: -+ return BBR_PHASE_PROBE_BW_REFILL; -+ default: -+ return BBR_PHASE_INVALID; -+ } -+} -+ - static size_t bbr_get_info(struct sock *sk, u32 ext, int *attr, -- union tcp_cc_info *info) -+ union tcp_cc_info *info) - { - if (ext & (1 << (INET_DIAG_BBRINFO - 1)) || - ext & (1 << (INET_DIAG_VEGASINFO - 1))) { -- struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); -- u64 bw = bbr_bw(sk); -- -- bw = bw * tp->mss_cache * USEC_PER_SEC >> BW_SCALE; -- memset(&info->bbr, 0, sizeof(info->bbr)); -- info->bbr.bbr_bw_lo = (u32)bw; -- info->bbr.bbr_bw_hi = (u32)(bw >> 32); -- info->bbr.bbr_min_rtt = bbr->min_rtt_us; -- info->bbr.bbr_pacing_gain = bbr->pacing_gain; -- info->bbr.bbr_cwnd_gain = bbr->cwnd_gain; -+ u64 bw = bbr_bw_bytes_per_sec(sk, bbr_bw(sk)); -+ u64 bw_hi = bbr_bw_bytes_per_sec(sk, bbr_max_bw(sk)); -+ u64 bw_lo = bbr->bw_lo == ~0U ? -+ ~0ULL : bbr_bw_bytes_per_sec(sk, bbr->bw_lo); -+ struct tcp_bbr_info *bbr_info = &info->bbr; -+ -+ memset(bbr_info, 0, sizeof(*bbr_info)); -+ bbr_info->bbr_bw_lo = (u32)bw; -+ bbr_info->bbr_bw_hi = (u32)(bw >> 32); -+ bbr_info->bbr_min_rtt = bbr->min_rtt_us; -+ bbr_info->bbr_pacing_gain = bbr->pacing_gain; -+ bbr_info->bbr_cwnd_gain = bbr->cwnd_gain; -+ bbr_info->bbr_bw_hi_lsb = (u32)bw_hi; -+ bbr_info->bbr_bw_hi_msb = (u32)(bw_hi >> 32); -+ bbr_info->bbr_bw_lo_lsb = (u32)bw_lo; -+ bbr_info->bbr_bw_lo_msb = (u32)(bw_lo >> 32); -+ bbr_info->bbr_mode = bbr->mode; -+ bbr_info->bbr_phase = (__u8)bbr_get_phase(bbr); -+ bbr_info->bbr_version = (__u8)BBR_VERSION; -+ bbr_info->bbr_inflight_lo = bbr->inflight_lo; -+ bbr_info->bbr_inflight_hi = bbr->inflight_hi; -+ bbr_info->bbr_extra_acked = bbr_extra_acked(sk); - *attr = INET_DIAG_BBRINFO; -- return sizeof(info->bbr); -+ return sizeof(*bbr_info); - } - return 0; - } - - __bpf_kfunc static void bbr_set_state(struct sock *sk, u8 new_state) - { -+ struct tcp_sock *tp = tcp_sk(sk); - struct bbr *bbr = inet_csk_ca(sk); - - if (new_state == TCP_CA_Loss) { -- struct rate_sample rs = { .losses = 1 }; - - bbr->prev_ca_state = TCP_CA_Loss; -- bbr->full_bw = 0; -- bbr->round_start = 1; /* treat RTO like end of a round */ -- bbr_lt_bw_sampling(sk, &rs); -+ tcp_plb_update_state_upon_rto(sk, &bbr->plb); -+ /* The tcp_write_timeout() call to sk_rethink_txhash() likely -+ * repathed this flow, so re-learn the min network RTT on the -+ * new path: -+ */ -+ bbr_reset_full_bw(sk); -+ if (!bbr_is_probing_bandwidth(sk) && bbr->inflight_lo == ~0U) { -+ /* bbr_adapt_lower_bounds() needs cwnd before -+ * we suffered an RTO, to update inflight_lo: -+ */ -+ bbr->inflight_lo = -+ max(tcp_snd_cwnd(tp), bbr->prior_cwnd); -+ } -+ } else if (bbr->prev_ca_state == TCP_CA_Loss && -+ new_state != TCP_CA_Loss) { -+ bbr_exit_loss_recovery(sk); - } - } - -+ - static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = { -- .flags = TCP_CONG_NON_RESTRICTED, -+ .flags = TCP_CONG_NON_RESTRICTED | TCP_CONG_WANTS_CE_EVENTS, - .name = "bbr", - .owner = THIS_MODULE, - .init = bbr_init, - .cong_control = bbr_main, - .sndbuf_expand = bbr_sndbuf_expand, -+ .skb_marked_lost = bbr_skb_marked_lost, - .undo_cwnd = bbr_undo_cwnd, - .cwnd_event = bbr_cwnd_event, - .ssthresh = bbr_ssthresh, -@@ -1175,10 +2358,11 @@ BTF_SET8_START(tcp_bbr_check_kfunc_ids) - BTF_ID_FLAGS(func, bbr_init) - BTF_ID_FLAGS(func, bbr_main) - BTF_ID_FLAGS(func, bbr_sndbuf_expand) -+BTF_ID_FLAGS(func, bbr_skb_marked_lost) - BTF_ID_FLAGS(func, bbr_undo_cwnd) - BTF_ID_FLAGS(func, bbr_cwnd_event) - BTF_ID_FLAGS(func, bbr_ssthresh) --BTF_ID_FLAGS(func, bbr_min_tso_segs) -+BTF_ID_FLAGS(func, bbr_tso_segs) - BTF_ID_FLAGS(func, bbr_set_state) - #endif - #endif -@@ -1213,5 +2397,12 @@ MODULE_AUTHOR("Van Jacobson "); - MODULE_AUTHOR("Yuchung Cheng "); - MODULE_AUTHOR("Soheil Hassas Yeganeh "); -+MODULE_AUTHOR("Priyaranjan Jha "); -+MODULE_AUTHOR("Yousuk Seung "); -+MODULE_AUTHOR("Kevin Yang "); -+MODULE_AUTHOR("Arjun Roy "); -+MODULE_AUTHOR("David Morley "); -+ - MODULE_LICENSE("Dual BSD/GPL"); - MODULE_DESCRIPTION("TCP BBR (Bottleneck Bandwidth and RTT)"); -+MODULE_VERSION(__stringify(BBR_VERSION)); diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch deleted file mode 100644 index e927946a6..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 17d1b4acccbfb50826774eda03ac802aeb81c49e Mon Sep 17 00:00:00 2001 -From: Adithya Abraham Philip -Date: Fri, 11 Jun 2021 21:56:10 +0000 -Subject: [PATCH 17/18] net-tcp_bbr: v3: ensure ECN-enabled BBR flows set ECT - on retransmits - -Adds a new flag TCP_ECN_ECT_PERMANENT that is used by CCAs to -indicate that retransmitted packets and pure ACKs must have the -ECT bit set. This is necessary for BBR, which when using -ECN expects ECT to be set even on retransmitted packets and ACKs. - -Previous to this addition of TCP_ECN_ECT_PERMANENT, CCAs which can use -ECN but don't "need" it did not have a way to indicate that ECT should -be set on retransmissions/ACKs. - -Signed-off-by: Adithya Abraham Philip -Signed-off-by: Neal Cardwell -Change-Id: I8b048eaab35e136fe6501ef6cd89fd9faa15e6d2 -Signed-off-by: Alexandre Frade ---- - include/net/tcp.h | 1 + - net/ipv4/tcp_bbr.c | 3 +++ - net/ipv4/tcp_output.c | 3 ++- - 3 files changed, 6 insertions(+), 1 deletion(-) - ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -373,6 +373,7 @@ static inline void tcp_dec_quickack_mode - #define TCP_ECN_DEMAND_CWR 4 - #define TCP_ECN_SEEN 8 - #define TCP_ECN_LOW 16 -+#define TCP_ECN_ECT_PERMANENT 32 - - enum tcp_tw_status { - TCP_TW_SUCCESS = 0, ---- a/net/ipv4/tcp_bbr.c -+++ b/net/ipv4/tcp_bbr.c -@@ -2151,6 +2151,9 @@ __bpf_kfunc static void bbr_init(struct - bbr->plb.pause_until = 0; - - tp->fast_ack_mode = bbr_fast_ack_mode ? 1 : 0; -+ -+ if (bbr_can_use_ecn(sk)) -+ tp->ecn_flags |= TCP_ECN_ECT_PERMANENT; - } - - /* BBR marks the current round trip as a loss round. */ ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -388,7 +388,8 @@ static void tcp_ecn_send(struct sock *sk - th->cwr = 1; - skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; - } -- } else if (!tcp_ca_needs_ecn(sk)) { -+ } else if (!(tp->ecn_flags & TCP_ECN_ECT_PERMANENT) && -+ !tcp_ca_needs_ecn(sk)) { - /* ACK or retransmitted segment: clear ECT|CE */ - INET_ECN_dontxmit(sk); - } diff --git a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch deleted file mode 100644 index d8642a778..000000000 --- a/openwrt/patch/kernel-6.6/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 54488b0d0855fc0e772fcdf4d7a2756219e3757c Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Sun, 23 Jul 2023 23:25:34 -0400 -Subject: [PATCH 18/18] tcp: export TCPI_OPT_ECN_LOW in tcp_info tcpi_options - field - -Analogous to other important ECN information, export TCPI_OPT_ECN_LOW -in tcp_info tcpi_options field. - -Signed-off-by: Neal Cardwell -Change-Id: I08d8d8c7e8780e6e37df54038ee50301ac5a0320 -Signed-off-by: Alexandre Frade ---- - include/uapi/linux/tcp.h | 1 + - net/ipv4/tcp.c | 2 ++ - 2 files changed, 3 insertions(+) - ---- a/include/uapi/linux/tcp.h -+++ b/include/uapi/linux/tcp.h -@@ -170,6 +170,7 @@ enum tcp_fastopen_client_fail { - #define TCPI_OPT_ECN 8 /* ECN was negociated at TCP session init */ - #define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */ - #define TCPI_OPT_SYN_DATA 32 /* SYN-ACK acked data in SYN sent or rcvd */ -+#define TCPI_OPT_ECN_LOW 64 /* Low-latency ECN configured at init */ - - /* - * Sender's congestion state indicating normal or abnormal situations ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -3791,6 +3791,8 @@ void tcp_get_info(struct sock *sk, struc - info->tcpi_options |= TCPI_OPT_ECN; - if (tp->ecn_flags & TCP_ECN_SEEN) - info->tcpi_options |= TCPI_OPT_ECN_SEEN; -+ if (tp->ecn_flags & TCP_ECN_LOW) -+ info->tcpi_options |= TCPI_OPT_ECN_LOW; - if (tp->syn_data_acked) - info->tcpi_options |= TCPI_OPT_SYN_DATA; - diff --git a/openwrt/patch/kernel-6.6/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.6/btf/990-btf-silence-btf-module-warning-messages.patch deleted file mode 100644 index d5b98b990..000000000 --- a/openwrt/patch/kernel-6.6/btf/990-btf-silence-btf-module-warning-messages.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 5e5aa2d2722f835878447e93f7bc623d344611ae Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 14 Jan 2024 04:35:39 +0800 -Subject: [PATCH] btf: silence btf module warning messages - -Signed-off-by: sbwml ---- - kernel/bpf/btf.c | 2 -- - 1 file changed, 2 deletions(-) - ---- a/kernel/bpf/btf.c -+++ b/kernel/bpf/btf.c -@@ -7376,8 +7376,6 @@ static int btf_module_notify(struct noti - pr_warn("failed to validate module [%s] BTF: %ld\n", - mod->name, PTR_ERR(btf)); - err = PTR_ERR(btf); -- } else { -- pr_warn_once("Kernel module BTF mismatch detected, BTF debug info may be unavailable for some modules\n"); - } - goto out; - } diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch deleted file mode 100644 index b86025af8..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch +++ /dev/null @@ -1,4336 +0,0 @@ -From 9b56d7ac8b429d14dfdc07956cce303f4d401d9f Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Tue, 25 Apr 2023 22:22:44 +0200 -Subject: [PATCH 01/25] LRNG: Entropy Source and DRNG Manager - -The kernel crypto API contains deterministic random number generators -(DRNG) which a caller must seed and reseed. The task of seeding a DRNG -is a non-trivial task requiring the consideration of a significant -number of aspects. The Entropy Source and DRNG Manager (ESDM) fills -that gap to transparently seed and reseed DRNGs. A user of the ESDM -obtains random numbers from an appropriately seeded and initialized -DRNG. Further, the ESDM controls various entropy sources guaranteeing -that they are properly initialized and managed. - -The ESDM consists of two main parts: - -- The entropy source (ES) manager implemented in lrng_es_mgr.c - controls the available entropy sources including pulling appropritate - amount of data from them for the DRNG manager. - -- The DRNG manager provided with lrng_drng_mgr.c controls the DRNG(s) - and ensures proper seeding and reseeding. - -The entropy source manager controls the entropy sources registered in -the lrng_es array. The entropy sources provide a function pointer data -structure that is used to obtain the services from it. - -The ES manager triggers the initial seeding of the DRNGs during boot -time in three stages: - -1. The DRNG is seeded from the entropy sources if all entropy sources - collectively have at least 32 bits of entropy available. The goal - of this step is to ensure that the DRNG receive some initial entropy - as early as possible. - -2. The DRNG is reseeded from the entropy sources if all entropy sources - collectively have at least 128 bits of entropy available. - -3. The DRNG is reseeded from the entropy sources if all entropy sources - collectively have at least 256 bits of entropy available. - -At the time of the reseeding steps, the DRNG requests as much entropy as -is available in order to skip certain steps and reach the seeding level -of 256 bits. This may imply that one or more of the aforementioned steps -are skipped. - -In all listed steps, the DRNG is (re)seeded with a number of random bytes -from the entropy pool that is at most the amount of entropy present in -the entropy pool. This means that for example when the entropy pool -contains 128 or more bits of entropy, the DRNG is seeded with that amount -of entropy as well. - -Entropy sources (ES) inform the ES manager when new entropy has been -collected using the lrng_es_add_entropy() function. That function -schedules a DRNG (re)seed with the DRNG manager. When the DRNG manager -requests entropy data, the function lrng_fill_seed_buffer fills the seed -buffer by iterating through all available ES. The output of all entropy -sources is concatenated with each other. Further, the seed buffer -contains the amount of entropy each entropy credits its data. Finally a -time stamp is added. - -The ES trigger such (re)seeding events only as long as not all DRNGs -are fully seeded with 256 bits of entropy. Once that seeding level is -reached, the triggers are not further processed. - -The DRNG manager initializes the initial DRNG instance during late stage -of the kernel boot process before user space is triggered. The DRNG is -seeded at the following occasions: - -- when the DRNG is initialized, the available amount of entropy is used, - -- during boot time until the DRNG is fully initialized, the reaching of - the aforementioned seeding steps of 32/128/256 bits of entropy trigger - a reseed of the DRNG. - -- at runtime after the elapse of 600 seconds since the last seeding, - the DRNG reseeding flag is raised - -- at runtime when more than 2^20 generate operations were performed by - the given DRNG since last reseeding, the reseeding flag is raised - -Raising the reseeding flag implies that the DRNG is seeded in process -context the next time a caller requests random numbers. - -At runtime, the DRNG manager requires at least 128 bits of entropy from -the entropy sources (or 256 bits when the FIPS mode is active to be -SP800-90C compliant). It may be possible that the entropy sources may -not deliver that amount. The DRNG is reseeded with the available amount -of entropy and continues to operate. Yet, when after 2^30 generate -requests since the last seeding with 128 bits (or 256 bits in FIPS mode) -the DRNG cannot be seeded with 128 bits (or 256 bits), the DRNG becomes -unseeded which means it will not produce random numbers until it is -fully reseeded again. - -To support the DRNG manager, a DRNG implementation is provided with -lrng_drng_kcapi.c. It uses the kernel crypto API RNG framework and -allows the specification of the used DRNG with the kernel command line -option of lrng_drng_kcapi.drng_name. If no reference is given, the -default is the SP800-90A DRBG. In case the chosen DRNG requires the seed -to have a certain length, a hash is used bring the entropy buffer into -the proper size. - -In addition, the DRNG manager controls the message digest implementation -offered to entropy sources when they want to perform a conditioning -operation. As entropy sources may require the conditioning operation at -any time, the default is a SHA-256 software hash implementation that -neither sleeps nor does it need any memory allocation operation. -Therefore, this hash is available even for the earliest kernel -operations. - -The initial drop of the ESDM includes the entropy source of the -"auxiliary" pool. This entropy source must always be present. It is an -entropy pool that is based on the state of a message digest. Every -insertion of data is a hash update operation. In order to obtain data, a -hash final operation is performed. The purpose of this auxiliary pool is -twofold: - -- Provide a general interface to inject an arbitrary amount of data from - any external source. When providing such data, the caller may specify - the amount of entropy it contains. - -- The auxiliary pool also provides the backtracking resistance for all - entropy sources. Once a seed buffer is filled from all entropy sources - it is re-inserted into the auxiliary pool at the same time it is used - for seeding the DRNG. Naturally, the insertion of the seed buffer into - the auxiliary pool is not credited with any entropy. - -If enabled during compile time with the boot option of -fips=1, the entropy source oversampling is activated. The oversampling -pulls 128 more bits of entropy than originally requested. This implies -that when 256 bits of entropy are requested for a (re)seed of a DRNG, -the ES are queried for 384 bits. This oversampling complies with -SP800-90C. - -This patch set contains a number of header files for subsequent -additions, but with the current Kconfig settings, these additional -settings will be folded to noops. - -Signed-off-by: Stephan Mueller ---- - drivers/char/Kconfig | 2 + - drivers/char/Makefile | 2 + - drivers/char/lrng/Kconfig | 1017 +++++++++++++++++ - drivers/char/lrng/Makefile | 11 + - drivers/char/lrng/lrng_definitions.h | 163 +++ - drivers/char/lrng/lrng_drng_atomic.h | 23 + - drivers/char/lrng/lrng_drng_chacha20.c | 195 ++++ - drivers/char/lrng/lrng_drng_chacha20.h | 42 + - drivers/char/lrng/lrng_drng_drbg.h | 13 + - drivers/char/lrng/lrng_drng_kcapi.h | 13 + - drivers/char/lrng/lrng_drng_mgr.c | 742 ++++++++++++ - drivers/char/lrng/lrng_drng_mgr.h | 86 ++ - drivers/char/lrng/lrng_es_aux.c | 335 ++++++ - drivers/char/lrng/lrng_es_aux.h | 44 + - drivers/char/lrng/lrng_es_cpu.h | 17 + - drivers/char/lrng/lrng_es_irq.h | 24 + - drivers/char/lrng/lrng_es_jent.h | 17 + - drivers/char/lrng/lrng_es_krng.h | 17 + - drivers/char/lrng/lrng_es_mgr.c | 506 ++++++++ - drivers/char/lrng/lrng_es_mgr.h | 56 + - drivers/char/lrng/lrng_es_mgr_cb.h | 87 ++ - drivers/char/lrng/lrng_es_sched.h | 20 + - drivers/char/lrng/lrng_es_timer_common.h | 83 ++ - drivers/char/lrng/lrng_interface_dev_common.h | 51 + - .../char/lrng/lrng_interface_random_kernel.h | 17 + - drivers/char/lrng/lrng_numa.h | 11 + - drivers/char/lrng/lrng_sha.h | 14 + - drivers/char/lrng/lrng_sha1.c | 88 ++ - drivers/char/lrng/lrng_sha256.c | 72 ++ - drivers/char/lrng/lrng_sysctl.h | 15 + - include/linux/lrng.h | 251 ++++ - 31 files changed, 4034 insertions(+) - create mode 100644 drivers/char/lrng/Kconfig - create mode 100644 drivers/char/lrng/Makefile - create mode 100644 drivers/char/lrng/lrng_definitions.h - create mode 100644 drivers/char/lrng/lrng_drng_atomic.h - create mode 100644 drivers/char/lrng/lrng_drng_chacha20.c - create mode 100644 drivers/char/lrng/lrng_drng_chacha20.h - create mode 100644 drivers/char/lrng/lrng_drng_drbg.h - create mode 100644 drivers/char/lrng/lrng_drng_kcapi.h - create mode 100644 drivers/char/lrng/lrng_drng_mgr.c - create mode 100644 drivers/char/lrng/lrng_drng_mgr.h - create mode 100644 drivers/char/lrng/lrng_es_aux.c - create mode 100644 drivers/char/lrng/lrng_es_aux.h - create mode 100644 drivers/char/lrng/lrng_es_cpu.h - create mode 100644 drivers/char/lrng/lrng_es_irq.h - create mode 100644 drivers/char/lrng/lrng_es_jent.h - create mode 100644 drivers/char/lrng/lrng_es_krng.h - create mode 100644 drivers/char/lrng/lrng_es_mgr.c - create mode 100644 drivers/char/lrng/lrng_es_mgr.h - create mode 100644 drivers/char/lrng/lrng_es_mgr_cb.h - create mode 100644 drivers/char/lrng/lrng_es_sched.h - create mode 100644 drivers/char/lrng/lrng_es_timer_common.h - create mode 100644 drivers/char/lrng/lrng_interface_dev_common.h - create mode 100644 drivers/char/lrng/lrng_interface_random_kernel.h - create mode 100644 drivers/char/lrng/lrng_numa.h - create mode 100644 drivers/char/lrng/lrng_sha.h - create mode 100644 drivers/char/lrng/lrng_sha1.c - create mode 100644 drivers/char/lrng/lrng_sha256.c - create mode 100644 drivers/char/lrng/lrng_sysctl.h - create mode 100644 include/linux/lrng.h - ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -422,4 +422,6 @@ config ADI - and SSM (Silicon Secured Memory). Intended consumers of this - driver include crash and makedumpfile. - -+source "drivers/char/lrng/Kconfig" -+ - endmenu ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -44,3 +44,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o - obj-$(CONFIG_XILLYBUS_CLASS) += xillybus/ - obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o - obj-$(CONFIG_ADI) += adi.o -+ -+obj-$(CONFIG_LRNG) += lrng/ ---- /dev/null -+++ b/drivers/char/lrng/Kconfig -@@ -0,0 +1,1017 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# Linux Random Number Generator configuration -+# -+ -+config RANDOM_DEFAULT_IMPL -+ bool "Kernel RNG Default Implementation" -+ default y -+ help -+ The default random number generator as provided with -+ drivers/char/random.c is selected with this option. -+ -+config LRNG_AUTO_SELECTED -+ bool -+ default y if !RANDOM_DEFAULT_IMPL -+ default n if RANDOM_DEFAULT_IMPL -+ select LRNG -+ -+config LRNG -+ bool "Linux Random Number Generator" -+ default n -+ select CRYPTO_LIB_SHA256 if CRYPTO -+ help -+ The Linux Random Number Generator (LRNG) generates entropy -+ from different entropy sources. Each entropy source can -+ be enabled and configured independently. The interrupt -+ entropy source can be configured to be SP800-90B compliant. -+ The entire LRNG can be configured to be SP800-90C compliant. -+ Runtime-switchable cryptographic support is available. -+ The LRNG delivers significant entropy during boot. -+ -+ The LRNG also provides compliance to SP800-90A/B/C. -+ -+menu "Linux Random Number Generator Configuration" -+ depends on LRNG -+ -+if LRNG -+ -+config LRNG_SHA256 -+ bool -+ default y if CRYPTO_LIB_SHA256 -+ -+config LRNG_SHA1 -+ bool -+ default y if !CRYPTO_LIB_SHA256 -+ -+config LRNG_COMMON_DEV_IF -+ bool -+ -+config LRNG_DRNG_ATOMIC -+ bool -+ select LRNG_DRNG_CHACHA20 -+ -+config LRNG_SYSCTL -+ bool -+ depends on SYSCTL -+ -+config LRNG_RANDOM_IF -+ bool -+ default n if RANDOM_DEFAULT_IMPL -+ default y if !RANDOM_DEFAULT_IMPL -+ select LRNG_COMMON_DEV_IF -+ select LRNG_DRNG_ATOMIC -+ select LRNG_SYSCTL -+ -+menu "Specific DRNG seeding strategies" -+ -+config LRNG_AIS2031_NTG1_SEEDING_STRATEGY -+ bool "AIS 20/31 NTG.1 seeding strategy" -+ default n -+ help -+ When enabling this option, two entropy sources must -+ deliver 220 bits of entropy each to consider a DRNG -+ as fully seeded. Any two entropy sources can be used -+ to fulfill this requirement. If specific entropy sources -+ shall not be capable of contributing to this seeding -+ strategy, the respective entropy source must be configured -+ to provide less than 220 bits of entropy. -+ -+ The strategy is consistent with the requirements for -+ NTG.1 compliance in German AIS 20/31 draft from 2022 -+ and is only enforced with lrng_es_mgr.ntg1=1. -+ -+ Compliance with German AIS 20/31 from 2011 is always -+ present when using /dev/random with the flag O_SYNC or -+ getrandom(2) with GRND_RANDOM. -+ -+ If unsure, say N. -+ -+endmenu # "Specific DRNG seeding strategies" -+ -+# menu "LRNG Interfaces" -+# -+# config LRNG_KCAPI_IF -+# tristate "Interface with Kernel Crypto API" -+# depends on CRYPTO_RNG -+# help -+# The LRNG can be registered with the kernel crypto API's -+# random number generator framework. This offers a random -+# number generator with the name "lrng" and a priority that -+# is intended to be higher than the existing RNG -+# implementations. -+# -+# config LRNG_HWRAND_IF -+# tristate "Interface with Hardware Random Number Generator Framework" -+# depends on HW_RANDOM -+# select LRNG_DRNG_ATOMIC -+# help -+# The LRNG can be registered with the hardware random number -+# generator framework. This offers a random number generator -+# with the name "lrng" that is accessible via the framework. -+# For example it allows pulling data from the LRNG via the -+# /dev/hwrng file. -+# -+# config LRNG_DEV_IF -+# bool "Character device file interface" -+# select LRNG_COMMON_DEV_IF -+# help -+# The LRNG can create a character device file that operates -+# identically to /dev/random including IOCTL, read and write -+# operations. -+# -+# endmenu # "LRNG Interfaces" -+ -+# menu "Entropy Source Configuration" -+# -+# config LRNG_RUNTIME_ES_CONFIG -+# bool "Enable runtime configuration of entropy sources" -+# help -+# When enabling this option, the LRNG provides the mechanism -+# allowing to alter the entropy rate of each entropy source -+# during boot time and runtime. -+# -+# Each entropy source allows its entropy rate changed with -+# a kernel command line option. When not providing any -+# option, the default specified during kernel compilation -+# is applied. -+# -+# comment "Common Timer-based Entropy Source Configuration" -+# -+# config LRNG_IRQ_DFLT_TIMER_ES -+# bool -+# -+# config LRNG_SCHED_DFLT_TIMER_ES -+# bool -+# -+# config LRNG_TIMER_COMMON -+# bool -+# -+# choice -+# prompt "Default Timer-based Entropy Source" -+# default LRNG_IRQ_DFLT_TIMER_ES -+# depends on LRNG_TIMER_COMMON -+# help -+# Select the timer-based entropy source that is credited -+# with entropy. The other timer-based entropy sources may -+# be operational and provide data, but are credited with no -+# entropy. -+# -+# config LRNG_IRQ_DFLT_TIMER_ES -+# bool "Interrupt Entropy Source" -+# depends on LRNG_IRQ -+# help -+# The interrupt entropy source is selected as a timer-based -+# entropy source to provide entropy. -+# -+# config LRNG_SCHED_DFLT_TIMER_ES -+# bool "Scheduler Entropy Source" -+# depends on LRNG_SCHED -+# help -+# The scheduler entropy source is selected as timer-based -+# entropy source to provide entropy. -+# endchoice -+# -+# choice -+# prompt "LRNG Entropy Collection Pool Size" -+# default LRNG_COLLECTION_SIZE_1024 -+# depends on LRNG_TIMER_COMMON -+# help -+# Select the size of the LRNG entropy collection pool -+# storing data for the interrupt as well as the scheduler -+# entropy sources without performing a compression -+# operation. The larger the collection size is, the faster -+# the average interrupt handling will be. The collection -+# size represents the number of bytes of the per-CPU memory -+# used to batch up entropy event data. -+# -+# The default value is good for regular operations. Choose -+# larger sizes for servers that have no memory limitations. -+# If runtime memory is precious, choose a smaller size. -+# -+# The collection size is unrelated to the entropy rate -+# or the amount of entropy the LRNG can process. -+# -+# config LRNG_COLLECTION_SIZE_32 -+# depends on LRNG_CONTINUOUS_COMPRESSION_ENABLED -+# depends on !LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION -+# depends on !CRYPTO_FIPS -+# bool "32 interrupt events" -+# -+# config LRNG_COLLECTION_SIZE_256 -+# depends on !CRYPTO_FIPS -+# bool "256 interrupt events" -+# -+# config LRNG_COLLECTION_SIZE_512 -+# bool "512 interrupt events" -+# -+# config LRNG_COLLECTION_SIZE_1024 -+# bool "1024 interrupt events (default)" -+# -+# config LRNG_COLLECTION_SIZE_2048 -+# bool "2048 interrupt events" -+# -+# config LRNG_COLLECTION_SIZE_4096 -+# bool "4096 interrupt events" -+# -+# config LRNG_COLLECTION_SIZE_8192 -+# bool "8192 interrupt events" -+# -+# endchoice -+# -+# config LRNG_COLLECTION_SIZE -+# int -+# default 32 if LRNG_COLLECTION_SIZE_32 -+# default 256 if LRNG_COLLECTION_SIZE_256 -+# default 512 if LRNG_COLLECTION_SIZE_512 -+# default 1024 if LRNG_COLLECTION_SIZE_1024 -+# default 2048 if LRNG_COLLECTION_SIZE_2048 -+# default 4096 if LRNG_COLLECTION_SIZE_4096 -+# default 8192 if LRNG_COLLECTION_SIZE_8192 -+# -+# config LRNG_HEALTH_TESTS -+# bool "Enable internal entropy source online health tests" -+# depends on LRNG_TIMER_COMMON -+# help -+# The online health tests applied to the interrupt entropy -+# source and to the scheduler entropy source to validate -+# the noise source at runtime for fatal errors. These tests -+# include SP800-90B compliant tests which are invoked if -+# the system is booted with fips=1. In case of fatal errors -+# during active SP800-90B tests, the issue is logged and -+# the noise data is discarded. These tests are required for -+# full compliance of the interrupt entropy source with -+# SP800-90B. -+# -+# If both, the scheduler and the interrupt entropy sources, -+# are enabled, the health tests for both are applied -+# independent of each other. -+# -+# If unsure, say Y. -+# -+# config LRNG_RCT_BROKEN -+# bool "SP800-90B RCT with dangerous low cutoff value" -+# depends on LRNG_HEALTH_TESTS -+# depends on BROKEN -+# default n -+# help -+# This option enables a dangerously low SP800-90B repetitive -+# count test (RCT) cutoff value which makes it very likely -+# that the RCT is triggered to raise a self test failure. -+# -+# This option is ONLY intended for developers wanting to -+# test the effectiveness of the SP800-90B RCT health test. -+# -+# If unsure, say N. -+# -+# config LRNG_APT_BROKEN -+# bool "SP800-90B APT with dangerous low cutoff value" -+# depends on LRNG_HEALTH_TESTS -+# depends on BROKEN -+# default n -+# help -+# This option enables a dangerously low SP800-90B adaptive -+# proportion test (APT) cutoff value which makes it very -+# likely that the APT is triggered to raise a self test -+# failure. -+# -+# This option is ONLY intended for developers wanting to -+# test the effectiveness of the SP800-90B APT health test. -+# -+# If unsure, say N. -+# -+# Default taken from SP800-90B sec 4.4.1 - significance level 2^-30 -+# config LRNG_RCT_CUTOFF -+# int -+# default 31 if !LRNG_RCT_BROKEN -+# default 1 if LRNG_RCT_BROKEN -+# -+# Default taken from SP800-90B sec 4.4.1 - significance level 2^-80 -+# config LRNG_RCT_CUTOFF_PERMANENT -+# int -+# default 81 if !LRNG_RCT_BROKEN -+# default 2 if LRNG_RCT_BROKEN -+# -+# Default taken from SP800-90B sec 4.4.2 - significance level 2^-30 -+# config LRNG_APT_CUTOFF -+# int -+# default 325 if !LRNG_APT_BROKEN -+# default 32 if LRNG_APT_BROKEN -+# -+# Default taken from SP800-90B sec 4.4.2 - significance level 2^-80 -+# config LRNG_APT_CUTOFF_PERMANENT -+# int -+# default 371 if !LRNG_APT_BROKEN -+# default 33 if LRNG_APT_BROKEN -+# -+# comment "Interrupt Entropy Source" -+# -+# config LRNG_IRQ -+# bool "Enable Interrupt Entropy Source as LRNG Seed Source" -+# default y -+# depends on !RANDOM_DEFAULT_IMPL -+# select LRNG_TIMER_COMMON -+# help -+# The LRNG models an entropy source based on the timing of the -+# occurrence of interrupts. Enable this option to enable this -+# IRQ entropy source. -+# -+# The IRQ entropy source is triggered every time an interrupt -+# arrives and thus causes the interrupt handler to execute -+# slightly longer. Disabling the IRQ entropy source implies -+# that the performance penalty on the interrupt handler added -+# by the LRNG is eliminated. Yet, this entropy source is -+# considered to be an internal entropy source of the LRNG. -+# Thus, only disable it if you ensured that other entropy -+# sources are available that supply the LRNG with entropy. -+# -+# If you disable the IRQ entropy source, you MUST ensure -+# one or more entropy sources collectively have the -+# capability to deliver sufficient entropy with one invocation -+# at a rate compliant to the security strength of the DRNG -+# (usually 256 bits of entropy). In addition, if those -+# entropy sources do not deliver sufficient entropy during -+# first request, the reseed must be triggered from user -+# space or kernel space when sufficient entropy is considered -+# to be present. -+# -+# If unsure, say Y. -+# -+# choice -+# prompt "Continuous entropy compression boot time setting" -+# default LRNG_CONTINUOUS_COMPRESSION_ENABLED -+# depends on LRNG_IRQ -+# help -+# Select the default behavior of the interrupt entropy source -+# continuous compression operation. -+# -+# The LRNG IRQ ES collects entropy data during each interrupt. -+# For performance reasons, a amount of entropy data defined by -+# the LRNG entropy collection pool size is concatenated into -+# an array. When that array is filled up, a hash is calculated -+# to compress the entropy. That hash is calculated in -+# interrupt context. -+# -+# In case such hash calculation in interrupt context is deemed -+# too time-consuming, the continuous compression operation -+# can be disabled. If disabled, the collection of entropy will -+# not trigger a hash compression operation in interrupt context. -+# The compression happens only when the DRNG is reseeded which is -+# in process context. This implies that old entropy data -+# collected after the last DRNG-reseed is overwritten with newer -+# entropy data once the collection pool is full instead of -+# retaining its entropy with the compression operation. -+# -+# config LRNG_CONTINUOUS_COMPRESSION_ENABLED -+# bool "Enable continuous compression (default)" -+# -+# config LRNG_CONTINUOUS_COMPRESSION_DISABLED -+# bool "Disable continuous compression" -+# -+# endchoice -+# -+# config LRNG_ENABLE_CONTINUOUS_COMPRESSION -+# bool -+# default y if LRNG_CONTINUOUS_COMPRESSION_ENABLED -+# default n if LRNG_CONTINUOUS_COMPRESSION_DISABLED -+# -+# config LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION -+# bool "Runtime-switchable continuous entropy compression" -+# depends on LRNG_IRQ -+# help -+# Per default, the interrupt entropy source continuous -+# compression operation behavior is hard-wired into the kernel. -+# Enable this option to allow it to be configurable at boot time. -+# -+# To modify the default behavior of the continuous -+# compression operation, use the kernel command line option -+# of lrng_sw_noise.lrng_pcpu_continuous_compression. -+# -+# If unsure, say N. -+# -+# config LRNG_IRQ_ENTROPY_RATE -+# int "Interrupt Entropy Source Entropy Rate" -+# depends on LRNG_IRQ -+# range 256 4294967295 if LRNG_IRQ_DFLT_TIMER_ES -+# range 4294967295 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES -+# default 256 if LRNG_IRQ_DFLT_TIMER_ES -+# default 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES -+# help -+# The LRNG will collect the configured number of interrupts to -+# obtain 256 bits of entropy. This value can be set to any between -+# 256 and 4294967295. The LRNG guarantees that this value is not -+# lower than 256. This lower limit implies that one interrupt event -+# is credited with one bit of entropy. This value is subject to the -+# increase by the oversampling factor, if no high-resolution timer -+# is found. -+# -+# In order to effectively disable the interrupt entropy source, -+# the option has to be set to 4294967295. In this case, the -+# interrupt entropy source will still deliver data but without -+# being credited with entropy. -+# -+# comment "Jitter RNG Entropy Source" -+# -+# config LRNG_JENT -+# bool "Enable Jitter RNG as LRNG Seed Source" -+# depends on CRYPTO -+# select CRYPTO_JITTERENTROPY -+# help -+# The LRNG may use the Jitter RNG as entropy source. Enabling -+# this option enables the use of the Jitter RNG. Its default -+# entropy level is 16 bits of entropy per 256 data bits delivered -+# by the Jitter RNG. This entropy level can be changed at boot -+# time or at runtime with the lrng_base.jitterrng configuration -+# variable. -+# -+#choice -+# prompt "Jitter RNG Async Block Number" -+# default LRNG_JENT_ENTROPY_BLOCKS_NO_128 -+# depends on LRNG_JENT -+# help -+# Select the number of Jitter RNG entropy blocks the asynchronous -+# collection operation will fill. A caller for Jitter RNG entropy -+# will be given data from the pre-filled blocks if available to -+# prevent the Jitter RNG from utilizing the CPU too much in a -+# possible hot code path. -+# -+# The number specifies the number of 256/384 bit blocks that will -+# be held in memory and asynchronously filled with Jitter RNG data. -+# -+# The asynchronous entropy collection can also be disabled at -+# kernel startup time when setting the command line option of -+# lrng_es_jent.jent_async_enabled=0. Also, setting this option at -+# runtime is allowed via the corresponding SysFS interface. This -+# option is only available with the options SysFS and -+# CONFIG_LRNG_RUNTIME_ES_CONFIG enabled. -+# -+# config LRNG_JENT_ENTROPY_BLOCKS_DISABLED -+# bool "Async collection disabled" -+# -+# # Any block number is allowed, provided it is a power of 2 and -+# # equal or larger than 4 (4 is due to the division in -+# # lrng_jent_async_get when deciding to wake up the monitor). -+# config LRNG_JENT_ENTROPY_BLOCKS_NO_32 -+# bool "32 blocks" -+# -+# config LRNG_JENT_ENTROPY_BLOCKS_NO_64 -+# bool "64 blocks" -+# -+# config LRNG_JENT_ENTROPY_BLOCKS_NO_128 -+# bool "128 blocks (default)" -+# -+# config LRNG_JENT_ENTROPY_BLOCKS_NO_256 -+# bool "256 blocks" -+# -+# config LRNG_JENT_ENTROPY_BLOCKS_NO_512 -+# bool "512 blocks" -+# -+# config LRNG_JENT_ENTROPY_BLOCKS_NO_1024 -+# bool "1024 blocks" -+# -+#endchoice -+# -+#config LRNG_JENT_ENTROPY_BLOCKS -+# int -+# default 0 if LRNG_JENT_ENTROPY_BLOCKS_DISABLED -+# default 32 if LRNG_JENT_ENTROPY_BLOCKS_NO_32 -+# default 64 if LRNG_JENT_ENTROPY_BLOCKS_NO_64 -+# default 128 if LRNG_JENT_ENTROPY_BLOCKS_NO_128 -+# default 256 if LRNG_JENT_ENTROPY_BLOCKS_NO_256 -+# default 512 if LRNG_JENT_ENTROPY_BLOCKS_NO_512 -+# default 1024 if LRNG_JENT_ENTROPY_BLOCKS_NO_1024 -+# -+# config LRNG_JENT_ENTROPY_RATE -+# int "Jitter RNG Entropy Source Entropy Rate" -+# depends on LRNG_JENT -+# range 0 256 -+# default 16 -+# help -+# The option defines the amount of entropy the LRNG applies to 256 -+# bits of data obtained from the Jitter RNG entropy source. The -+# LRNG enforces the limit that this value must be in the range -+# between 0 and 256. -+# -+# When configuring this value to 0, the Jitter RNG entropy source -+# will provide 256 bits of data without being credited to contain -+# entropy. -+# -+# comment "CPU Entropy Source" -+# -+# config LRNG_CPU -+# bool "Enable CPU Entropy Source as LRNG Seed Source" -+# default y -+# help -+# Current CPUs commonly contain entropy sources which can be -+# used to seed the LRNG. For example, the Intel RDSEED -+# instruction, or the POWER DARN instruction will be sourced -+# to seed the LRNG if this option is enabled. -+# -+# Note, if this option is enabled and the underlying CPU -+# does not offer such entropy source, the LRNG will automatically -+# detect this and ignore the hardware. -+# -+# config LRNG_CPU_FULL_ENT_MULTIPLIER -+# int -+# default 1 if !LRNG_TEST_CPU_ES_COMPRESSION -+# default 123 if LRNG_TEST_CPU_ES_COMPRESSION -+# -+# config LRNG_CPU_ENTROPY_RATE -+# int "CPU Entropy Source Entropy Rate" -+# depends on LRNG_CPU -+# range 0 256 -+# default 8 -+# help -+# The option defines the amount of entropy the LRNG applies to 256 -+# bits of data obtained from the CPU entropy source. The LRNG -+# enforces the limit that this value must be in the range between -+# 0 and 256. -+# -+# When configuring this value to 0, the CPU entropy source will -+# provide 256 bits of data without being credited to contain -+# entropy. -+# -+# Note, this option is overwritten when the option -+# CONFIG_RANDOM_TRUST_CPU is set. -+# -+# comment "Scheduler Entropy Source" -+# -+# config LRNG_SCHED -+# bool "Enable Scheduer Entropy Source as LRNG Seed Source" -+# select LRNG_TIMER_COMMON -+# help -+# The LRNG models an entropy source based on the timing of the -+# occurrence of scheduler-triggered context switches. Enable -+# this option to enable this scheduler entropy source. -+# -+# The scheduler entropy source is triggered every time a -+# context switch is triggered thus causes the scheduler to -+# execute slightly longer. Disabling the scheduler entropy -+# source implies that the performance penalty on the scheduler -+# added by the LRNG is eliminated. Yet, this entropy source is -+# considered to be an internal entropy source of the LRNG. -+# Thus, only disable it if you ensured that other entropy -+# sources are available that supply the LRNG with entropy. -+# -+# If you disable the scheduler entropy source, you MUST -+# ensure one or more entropy sources collectively have the -+# capability to deliver sufficient entropy with one invocation -+# at a rate compliant to the security strength of the DRNG -+# (usually 256 bits of entropy). In addition, if those -+# entropy sources do not deliver sufficient entropy during -+# first request, the reseed must be triggered from user -+# space or kernel space when sufficient entropy is considered -+# to be present. -+# -+# If unsure, say Y. -+# -+# config LRNG_SCHED_ENTROPY_RATE -+# int "Scheduler Entropy Source Entropy Rate" -+# depends on LRNG_SCHED -+# range 256 4294967295 if LRNG_SCHED_DFLT_TIMER_ES -+# range 4294967295 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES -+# default 256 if LRNG_SCHED_DFLT_TIMER_ES -+# default 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES -+# help -+# The LRNG will collect the configured number of context switches -+# triggered by the scheduler to obtain 256 bits of entropy. This -+# value can be set to any between 256 and 4294967295. The LRNG -+# guarantees that this value is not lower than 256. This lower -+# limit implies that one interrupt event is credited with one bit -+# of entropy. This value is subject to the increase by the -+# oversampling factor, if no high-resolution timer is found. -+# -+# In order to effectively disable the scheduler entropy source, -+# the option has to be set to 4294967295. In this case, the -+# scheduler entropy source will still deliver data but without -+# being credited with entropy. -+# -+# comment "Kernel RNG Entropy Source" -+# -+# config LRNG_KERNEL_RNG -+# bool "Enable Kernel RNG as LRNG Seed Source" -+# depends on RANDOM_DEFAULT_IMPL -+# help -+# The LRNG may use the kernel RNG (random.c) as entropy -+# source. -+# -+# config LRNG_KERNEL_RNG_ENTROPY_RATE -+# int "Kernel RNG Entropy Source Entropy Rate" -+# depends on LRNG_KERNEL_RNG -+# range 0 256 -+# default 256 -+# help -+# The option defines the amount of entropy the LRNG applies to 256 -+# bits of data obtained from the kernel RNG entropy source. The -+# LRNG enforces the limit that this value must be in the range -+# between 0 and 256. -+# -+# When configuring this value to 0, the kernel RNG entropy source -+# will provide 256 bits of data without being credited to contain -+# entropy. -+# -+# Note: This value is set to 0 automatically when booting the -+# kernel in FIPS mode (with fips=1 kernel command line option). -+# This is due to the fact that random.c is not SP800-90B -+# compliant. -+# -+# endmenu # "Entropy Source Configuration" -+ -+config LRNG_DRNG_CHACHA20 -+ tristate -+ -+# config LRNG_DRBG -+# tristate -+# depends on CRYPTO -+# select CRYPTO_DRBG_MENU -+# -+# config LRNG_DRNG_KCAPI -+# tristate -+# depends on CRYPTO -+# select CRYPTO_RNG -+# -+# config LRNG_SWITCH -+# bool -+# -+# menuconfig LRNG_SWITCH_HASH -+# bool "Support conditioning hash runtime switching" -+# select LRNG_SWITCH -+# help -+# The LRNG uses a default message digest. With this -+# configuration option other message digests can be selected -+# and loaded at runtime. -+# -+# if LRNG_SWITCH_HASH -+# -+# config LRNG_HASH_KCAPI -+# tristate "Kernel crypto API hashing support for LRNG" -+# select CRYPTO_HASH -+# select CRYPTO_SHA512 -+# help -+# Enable the kernel crypto API support for entropy compression -+# and conditioning functions. -+# -+# endif # LRNG_SWITCH_HASH -+# -+# menuconfig LRNG_SWITCH_DRNG -+# bool "Support DRNG runtime switching" -+# select LRNG_SWITCH -+# help -+# The LRNG uses a default DRNG With this configuration -+# option other DRNGs or message digests can be selected and -+# loaded at runtime. -+# -+# if LRNG_SWITCH_DRNG -+# -+# config LRNG_SWITCH_DRNG_CHACHA20 -+# tristate "ChaCha20-based DRNG support for LRNG" -+# depends on !LRNG_DFLT_DRNG_CHACHA20 -+# select LRNG_DRNG_CHACHA20 -+# help -+# Enable the ChaCha20-based DRNG. This DRNG implementation -+# does not depend on the kernel crypto API presence. -+# -+# config LRNG_SWITCH_DRBG -+# tristate "SP800-90A support for the LRNG" -+# depends on !LRNG_DFLT_DRNG_DRBG -+# select LRNG_DRBG -+# help -+# Enable the SP800-90A DRBG support for the LRNG. Once the -+# module is loaded, output from /dev/random, /dev/urandom, -+# getrandom(2), or get_random_bytes_full is provided by a DRBG. -+# -+# config LRNG_SWITCH_DRNG_KCAPI -+# tristate "Kernel Crypto API support for the LRNG" -+# depends on !LRNG_DFLT_DRNG_KCAPI -+# depends on !LRNG_SWITCH_DRBG -+# select LRNG_DRNG_KCAPI -+# help -+# Enable the support for generic pseudo-random number -+# generators offered by the kernel crypto API with the -+# LRNG. Once the module is loaded, output from /dev/random, -+# /dev/urandom, getrandom(2), or get_random_bytes is -+# provided by the selected kernel crypto API RNG. -+# -+# endif # LRNG_SWITCH_DRNG -+ -+choice -+ prompt "LRNG Default DRNG" -+ default LRNG_DFLT_DRNG_CHACHA20 -+ help -+ Select the default deterministic random number generator -+ that is used by the LRNG. When enabling the switchable -+ cryptographic mechanism support, this DRNG can be -+ replaced at runtime. -+ -+ config LRNG_DFLT_DRNG_CHACHA20 -+ bool "ChaCha20-based DRNG" -+ select LRNG_DRNG_CHACHA20 -+ -+# config LRNG_DFLT_DRNG_DRBG -+# depends on RANDOM_DEFAULT_IMPL -+# bool "SP800-90A DRBG" -+# select LRNG_DRBG -+# -+# config LRNG_DFLT_DRNG_KCAPI -+# depends on RANDOM_DEFAULT_IMPL -+# bool "Kernel Crypto API DRNG" -+# select LRNG_DRNG_KCAPI -+endchoice -+ -+# menuconfig LRNG_TESTING_MENU -+# bool "LRNG testing interfaces" -+# depends on DEBUG_FS -+# help -+# Enable one or more of the following test interfaces. -+# -+# If unsure, say N. -+# -+# if LRNG_TESTING_MENU -+# -+# config LRNG_TESTING -+# bool -+# -+# config LRNG_TESTING_RECORDING -+# bool -+# -+# comment "Interrupt Entropy Source Test Interfaces" -+# -+# config LRNG_RAW_HIRES_ENTROPY -+# bool "Interface to obtain raw unprocessed IRQ noise source data" -+# default y -+# depends on LRNG_IRQ -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned high resolution time stamp noise that -+# is collected by the LRNG for statistical analysis. Extracted -+# noise data is not used to seed the LRNG. -+# -+# The raw noise data can be obtained using the lrng_raw_hires -+# debugfs file. Using the option lrng_testing.boot_raw_hires_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_RAW_JIFFIES_ENTROPY -+# bool "Entropy test interface to Jiffies of IRQ noise source" -+# depends on LRNG_IRQ -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned Jiffies that is collected by -+# the LRNG for statistical analysis. This data is used for -+# seeding the LRNG if a high-resolution time stamp is not -+# available. If a high-resolution time stamp is detected, -+# the Jiffies value is not collected by the LRNG and no -+# data is provided via the test interface. Extracted noise -+# data is not used to seed the random number generator. -+# -+# The raw noise data can be obtained using the lrng_raw_jiffies -+# debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_RAW_IRQ_ENTROPY -+# bool "Entropy test interface to IRQ number noise source" -+# depends on LRNG_IRQ -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned interrupt number that is collected by -+# the LRNG for statistical analysis. Extracted noise data is -+# not used to seed the random number generator. -+# -+# The raw noise data can be obtained using the lrng_raw_irq -+# debugfs file. Using the option lrng_testing.boot_raw_irq_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_RAW_RETIP_ENTROPY -+# bool "Entropy test interface to RETIP value of IRQ noise source" -+# depends on LRNG_IRQ -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned return instruction pointer value -+# that is collected by the LRNG for statistical analysis. -+# Extracted noise data is not used to seed the random number -+# generator. -+# -+# The raw noise data can be obtained using the lrng_raw_retip -+# debugfs file. Using the option lrng_testing.boot_raw_retip_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_RAW_REGS_ENTROPY -+# bool "Entropy test interface to IRQ register value noise source" -+# depends on LRNG_IRQ -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned interrupt register value that is -+# collected by the LRNG for statistical analysis. Extracted noise -+# data is not used to seed the random number generator. -+# -+# The raw noise data can be obtained using the lrng_raw_regs -+# debugfs file. Using the option lrng_testing.boot_raw_regs_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_RAW_ARRAY -+# bool "Test interface to LRNG raw entropy IRQ storage array" -+# depends on LRNG_IRQ -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw noise data that is collected by the LRNG -+# in the per-CPU array for statistical analysis. The purpose -+# of this interface is to verify that the array handling code -+# truly only concatenates data and provides the same entropy -+# rate as the raw unconditioned noise source when assessing -+# the collected data byte-wise. -+# -+# The data can be obtained using the lrng_raw_array debugfs -+# file. Using the option lrng_testing.boot_raw_array=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_IRQ_PERF -+# bool "LRNG interrupt entropy source performance monitor" -+# depends on LRNG_IRQ -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# With this option, the performance monitor of the LRNG -+# interrupt handling code is enabled. The file provides -+# the execution time of the interrupt handler in -+# cycles. -+# -+# The interrupt performance data can be obtained using -+# the lrng_irq_perf debugfs file. Using the option -+# lrng_testing.boot_irq_perf=1 the performance data of -+# the first 1000 entropy events since boot can be sampled. -+# -+# comment "Scheduler Entropy Source Test Interfaces" -+# -+# config LRNG_RAW_SCHED_HIRES_ENTROPY -+# bool "Interface to obtain raw unprocessed scheduler noise source data" -+# depends on LRNG_SCHED -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned high resolution time stamp noise that -+# is collected by the LRNG for the Scheduler-based noise source -+# for statistical analysis. Extracted noise data is not used to -+# seed the LRNG. -+# -+# The raw noise data can be obtained using the lrng_raw_sched_hires -+# debugfs file. Using the option -+# lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the -+# first 1000 entropy events since boot can be sampled. -+# -+# config LRNG_RAW_SCHED_PID_ENTROPY -+# bool "Entropy test interface to PID value" -+# depends on LRNG_SCHED -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned PID value that is collected by the -+# LRNG for statistical analysis. Extracted noise -+# data is not used to seed the random number generator. -+# -+# The raw noise data can be obtained using the -+# lrng_raw_sched_pid debugfs file. Using the option -+# lrng_testing.boot_raw_sched_pid_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_RAW_SCHED_START_TIME_ENTROPY -+# bool "Entropy test interface to task start time value" -+# depends on LRNG_SCHED -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned task start time value that is collected -+# by the LRNG for statistical analysis. Extracted noise -+# data is not used to seed the random number generator. -+# -+# The raw noise data can be obtained using the -+# lrng_raw_sched_starttime debugfs file. Using the option -+# lrng_testing.boot_raw_sched_starttime_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# -+# config LRNG_RAW_SCHED_NVCSW_ENTROPY -+# bool "Entropy test interface to task context switch numbers" -+# depends on LRNG_SCHED -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# The test interface allows a privileged process to capture -+# the raw unconditioned task numbers of context switches that -+# are collected by the LRNG for statistical analysis. Extracted -+# noise data is not used to seed the random number generator. -+# -+# The raw noise data can be obtained using the -+# lrng_raw_sched_nvcsw debugfs file. Using the option -+# lrng_testing.boot_raw_sched_nvcsw_test=1 -+# the raw noise of the first 1000 entropy events since boot -+# can be sampled. -+# -+# config LRNG_SCHED_PERF -+# bool "LRNG scheduler entropy source performance monitor" -+# depends on LRNG_SCHED -+# select LRNG_TESTING -+# select LRNG_TESTING_RECORDING -+# help -+# With this option, the performance monitor of the LRNG -+# scheduler event handling code is enabled. The file provides -+# the execution time of the interrupt handler in cycles. -+# -+# The scheduler performance data can be obtained using -+# the lrng_sched_perf debugfs file. Using the option -+# lrng_testing.boot_sched_perf=1 the performance data of -+# the first 1000 entropy events since boot can be sampled. -+# -+# comment "Auxiliary Test Interfaces" -+# -+# config LRNG_ACVT_HASH -+# bool "Enable LRNG ACVT Hash interface" -+# select LRNG_TESTING -+# help -+# With this option, the LRNG built-in hash function used for -+# auxiliary pool management and prior to switching the -+# cryptographic backends is made available for ACVT. The -+# interface allows writing of the data to be hashed -+# into the interface. The read operation triggers the hash -+# operation to generate message digest. -+# -+# The ACVT interface is available with the lrng_acvt_hash -+# debugfs file. -+# -+# config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG -+# bool "Enable runtime configuration of max reseed threshold" -+# help -+# When enabling this option, the LRNG provides an interface -+# allowing the setting of the maximum number of DRNG generate -+# operations without a reseed that has full entropy. The -+# interface is lrng_drng.max_wo_reseed. -+# -+#config LRNG_RUNTIME_FORCE_SEEDING_DISABLE -+# bool "Enable runtime configuration of force seeding" -+# help -+# When enabling this option, the LRNG provides an interface -+# allowing the disabling of the force seeding when the DRNG -+# is not fully seeded but entropy is available. -+# -+# config LRNG_TEST_CPU_ES_COMPRESSION -+# bool "Force CPU ES compression operation" -+# help -+# When enabling this option, the CPU ES compression operation -+# is forced by setting an arbitrary value > 1 for the data -+# multiplier even when the CPU ES would deliver full entropy. -+# This allows testing of the compression operation. It -+# therefore forces to pull more data from the CPU ES -+# than what may be required. -+# -+# endif #LRNG_TESTING_MENU -+# -+# config LRNG_SELFTEST -+# bool "Enable power-on and on-demand self-tests" -+# help -+# The power-on self-tests are executed during boot time -+# covering the ChaCha20 DRNG, the hash operation used for -+# processing the entropy pools and the auxiliary pool, and -+# the time stamp management of the LRNG. -+# -+# The on-demand self-tests are triggered by writing any -+# value into the SysFS file selftest_status. At the same -+# time, when reading this file, the test status is -+# returned. A zero indicates that all tests were executed -+# successfully. -+# -+# If unsure, say Y. -+# -+# if LRNG_SELFTEST -+# -+# config LRNG_SELFTEST_PANIC -+# bool "Panic the kernel upon self-test failure" -+# help -+# If the option is enabled, the kernel is terminated if an -+# LRNG power-on self-test failure is detected. -+# -+# endif # LRNG_SELFTEST -+ -+endif # LRNG -+ -+endmenu # LRNG ---- /dev/null -+++ b/drivers/char/lrng/Makefile -@@ -0,0 +1,11 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# Makefile for the Entropy Source and DRNG Manager. -+# -+ -+obj-y += lrng_es_mgr.o lrng_drng_mgr.o \ -+ lrng_es_aux.o -+obj-$(CONFIG_LRNG_SHA256) += lrng_sha256.o -+obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o -+ -+obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_definitions.h -@@ -0,0 +1,163 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022 - 2023, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_DEFINITIONS_H -+#define _LRNG_DEFINITIONS_H -+ -+#include -+#include -+#include -+ -+/*************************** General LRNG parameter ***************************/ -+ -+/* -+ * Specific settings for different use cases -+ */ -+#ifdef CONFIG_CRYPTO_FIPS -+# define LRNG_OVERSAMPLE_ES_BITS 64 -+# define LRNG_SEED_BUFFER_INIT_ADD_BITS 128 -+#else /* CONFIG_CRYPTO_FIPS */ -+# define LRNG_OVERSAMPLE_ES_BITS 0 -+# define LRNG_SEED_BUFFER_INIT_ADD_BITS 0 -+#endif /* CONFIG_CRYPTO_FIPS */ -+ -+/* Security strength of LRNG -- this must match DRNG security strength */ -+#define LRNG_DRNG_SECURITY_STRENGTH_BYTES 32 -+#define LRNG_DRNG_SECURITY_STRENGTH_BITS (LRNG_DRNG_SECURITY_STRENGTH_BYTES * 8) -+#define LRNG_DRNG_INIT_SEED_SIZE_BITS \ -+ (LRNG_DRNG_SECURITY_STRENGTH_BITS + LRNG_SEED_BUFFER_INIT_ADD_BITS) -+#define LRNG_DRNG_INIT_SEED_SIZE_BYTES (LRNG_DRNG_INIT_SEED_SIZE_BITS >> 3) -+ -+/* -+ * SP800-90A defines a maximum request size of 1<<16 bytes. The given value is -+ * considered a safer margin. -+ * -+ * This value is allowed to be changed. -+ */ -+#define LRNG_DRNG_MAX_REQSIZE (1<<12) -+ -+/* -+ * SP800-90A defines a maximum number of requests between reseeds of 2^48. -+ * The given value is considered a much safer margin, balancing requests for -+ * frequent reseeds with the need to conserve entropy. This value MUST NOT be -+ * larger than INT_MAX because it is used in an atomic_t. -+ * -+ * This value is allowed to be changed. -+ */ -+#define LRNG_DRNG_RESEED_THRESH (1<<20) -+ -+/* -+ * Maximum DRNG generation operations without reseed having full entropy -+ * This value defines the absolute maximum value of DRNG generation operations -+ * without a reseed holding full entropy. LRNG_DRNG_RESEED_THRESH is the -+ * threshold when a new reseed is attempted. But it is possible that this fails -+ * to deliver full entropy. In this case the DRNG will continue to provide data -+ * even though it was not reseeded with full entropy. To avoid in the extreme -+ * case that no reseed is performed for too long, this threshold is enforced. -+ * If that absolute low value is reached, the LRNG is marked as not operational. -+ * -+ * This value is allowed to be changed. -+ */ -+#define LRNG_DRNG_MAX_WITHOUT_RESEED (1<<30) -+ -+/* -+ * Min required seed entropy is 128 bits covering the minimum entropy -+ * requirement of SP800-131A and the German BSI's TR02102. -+ * -+ * This value is allowed to be changed. -+ */ -+#define LRNG_FULL_SEED_ENTROPY_BITS LRNG_DRNG_SECURITY_STRENGTH_BITS -+#define LRNG_MIN_SEED_ENTROPY_BITS 128 -+#define LRNG_INIT_ENTROPY_BITS 32 -+ -+/* AIS20/31: NTG.1.4 minimum entropy rate for one entropy source*/ -+#define LRNG_AIS2031_NPTRNG_MIN_ENTROPY 220 -+ -+/* -+ * Wakeup value -+ * -+ * This value is allowed to be changed but must not be larger than the -+ * digest size of the hash operation used update the aux_pool. -+ */ -+#ifdef CONFIG_LRNG_SHA256 -+# define LRNG_ATOMIC_DIGEST_SIZE SHA256_DIGEST_SIZE -+#else -+# define LRNG_ATOMIC_DIGEST_SIZE SHA1_DIGEST_SIZE -+#endif -+#define LRNG_WRITE_WAKEUP_ENTROPY LRNG_ATOMIC_DIGEST_SIZE -+ -+/* -+ * If the switching support is configured, we must provide support up to -+ * the largest digest size. Without switching support, we know it is only -+ * the built-in digest size. -+ */ -+#ifdef CONFIG_LRNG_SWITCH -+# define LRNG_MAX_DIGESTSIZE 64 -+#else -+# define LRNG_MAX_DIGESTSIZE LRNG_ATOMIC_DIGEST_SIZE -+#endif -+ -+/* -+ * Oversampling factor of timer-based events to obtain -+ * LRNG_DRNG_SECURITY_STRENGTH_BYTES. This factor is used when a -+ * high-resolution time stamp is not available. In this case, jiffies and -+ * register contents are used to fill the entropy pool. These noise sources -+ * are much less entropic than the high-resolution timer. The entropy content -+ * is the entropy content assumed with LRNG_[IRQ|SCHED]_ENTROPY_BITS divided by -+ * LRNG_ES_OVERSAMPLING_FACTOR. -+ * -+ * This value is allowed to be changed. -+ */ -+#define LRNG_ES_OVERSAMPLING_FACTOR 10 -+ -+/* Alignmask that is intended to be identical to CRYPTO_MINALIGN */ -+#define LRNG_KCAPI_ALIGN ARCH_KMALLOC_MINALIGN -+ -+/* -+ * This definition must provide a buffer that is equal to SHASH_DESC_ON_STACK -+ * as it will be casted into a struct shash_desc. -+ */ -+#define LRNG_POOL_SIZE (sizeof(struct shash_desc) + HASH_MAX_DESCSIZE) -+ -+/* -+ * Identification of a permanent health falure. -+ * -+ * Allow the given number of back-to-back health failures until incuring a -+ * permanent health failure. The chosen value implies an alpha of 2^-60 -+ * considering that the alpha of one health failure is 2^-30 -+ */ -+#define LRNG_PERMANENT_HEALTH_FAILURES 2 -+ -+/****************************** Helper code ***********************************/ -+ -+static inline u32 lrng_fast_noise_entropylevel(u32 ent_bits, u32 requested_bits) -+{ -+ /* Obtain entropy statement */ -+ ent_bits = ent_bits * requested_bits / LRNG_DRNG_SECURITY_STRENGTH_BITS; -+ /* Cap entropy to buffer size in bits */ -+ ent_bits = min_t(u32, ent_bits, requested_bits); -+ return ent_bits; -+} -+ -+/* Convert entropy in bits into nr. of events with the same entropy content. */ -+static inline u32 lrng_entropy_to_data(u32 entropy_bits, u32 entropy_rate) -+{ -+ return ((entropy_bits * entropy_rate) / -+ LRNG_DRNG_SECURITY_STRENGTH_BITS); -+} -+ -+/* Convert number of events into entropy value. */ -+static inline u32 lrng_data_to_entropy(u32 num, u32 entropy_rate) -+{ -+ return ((num * LRNG_DRNG_SECURITY_STRENGTH_BITS) / -+ entropy_rate); -+} -+ -+static inline u32 atomic_read_u32(atomic_t *v) -+{ -+ return (u32)atomic_read(v); -+} -+ -+#endif /* _LRNG_DEFINITIONS_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_atomic.h -@@ -0,0 +1,23 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_DRNG_ATOMIC_H -+#define _LRNG_DRNG_ATOMIC_H -+ -+#include "lrng_drng_mgr.h" -+ -+#ifdef CONFIG_LRNG_DRNG_ATOMIC -+void lrng_drng_atomic_reset(void); -+void lrng_drng_atomic_seed_drng(struct lrng_drng *drng); -+void lrng_drng_atomic_force_reseed(void); -+struct lrng_drng *lrng_get_atomic(void); -+#else /* CONFIG_LRNG_DRNG_ATOMIC */ -+static inline void lrng_drng_atomic_reset(void) { } -+static inline void lrng_drng_atomic_seed_drng(struct lrng_drng *drng) { } -+static inline void lrng_drng_atomic_force_reseed(void) { } -+static inline struct lrng_drng *lrng_get_atomic(void) { return NULL; } -+#endif /* CONFIG_LRNG_DRNG_ATOMIC */ -+ -+#endif /* _LRNG_DRNG_ATOMIC_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_chacha20.c -@@ -0,0 +1,195 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * Backend for the LRNG providing the cryptographic primitives using -+ * ChaCha20 cipher implementations. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+ -+#include "lrng_drng_chacha20.h" -+ -+/******************************* ChaCha20 DRNG *******************************/ -+ -+#define CHACHA_BLOCK_WORDS (CHACHA_BLOCK_SIZE / sizeof(u32)) -+ -+/* -+ * Update of the ChaCha20 state by either using an unused buffer part or by -+ * generating one ChaCha20 block which is half of the state of the ChaCha20. -+ * The block is XORed into the key part of the state. This shall ensure -+ * backtracking resistance as well as a proper mix of the ChaCha20 state once -+ * the key is injected. -+ */ -+static void lrng_chacha20_update(struct chacha20_state *chacha20_state, -+ __le32 *buf, u32 used_words) -+{ -+ struct chacha20_block *chacha20 = &chacha20_state->block; -+ u32 i; -+ __le32 tmp[CHACHA_BLOCK_WORDS]; -+ -+ BUILD_BUG_ON(sizeof(struct chacha20_block) != CHACHA_BLOCK_SIZE); -+ BUILD_BUG_ON(CHACHA_BLOCK_SIZE != 2 * CHACHA_KEY_SIZE); -+ -+ if (used_words > CHACHA_KEY_SIZE_WORDS) { -+ chacha20_block(&chacha20->constants[0], (u8 *)tmp); -+ for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++) -+ chacha20->key.u[i] ^= le32_to_cpu(tmp[i]); -+ memzero_explicit(tmp, sizeof(tmp)); -+ } else { -+ for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++) -+ chacha20->key.u[i] ^= le32_to_cpu(buf[i + used_words]); -+ } -+ -+ /* Deterministic increment of nonce as required in RFC 7539 chapter 4 */ -+ chacha20->nonce[0]++; -+ if (chacha20->nonce[0] == 0) { -+ chacha20->nonce[1]++; -+ if (chacha20->nonce[1] == 0) -+ chacha20->nonce[2]++; -+ } -+ -+ /* Leave counter untouched as it is start value is undefined in RFC */ -+} -+ -+/* -+ * Seed the ChaCha20 DRNG by injecting the input data into the key part of -+ * the ChaCha20 state. If the input data is longer than the ChaCha20 key size, -+ * perform a ChaCha20 operation after processing of key size input data. -+ * This operation shall spread out the entropy into the ChaCha20 state before -+ * new entropy is injected into the key part. -+ */ -+static int lrng_cc20_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen) -+{ -+ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng; -+ struct chacha20_block *chacha20 = &chacha20_state->block; -+ -+ while (inbuflen) { -+ u32 i, todo = min_t(u32, inbuflen, CHACHA_KEY_SIZE); -+ -+ for (i = 0; i < todo; i++) -+ chacha20->key.b[i] ^= inbuf[i]; -+ -+ /* Break potential dependencies between the inbuf key blocks */ -+ lrng_chacha20_update(chacha20_state, NULL, -+ CHACHA_BLOCK_WORDS); -+ inbuf += todo; -+ inbuflen -= todo; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Chacha20 DRNG generation of random numbers: the stream output of ChaCha20 -+ * is the random number. After the completion of the generation of the -+ * stream, the entire ChaCha20 state is updated. -+ * -+ * Note, as the ChaCha20 implements a 32 bit counter, we must ensure -+ * that this function is only invoked for at most 2^32 - 1 ChaCha20 blocks -+ * before a reseed or an update happens. This is ensured by the variable -+ * outbuflen which is a 32 bit integer defining the number of bytes to be -+ * generated by the ChaCha20 DRNG. At the end of this function, an update -+ * operation is invoked which implies that the 32 bit counter will never be -+ * overflown in this implementation. -+ */ -+static int lrng_cc20_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen) -+{ -+ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng; -+ struct chacha20_block *chacha20 = &chacha20_state->block; -+ __le32 aligned_buf[CHACHA_BLOCK_WORDS]; -+ u32 ret = outbuflen, used = CHACHA_BLOCK_WORDS; -+ int zeroize_buf = 0; -+ -+ while (outbuflen >= CHACHA_BLOCK_SIZE) { -+ chacha20_block(&chacha20->constants[0], outbuf); -+ outbuf += CHACHA_BLOCK_SIZE; -+ outbuflen -= CHACHA_BLOCK_SIZE; -+ } -+ -+ if (outbuflen) { -+ chacha20_block(&chacha20->constants[0], (u8 *)aligned_buf); -+ memcpy(outbuf, aligned_buf, outbuflen); -+ used = ((outbuflen + sizeof(aligned_buf[0]) - 1) / -+ sizeof(aligned_buf[0])); -+ zeroize_buf = 1; -+ } -+ -+ lrng_chacha20_update(chacha20_state, aligned_buf, used); -+ -+ if (zeroize_buf) -+ memzero_explicit(aligned_buf, sizeof(aligned_buf)); -+ -+ return ret; -+} -+ -+/* -+ * Allocation of the DRNG state -+ */ -+static void *lrng_cc20_drng_alloc(u32 sec_strength) -+{ -+ struct chacha20_state *state = NULL; -+ -+ if (sec_strength > CHACHA_KEY_SIZE) { -+ pr_err("Security strength of ChaCha20 DRNG (%u bits) lower than requested by LRNG (%u bits)\n", -+ CHACHA_KEY_SIZE * 8, sec_strength * 8); -+ return ERR_PTR(-EINVAL); -+ } -+ if (sec_strength < CHACHA_KEY_SIZE) -+ pr_warn("Security strength of ChaCha20 DRNG (%u bits) higher than requested by LRNG (%u bits)\n", -+ CHACHA_KEY_SIZE * 8, sec_strength * 8); -+ -+ state = kmalloc(sizeof(struct chacha20_state), GFP_KERNEL); -+ if (!state) -+ return ERR_PTR(-ENOMEM); -+ pr_debug("memory for ChaCha20 core allocated\n"); -+ -+ lrng_cc20_init_rfc7539(&state->block); -+ -+ return state; -+} -+ -+static void lrng_cc20_drng_dealloc(void *drng) -+{ -+ struct chacha20_state *chacha20_state = (struct chacha20_state *)drng; -+ -+ pr_debug("ChaCha20 core zeroized and freed\n"); -+ kfree_sensitive(chacha20_state); -+} -+ -+static const char *lrng_cc20_drng_name(void) -+{ -+ return "ChaCha20 DRNG"; -+} -+ -+const struct lrng_drng_cb lrng_cc20_drng_cb = { -+ .drng_name = lrng_cc20_drng_name, -+ .drng_alloc = lrng_cc20_drng_alloc, -+ .drng_dealloc = lrng_cc20_drng_dealloc, -+ .drng_seed = lrng_cc20_drng_seed_helper, -+ .drng_generate = lrng_cc20_drng_generate_helper, -+}; -+ -+#if !defined(CONFIG_LRNG_DFLT_DRNG_CHACHA20) && \ -+ !defined(CONFIG_LRNG_DRNG_ATOMIC) -+static int __init lrng_cc20_drng_init(void) -+{ -+ return lrng_set_drng_cb(&lrng_cc20_drng_cb); -+} -+ -+static void __exit lrng_cc20_drng_exit(void) -+{ -+ lrng_set_drng_cb(NULL); -+} -+ -+late_initcall(lrng_cc20_drng_init); -+module_exit(lrng_cc20_drng_exit); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Stephan Mueller "); -+MODULE_DESCRIPTION("Entropy Source and DRNG Manager - ChaCha20-based DRNG backend"); -+#endif /* CONFIG_LRNG_DFLT_DRNG_CHACHA20 */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_chacha20.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * LRNG ChaCha20 definitions -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_CHACHA20_H -+#define _LRNG_CHACHA20_H -+ -+#include -+ -+/* State according to RFC 7539 section 2.3 */ -+struct chacha20_block { -+ u32 constants[4]; -+ union { -+#define CHACHA_KEY_SIZE_WORDS (CHACHA_KEY_SIZE / sizeof(u32)) -+ u32 u[CHACHA_KEY_SIZE_WORDS]; -+ u8 b[CHACHA_KEY_SIZE]; -+ } key; -+ u32 counter; -+ u32 nonce[3]; -+}; -+ -+struct chacha20_state { -+ struct chacha20_block block; -+}; -+ -+static inline void lrng_cc20_init_rfc7539(struct chacha20_block *chacha20) -+{ -+ chacha_init_consts(chacha20->constants); -+} -+ -+#define LRNG_CC20_INIT_RFC7539(x) \ -+ x.constants[0] = 0x61707865, \ -+ x.constants[1] = 0x3320646e, \ -+ x.constants[2] = 0x79622d32, \ -+ x.constants[3] = 0x6b206574, -+ -+extern const struct lrng_drng_cb lrng_cc20_drng_cb; -+ -+#endif /* _LRNG_CHACHA20_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_drbg.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * LRNG SP800-90A definitions -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_DRBG_H -+#define _LRNG_DRBG_H -+ -+extern const struct lrng_drng_cb lrng_drbg_cb; -+ -+#endif /* _LRNG_DRBG_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_kcapi.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * LRNG kernel crypto API DRNG definition -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_KCAPI_DRNG_H -+#define _LRNG_KCAPI_DRNG_H -+ -+extern const struct lrng_drng_cb lrng_kcapi_drng_cb; -+ -+#endif /* _LRNG_KCAPI_DRNG_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_mgr.c -@@ -0,0 +1,742 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG DRNG management -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_drng_atomic.h" -+#include "lrng_drng_chacha20.h" -+#include "lrng_drng_drbg.h" -+#include "lrng_drng_kcapi.h" -+#include "lrng_drng_mgr.h" -+#include "lrng_es_aux.h" -+#include "lrng_es_mgr.h" -+#include "lrng_interface_random_kernel.h" -+#include "lrng_numa.h" -+#include "lrng_sha.h" -+ -+/* -+ * Maximum number of seconds between DRNG reseed intervals of the DRNG. Note, -+ * this is enforced with the next request of random numbers from the -+ * DRNG. Setting this value to zero implies a reseeding attempt before every -+ * generated random number. -+ */ -+int lrng_drng_reseed_max_time = 600; -+ -+/* -+ * Is LRNG for general-purpose use (i.e. is at least the lrng_drng_init -+ * fully allocated)? -+ */ -+static atomic_t lrng_avail = ATOMIC_INIT(0); -+ -+/* Guard protecting all crypto callback update operation of all DRNGs. */ -+DEFINE_MUTEX(lrng_crypto_cb_update); -+ -+/* -+ * Default hash callback that provides the crypto primitive right from the -+ * kernel start. It must not perform any memory allocation operation, but -+ * simply perform the hash calculation. -+ */ -+const struct lrng_hash_cb *lrng_default_hash_cb = &lrng_sha_hash_cb; -+ -+/* -+ * Default DRNG callback that provides the crypto primitive which is -+ * allocated either during late kernel boot stage. So, it is permissible for -+ * the callback to perform memory allocation operations. -+ */ -+const struct lrng_drng_cb *lrng_default_drng_cb = -+#if defined(CONFIG_LRNG_DFLT_DRNG_CHACHA20) -+ &lrng_cc20_drng_cb; -+#elif defined(CONFIG_LRNG_DFLT_DRNG_DRBG) -+ &lrng_drbg_cb; -+#elif defined(CONFIG_LRNG_DFLT_DRNG_KCAPI) -+ &lrng_kcapi_drng_cb; -+#else -+#error "Unknown default DRNG selected" -+#endif -+ -+/* DRNG for non-atomic use cases */ -+static struct lrng_drng lrng_drng_init = { -+ LRNG_DRNG_STATE_INIT(lrng_drng_init, NULL, NULL, NULL, -+ &lrng_sha_hash_cb), -+ .lock = __MUTEX_INITIALIZER(lrng_drng_init.lock), -+}; -+ -+/* Prediction-resistance DRNG: only deliver as much data as received entropy */ -+static struct lrng_drng lrng_drng_pr = { -+ LRNG_DRNG_STATE_INIT(lrng_drng_pr, NULL, NULL, NULL, -+ &lrng_sha_hash_cb), -+ .lock = __MUTEX_INITIALIZER(lrng_drng_pr.lock), -+}; -+ -+static u32 max_wo_reseed = LRNG_DRNG_MAX_WITHOUT_RESEED; -+#ifdef CONFIG_LRNG_RUNTIME_MAX_WO_RESEED_CONFIG -+module_param(max_wo_reseed, uint, 0444); -+MODULE_PARM_DESC(max_wo_reseed, -+ "Maximum number of DRNG generate operation without full reseed\n"); -+#endif -+ -+static bool force_seeding = true; -+#ifdef CONFIG_LRNG_RUNTIME_FORCE_SEEDING_DISABLE -+module_param(force_seeding, bool, 0444); -+MODULE_PARM_DESC(force_seeding, -+ "Allow disabling of the forced seeding when insufficient entropy is available\n"); -+#endif -+ -+/* Wait queue to wait until the LRNG is initialized - can freely be used */ -+DECLARE_WAIT_QUEUE_HEAD(lrng_init_wait); -+ -+/********************************** Helper ************************************/ -+ -+bool lrng_get_available(void) -+{ -+ return likely(atomic_read(&lrng_avail)); -+} -+ -+struct lrng_drng *lrng_drng_init_instance(void) -+{ -+ return &lrng_drng_init; -+} -+ -+struct lrng_drng *lrng_drng_pr_instance(void) -+{ -+ return &lrng_drng_pr; -+} -+ -+struct lrng_drng *lrng_drng_node_instance(void) -+{ -+ struct lrng_drng **lrng_drng = lrng_drng_instances(); -+ int node = numa_node_id(); -+ -+ if (lrng_drng && lrng_drng[node]) -+ return lrng_drng[node]; -+ -+ return lrng_drng_init_instance(); -+} -+ -+void lrng_drng_reset(struct lrng_drng *drng) -+{ -+ /* Ensure reseed during next call */ -+ atomic_set(&drng->requests, 1); -+ atomic_set(&drng->requests_since_fully_seeded, 0); -+ drng->last_seeded = jiffies; -+ drng->fully_seeded = false; -+ /* Do not set force, as this flag is used for the emergency reseeding */ -+ drng->force_reseed = false; -+ pr_debug("reset DRNG\n"); -+} -+ -+/* Initialize the DRNG, except the mutex lock */ -+int lrng_drng_alloc_common(struct lrng_drng *drng, -+ const struct lrng_drng_cb *drng_cb) -+{ -+ if (!drng || !drng_cb) -+ return -EINVAL; -+ if (!IS_ERR_OR_NULL(drng->drng)) -+ return 0; -+ -+ drng->drng_cb = drng_cb; -+ drng->drng = drng_cb->drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES); -+ if (IS_ERR(drng->drng)) -+ return -PTR_ERR(drng->drng); -+ -+ lrng_drng_reset(drng); -+ return 0; -+} -+ -+/* Initialize the default DRNG during boot and perform its seeding */ -+int lrng_drng_initalize(void) -+{ -+ int ret; -+ -+ if (lrng_get_available()) -+ return 0; -+ -+ /* Catch programming error */ -+ WARN_ON(lrng_drng_init.hash_cb != lrng_default_hash_cb); -+ -+ mutex_lock(&lrng_drng_init.lock); -+ if (lrng_get_available()) { -+ mutex_unlock(&lrng_drng_init.lock); -+ return 0; -+ } -+ -+ /* Initialize the PR DRNG inside init lock as it guards lrng_avail. */ -+ mutex_lock(&lrng_drng_pr.lock); -+ ret = lrng_drng_alloc_common(&lrng_drng_pr, lrng_default_drng_cb); -+ mutex_unlock(&lrng_drng_pr.lock); -+ -+ if (!ret) { -+ ret = lrng_drng_alloc_common(&lrng_drng_init, -+ lrng_default_drng_cb); -+ if (!ret) -+ atomic_set(&lrng_avail, 1); -+ } -+ mutex_unlock(&lrng_drng_init.lock); -+ if (ret) -+ return ret; -+ -+ pr_debug("LRNG for general use is available\n"); -+ -+ /* Seed the DRNG with any entropy available */ -+ if (lrng_pool_trylock()) { -+ pr_info("Initial DRNG initialized triggering first seeding\n"); -+ lrng_drng_seed_work(NULL); -+ } else { -+ pr_info("Initial DRNG initialized without seeding\n"); -+ } -+ -+ return 0; -+} -+ -+static int __init lrng_drng_make_available(void) -+{ -+ return lrng_drng_initalize(); -+} -+late_initcall(lrng_drng_make_available); -+ -+bool lrng_sp80090c_compliant(void) -+{ -+ /* SP800-90C compliant oversampling is only requested in FIPS mode */ -+ return fips_enabled; -+} -+ -+/************************* Random Number Generation ***************************/ -+ -+/* Inject a data buffer into the DRNG - caller must hold its lock */ -+void lrng_drng_inject(struct lrng_drng *drng, const u8 *inbuf, u32 inbuflen, -+ bool fully_seeded, const char *drng_type) -+{ -+ BUILD_BUG_ON(LRNG_DRNG_RESEED_THRESH > INT_MAX); -+ pr_debug("seeding %s DRNG with %u bytes\n", drng_type, inbuflen); -+ if (drng->drng_cb->drng_seed(drng->drng, inbuf, inbuflen) < 0) { -+ pr_warn("seeding of %s DRNG failed\n", drng_type); -+ drng->force_reseed = true; -+ } else { -+ int gc = LRNG_DRNG_RESEED_THRESH - atomic_read(&drng->requests); -+ -+ pr_debug("%s DRNG stats since last seeding: %lu secs; generate calls: %d\n", -+ drng_type, -+ (time_after(jiffies, drng->last_seeded) ? -+ (jiffies - drng->last_seeded) : 0) / HZ, gc); -+ -+ /* Count the numbers of generate ops since last fully seeded */ -+ if (fully_seeded) -+ atomic_set(&drng->requests_since_fully_seeded, 0); -+ else -+ atomic_add(gc, &drng->requests_since_fully_seeded); -+ -+ drng->last_seeded = jiffies; -+ atomic_set(&drng->requests, LRNG_DRNG_RESEED_THRESH); -+ drng->force_reseed = false; -+ -+ if (!drng->fully_seeded) { -+ drng->fully_seeded = fully_seeded; -+ if (drng->fully_seeded) -+ pr_debug("%s DRNG fully seeded\n", drng_type); -+ } -+ } -+} -+ -+/* -+ * Perform the seeding of the DRNG with data from entropy source. -+ * The function returns the entropy injected into the DRNG in bits. -+ */ -+static u32 lrng_drng_seed_es_nolock(struct lrng_drng *drng, bool init_ops, -+ const char *drng_type) -+{ -+ struct entropy_buf seedbuf __aligned(LRNG_KCAPI_ALIGN), -+ collected_seedbuf; -+ u32 collected_entropy = 0; -+ unsigned int i, num_es_delivered = 0; -+ bool forced = drng->force_reseed; -+ -+ for_each_lrng_es(i) -+ collected_seedbuf.e_bits[i] = 0; -+ -+ do { -+ /* Count the number of ES which delivered entropy */ -+ num_es_delivered = 0; -+ -+ if (collected_entropy) -+ pr_debug("Force fully seeding level for %s DRNG by repeatedly pull entropy from available entropy sources\n", -+ drng_type); -+ -+ lrng_fill_seed_buffer(&seedbuf, -+ lrng_get_seed_entropy_osr(drng->fully_seeded), -+ forced && !drng->fully_seeded); -+ -+ collected_entropy += lrng_entropy_rate_eb(&seedbuf); -+ -+ /* Sum iterations up. */ -+ for_each_lrng_es(i) { -+ collected_seedbuf.e_bits[i] += seedbuf.e_bits[i]; -+ num_es_delivered += !!seedbuf.e_bits[i]; -+ } -+ -+ lrng_drng_inject(drng, (u8 *)&seedbuf, sizeof(seedbuf), -+ lrng_fully_seeded(drng->fully_seeded, -+ collected_entropy, -+ &collected_seedbuf), -+ drng_type); -+ -+ /* -+ * Set the seeding state of the LRNG -+ * -+ * Do not call lrng_init_ops(seedbuf) here as the atomic DRNG -+ * does not serve common users. -+ */ -+ if (init_ops) -+ lrng_init_ops(&collected_seedbuf); -+ -+ /* -+ * Emergency reseeding: If we reached the min seed threshold now -+ * multiple times but never reached fully seeded level and we collect -+ * entropy, keep doing it until we reached fully seeded level for -+ * at least one DRNG. This operation is not continued if the -+ * ES do not deliver entropy such that we cannot reach the fully seeded -+ * level. -+ * -+ * The emergency reseeding implies that the consecutively injected -+ * entropy can be added up. This is applicable due to the fact that -+ * the entire operation is atomic which means that the DRNG is not -+ * producing data while this is ongoing. -+ */ -+ } while (force_seeding && forced && !drng->fully_seeded && -+ num_es_delivered >= (lrng_ntg1_2022_compliant() ? 2 : 1)); -+ -+ memzero_explicit(&seedbuf, sizeof(seedbuf)); -+ -+ return collected_entropy; -+} -+ -+static void lrng_drng_seed_es(struct lrng_drng *drng) -+{ -+ mutex_lock(&drng->lock); -+ lrng_drng_seed_es_nolock(drng, true, "regular"); -+ mutex_unlock(&drng->lock); -+} -+ -+static void lrng_drng_seed(struct lrng_drng *drng) -+{ -+ BUILD_BUG_ON(LRNG_MIN_SEED_ENTROPY_BITS > -+ LRNG_DRNG_SECURITY_STRENGTH_BITS); -+ -+ /* (Re-)Seed DRNG */ -+ lrng_drng_seed_es(drng); -+ /* (Re-)Seed atomic DRNG from regular DRNG */ -+ lrng_drng_atomic_seed_drng(drng); -+} -+ -+static void lrng_drng_seed_work_one(struct lrng_drng *drng, u32 node) -+{ -+ pr_debug("reseed triggered by system events for DRNG on NUMA node %d\n", -+ node); -+ lrng_drng_seed(drng); -+ if (drng->fully_seeded) { -+ /* Prevent reseed storm */ -+ drng->last_seeded += node * 100 * HZ; -+ } -+} -+ -+/* -+ * DRNG reseed trigger: Kernel thread handler triggered by the schedule_work() -+ */ -+static void __lrng_drng_seed_work(bool force) -+{ -+ struct lrng_drng **lrng_drng; -+ u32 node; -+ -+ /* -+ * If the DRNG is not yet initialized, let us try to seed the atomic -+ * DRNG. -+ */ -+ if (!lrng_get_available()) { -+ struct lrng_drng *atomic; -+ unsigned long flags; -+ -+ if (wq_has_sleeper(&lrng_init_wait)) { -+ lrng_init_ops(NULL); -+ return; -+ } -+ atomic = lrng_get_atomic(); -+ if (!atomic || atomic->fully_seeded) -+ return; -+ -+ atomic->force_reseed |= force; -+ spin_lock_irqsave(&atomic->spin_lock, flags); -+ lrng_drng_seed_es_nolock(atomic, false, "atomic"); -+ spin_unlock_irqrestore(&atomic->spin_lock, flags); -+ -+ return; -+ } -+ -+ lrng_drng = lrng_drng_instances(); -+ if (lrng_drng) { -+ for_each_online_node(node) { -+ struct lrng_drng *drng = lrng_drng[node]; -+ -+ if (drng && !drng->fully_seeded) { -+ drng->force_reseed |= force; -+ lrng_drng_seed_work_one(drng, node); -+ return; -+ } -+ } -+ } else { -+ if (!lrng_drng_init.fully_seeded) { -+ lrng_drng_init.force_reseed |= force; -+ lrng_drng_seed_work_one(&lrng_drng_init, 0); -+ return; -+ } -+ } -+ -+ if (!lrng_drng_pr.fully_seeded) { -+ lrng_drng_pr.force_reseed |= force; -+ lrng_drng_seed_work_one(&lrng_drng_pr, 0); -+ return; -+ } -+ -+ lrng_pool_all_numa_nodes_seeded(true); -+} -+ -+void lrng_drng_seed_work(struct work_struct *dummy) -+{ -+ __lrng_drng_seed_work(false); -+ -+ /* Allow the seeding operation to be called again */ -+ lrng_pool_unlock(); -+} -+ -+/* Force all DRNGs to reseed before next generation */ -+void lrng_drng_force_reseed(void) -+{ -+ struct lrng_drng **lrng_drng = lrng_drng_instances(); -+ u32 node; -+ -+ /* -+ * If the initial DRNG is over the reseed threshold, allow a forced -+ * reseed only for the initial DRNG as this is the fallback for all. It -+ * must be kept seeded before all others to keep the LRNG operational. -+ */ -+ if (!lrng_drng || -+ (atomic_read_u32(&lrng_drng_init.requests_since_fully_seeded) > -+ LRNG_DRNG_RESEED_THRESH)) { -+ lrng_drng_init.force_reseed = lrng_drng_init.fully_seeded; -+ pr_debug("force reseed of initial DRNG\n"); -+ return; -+ } -+ for_each_online_node(node) { -+ struct lrng_drng *drng = lrng_drng[node]; -+ -+ if (!drng) -+ continue; -+ -+ drng->force_reseed = drng->fully_seeded; -+ pr_debug("force reseed of DRNG on node %u\n", node); -+ } -+ lrng_drng_atomic_force_reseed(); -+} -+EXPORT_SYMBOL(lrng_drng_force_reseed); -+ -+static bool lrng_drng_must_reseed(struct lrng_drng *drng) -+{ -+ return (atomic_dec_and_test(&drng->requests) || -+ drng->force_reseed || -+ time_after(jiffies, -+ drng->last_seeded + lrng_drng_reseed_max_time * HZ)); -+} -+ -+/* -+ * lrng_drng_get() - Get random data out of the DRNG which is reseeded -+ * frequently. -+ * -+ * @drng: DRNG instance -+ * @outbuf: buffer for storing random data -+ * @outbuflen: length of outbuf -+ * -+ * Return: -+ * * < 0 in error case (DRNG generation or update failed) -+ * * >=0 returning the returned number of bytes -+ */ -+int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen) -+{ -+ u32 processed = 0; -+ bool pr = (drng == &lrng_drng_pr) ? true : false; -+ -+ if (!outbuf || !outbuflen) -+ return 0; -+ -+ if (!lrng_get_available()) -+ return -EOPNOTSUPP; -+ -+ outbuflen = min_t(size_t, outbuflen, INT_MAX); -+ -+ /* If DRNG operated without proper reseed for too long, block LRNG */ -+ BUILD_BUG_ON(LRNG_DRNG_MAX_WITHOUT_RESEED < LRNG_DRNG_RESEED_THRESH); -+ if (atomic_read_u32(&drng->requests_since_fully_seeded) > max_wo_reseed) -+ lrng_unset_fully_seeded(drng); -+ -+ while (outbuflen) { -+ u32 todo = min_t(u32, outbuflen, LRNG_DRNG_MAX_REQSIZE); -+ int ret; -+ -+ /* In normal operation, check whether to reseed */ -+ if (!pr && lrng_drng_must_reseed(drng)) { -+ if (!lrng_pool_trylock()) { -+ drng->force_reseed = true; -+ } else { -+ lrng_drng_seed(drng); -+ lrng_pool_unlock(); -+ } -+ } -+ -+ mutex_lock(&drng->lock); -+ -+ if (pr) { -+ /* If async reseed did not deliver entropy, try now */ -+ if (!drng->fully_seeded) { -+ u32 coll_ent_bits; -+ -+ /* If we cannot get the pool lock, try again. */ -+ if (!lrng_pool_trylock()) { -+ mutex_unlock(&drng->lock); -+ continue; -+ } -+ -+ coll_ent_bits = lrng_drng_seed_es_nolock( -+ drng, true, "regular"); -+ -+ lrng_pool_unlock(); -+ -+ /* If no new entropy was received, stop now. */ -+ if (!coll_ent_bits) { -+ mutex_unlock(&drng->lock); -+ goto out; -+ } -+ -+ /* Produce no more data than received entropy */ -+ todo = min_t(u32, todo, coll_ent_bits >> 3); -+ } -+ -+ /* Do not produce more than DRNG security strength */ -+ todo = min_t(u32, todo, lrng_security_strength() >> 3); -+ } -+ ret = drng->drng_cb->drng_generate(drng->drng, -+ outbuf + processed, todo); -+ -+ mutex_unlock(&drng->lock); -+ if (ret <= 0) { -+ pr_warn("getting random data from DRNG failed (%d)\n", -+ ret); -+ return -EFAULT; -+ } -+ processed += ret; -+ outbuflen -= ret; -+ -+ if (pr) { -+ /* Force the async reseed for PR DRNG */ -+ lrng_unset_fully_seeded(drng); -+ if (outbuflen) -+ cond_resched(); -+ } -+ } -+ -+out: -+ return processed; -+} -+ -+int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen, bool pr) -+{ -+ struct lrng_drng **lrng_drng = lrng_drng_instances(); -+ struct lrng_drng *drng = &lrng_drng_init; -+ int ret, node = numa_node_id(); -+ -+ might_sleep(); -+ -+ if (pr) -+ drng = &lrng_drng_pr; -+ else if (lrng_drng && lrng_drng[node] && lrng_drng[node]->fully_seeded) -+ drng = lrng_drng[node]; -+ -+ ret = lrng_drng_initalize(); -+ if (ret) -+ return ret; -+ -+ return lrng_drng_get(drng, outbuf, outbuflen); -+} -+ -+/* Reset LRNG such that all existing entropy is gone */ -+static void _lrng_reset(struct work_struct *work) -+{ -+ struct lrng_drng **lrng_drng = lrng_drng_instances(); -+ -+ if (!lrng_drng) { -+ mutex_lock(&lrng_drng_init.lock); -+ lrng_drng_reset(&lrng_drng_init); -+ mutex_unlock(&lrng_drng_init.lock); -+ } else { -+ u32 node; -+ -+ for_each_online_node(node) { -+ struct lrng_drng *drng = lrng_drng[node]; -+ -+ if (!drng) -+ continue; -+ mutex_lock(&drng->lock); -+ lrng_drng_reset(drng); -+ mutex_unlock(&drng->lock); -+ } -+ } -+ -+ mutex_lock(&lrng_drng_pr.lock); -+ lrng_drng_reset(&lrng_drng_pr); -+ mutex_unlock(&lrng_drng_pr.lock); -+ -+ lrng_drng_atomic_reset(); -+ lrng_set_entropy_thresh(LRNG_INIT_ENTROPY_BITS); -+ -+ lrng_reset_state(); -+} -+ -+static DECLARE_WORK(lrng_reset_work, _lrng_reset); -+ -+void lrng_reset(void) -+{ -+ schedule_work(&lrng_reset_work); -+} -+ -+/******************* Generic LRNG kernel output interfaces ********************/ -+ -+void lrng_force_fully_seeded(void) -+{ -+ if (lrng_pool_all_numa_nodes_seeded_get()) -+ return; -+ -+ lrng_pool_lock(); -+ __lrng_drng_seed_work(true); -+ lrng_pool_unlock(); -+} -+ -+static int lrng_drng_sleep_while_not_all_nodes_seeded(unsigned int nonblock) -+{ -+ lrng_force_fully_seeded(); -+ if (lrng_pool_all_numa_nodes_seeded_get()) -+ return 0; -+ if (nonblock) -+ return -EAGAIN; -+ wait_event_interruptible(lrng_init_wait, -+ lrng_pool_all_numa_nodes_seeded_get()); -+ return 0; -+} -+ -+int lrng_drng_sleep_while_nonoperational(int nonblock) -+{ -+ lrng_force_fully_seeded(); -+ if (likely(lrng_state_operational())) -+ return 0; -+ if (nonblock) -+ return -EAGAIN; -+ return wait_event_interruptible(lrng_init_wait, -+ lrng_state_operational()); -+} -+ -+int lrng_drng_sleep_while_non_min_seeded(void) -+{ -+ lrng_force_fully_seeded(); -+ if (likely(lrng_state_min_seeded())) -+ return 0; -+ return wait_event_interruptible(lrng_init_wait, -+ lrng_state_min_seeded()); -+} -+ -+ssize_t lrng_get_seed(u64 *buf, size_t nbytes, unsigned int flags) -+{ -+ struct entropy_buf *eb = (struct entropy_buf *)(buf + 2); -+ u64 buflen = sizeof(struct entropy_buf) + 2 * sizeof(u64); -+ u64 collected_bits = 0; -+ int ret; -+ -+ /* Ensure buffer is aligned as required */ -+ BUILD_BUG_ON(sizeof(buflen) > LRNG_KCAPI_ALIGN); -+ if (nbytes < sizeof(buflen)) -+ return -EINVAL; -+ -+ /* Write buffer size into first word */ -+ buf[0] = buflen; -+ if (nbytes < buflen) -+ return -EMSGSIZE; -+ -+ ret = lrng_drng_sleep_while_not_all_nodes_seeded( -+ flags & LRNG_GET_SEED_NONBLOCK); -+ if (ret) -+ return ret; -+ -+ /* Try to get the pool lock and sleep on it to get it. */ -+ lrng_pool_lock(); -+ -+ /* If an LRNG DRNG becomes unseeded, give this DRNG precedence. */ -+ if (!lrng_pool_all_numa_nodes_seeded_get()) { -+ lrng_pool_unlock(); -+ return 0; -+ } -+ -+ /* -+ * Try to get seed data - a rarely used busyloop is cheaper than a wait -+ * queue that is constantly woken up by the hot code path of -+ * lrng_init_ops. -+ */ -+ for (;;) { -+ lrng_fill_seed_buffer(eb, -+ lrng_get_seed_entropy_osr(flags & -+ LRNG_GET_SEED_FULLY_SEEDED), -+ false); -+ collected_bits = lrng_entropy_rate_eb(eb); -+ -+ /* Break the collection loop if we got entropy, ... */ -+ if (collected_bits || -+ /* ... a DRNG becomes unseeded, give DRNG precedence, ... */ -+ !lrng_pool_all_numa_nodes_seeded_get() || -+ /* ... if the caller does not want a blocking behavior. */ -+ (flags & LRNG_GET_SEED_NONBLOCK)) -+ break; -+ -+ schedule(); -+ } -+ -+ lrng_pool_unlock(); -+ -+ /* Write collected entropy size into second word */ -+ buf[1] = collected_bits; -+ -+ return (ssize_t)buflen; -+} -+ -+void lrng_get_random_bytes_full(void *buf, int nbytes) -+{ -+ lrng_drng_sleep_while_nonoperational(0); -+ lrng_drng_get_sleep((u8 *)buf, (u32)nbytes, false); -+} -+EXPORT_SYMBOL(lrng_get_random_bytes_full); -+ -+void lrng_get_random_bytes_min(void *buf, int nbytes) -+{ -+ lrng_drng_sleep_while_non_min_seeded(); -+ lrng_drng_get_sleep((u8 *)buf, (u32)nbytes, false); -+} -+EXPORT_SYMBOL(lrng_get_random_bytes_min); -+ -+int lrng_get_random_bytes_pr(void *buf, int nbytes) -+{ -+ lrng_drng_sleep_while_nonoperational(0); -+ return lrng_drng_get_sleep((u8 *)buf, (u32)nbytes, true); -+} -+EXPORT_SYMBOL(lrng_get_random_bytes_pr); ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_mgr.h -@@ -0,0 +1,86 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_DRNG_H -+#define _LRNG_DRNG_H -+ -+#include -+#include -+#include -+ -+#include "lrng_definitions.h" -+ -+extern struct wait_queue_head lrng_init_wait; -+extern int lrng_drng_reseed_max_time; -+extern struct mutex lrng_crypto_cb_update; -+extern const struct lrng_drng_cb *lrng_default_drng_cb; -+extern const struct lrng_hash_cb *lrng_default_hash_cb; -+ -+/* DRNG state handle */ -+struct lrng_drng { -+ void *drng; /* DRNG handle */ -+ void *hash; /* Hash handle */ -+ const struct lrng_drng_cb *drng_cb; /* DRNG callbacks */ -+ const struct lrng_hash_cb *hash_cb; /* Hash callbacks */ -+ atomic_t requests; /* Number of DRNG requests */ -+ atomic_t requests_since_fully_seeded; /* Number DRNG requests since -+ * last fully seeded -+ */ -+ unsigned long last_seeded; /* Last time it was seeded */ -+ bool fully_seeded; /* Is DRNG fully seeded? */ -+ bool force_reseed; /* Force a reseed */ -+ -+ rwlock_t hash_lock; /* Lock hash_cb replacement */ -+ /* Lock write operations on DRNG state, DRNG replacement of drng_cb */ -+ struct mutex lock; /* Non-atomic DRNG operation */ -+ spinlock_t spin_lock; /* Atomic DRNG operation */ -+}; -+ -+#define LRNG_DRNG_STATE_INIT(x, d, h, d_cb, h_cb) \ -+ .drng = d, \ -+ .hash = h, \ -+ .drng_cb = d_cb, \ -+ .hash_cb = h_cb, \ -+ .requests = ATOMIC_INIT(LRNG_DRNG_RESEED_THRESH),\ -+ .requests_since_fully_seeded = ATOMIC_INIT(0), \ -+ .last_seeded = 0, \ -+ .fully_seeded = false, \ -+ .force_reseed = true, \ -+ .hash_lock = __RW_LOCK_UNLOCKED(x.hash_lock) -+ -+struct lrng_drng *lrng_drng_init_instance(void); -+struct lrng_drng *lrng_drng_pr_instance(void); -+struct lrng_drng *lrng_drng_node_instance(void); -+ -+void lrng_reset(void); -+int lrng_drng_alloc_common(struct lrng_drng *drng, -+ const struct lrng_drng_cb *crypto_cb); -+int lrng_drng_initalize(void); -+bool lrng_sp80090c_compliant(void); -+bool lrng_get_available(void); -+void lrng_drng_reset(struct lrng_drng *drng); -+void lrng_drng_inject(struct lrng_drng *drng, const u8 *inbuf, u32 inbuflen, -+ bool fully_seeded, const char *drng_type); -+int lrng_drng_get(struct lrng_drng *drng, u8 *outbuf, u32 outbuflen); -+int lrng_drng_sleep_while_nonoperational(int nonblock); -+int lrng_drng_sleep_while_non_min_seeded(void); -+int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen, bool pr); -+void lrng_drng_seed_work(struct work_struct *dummy); -+void lrng_drng_force_reseed(void); -+void lrng_force_fully_seeded(void); -+ -+static inline u32 lrng_compress_osr(void) -+{ -+ return lrng_sp80090c_compliant() ? LRNG_OVERSAMPLE_ES_BITS : 0; -+} -+ -+static inline u32 lrng_reduce_by_osr(u32 entropy_bits) -+{ -+ u32 osr_bits = lrng_compress_osr(); -+ -+ return (entropy_bits >= osr_bits) ? (entropy_bits - osr_bits) : 0; -+} -+ -+#endif /* _LRNG_DRNG_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_aux.c -@@ -0,0 +1,335 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Slow Entropy Source: Auxiliary entropy pool -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+ -+#include "lrng_es_aux.h" -+#include "lrng_es_mgr.h" -+#include "lrng_sysctl.h" -+ -+/* -+ * This is the auxiliary pool -+ * -+ * The aux pool array is aligned to 8 bytes to comfort the kernel crypto API -+ * cipher implementations of the hash functions used to read the pool: for some -+ * accelerated implementations, we need an alignment to avoid a realignment -+ * which involves memcpy(). The alignment to 8 bytes should satisfy all crypto -+ * implementations. -+ */ -+struct lrng_pool { -+ u8 aux_pool[LRNG_POOL_SIZE]; /* Aux pool: digest state */ -+ atomic_t aux_entropy_bits; -+ atomic_t digestsize; /* Digest size of used hash */ -+ bool initialized; /* Aux pool initialized? */ -+ -+ /* Serialize read of entropy pool and update of aux pool */ -+ spinlock_t lock; -+}; -+ -+static struct lrng_pool lrng_pool __aligned(LRNG_KCAPI_ALIGN) = { -+ .aux_entropy_bits = ATOMIC_INIT(0), -+ .digestsize = ATOMIC_INIT(LRNG_ATOMIC_DIGEST_SIZE), -+ .initialized = false, -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_pool.lock) -+}; -+ -+/********************************** Helper ***********************************/ -+ -+/* Entropy in bits present in aux pool */ -+static u32 lrng_aux_avail_entropy(u32 __unused) -+{ -+ /* Cap available entropy with max entropy */ -+ u32 avail_bits = min_t(u32, lrng_get_digestsize(), -+ atomic_read_u32(&lrng_pool.aux_entropy_bits)); -+ -+ /* Consider oversampling rate due to aux pool conditioning */ -+ return lrng_reduce_by_osr(avail_bits); -+} -+ -+/* Set the digest size of the used hash in bytes */ -+static void lrng_set_digestsize(u32 digestsize) -+{ -+ struct lrng_pool *pool = &lrng_pool; -+ u32 ent_bits = atomic_xchg_relaxed(&pool->aux_entropy_bits, 0), -+ old_digestsize = lrng_get_digestsize(); -+ -+ atomic_set(&lrng_pool.digestsize, digestsize); -+ -+ /* -+ * Update the write wakeup threshold which must not be larger -+ * than the digest size of the current conditioning hash. -+ */ -+ digestsize = lrng_reduce_by_osr(digestsize << 3); -+ lrng_sysctl_update_max_write_thresh(digestsize); -+ lrng_write_wakeup_bits = digestsize; -+ -+ /* -+ * In case the new digest is larger than the old one, cap the available -+ * entropy to the old message digest used to process the existing data. -+ */ -+ ent_bits = min_t(u32, ent_bits, old_digestsize); -+ atomic_add(ent_bits, &pool->aux_entropy_bits); -+} -+ -+static int __init lrng_init_wakeup_bits(void) -+{ -+ u32 digestsize = lrng_reduce_by_osr(lrng_get_digestsize()); -+ -+ lrng_sysctl_update_max_write_thresh(digestsize); -+ lrng_write_wakeup_bits = digestsize; -+ return 0; -+} -+core_initcall(lrng_init_wakeup_bits); -+ -+/* Obtain the digest size provided by the used hash in bits */ -+u32 lrng_get_digestsize(void) -+{ -+ return atomic_read_u32(&lrng_pool.digestsize) << 3; -+} -+ -+/* Set entropy content in user-space controllable aux pool */ -+void lrng_pool_set_entropy(u32 entropy_bits) -+{ -+ atomic_set(&lrng_pool.aux_entropy_bits, entropy_bits); -+} -+ -+static void lrng_aux_reset(void) -+{ -+ lrng_pool_set_entropy(0); -+} -+ -+/* -+ * Replace old with new hash for auxiliary pool handling -+ * -+ * Assumption: the caller must guarantee that the new_cb is available during the -+ * entire operation (e.g. it must hold the write lock against pointer updating). -+ */ -+static int -+lrng_aux_switch_hash(struct lrng_drng *drng, int __unused, -+ const struct lrng_hash_cb *new_cb, void *new_hash, -+ const struct lrng_hash_cb *old_cb) -+{ -+ struct lrng_drng *init_drng = lrng_drng_init_instance(); -+ struct lrng_pool *pool = &lrng_pool; -+ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; -+ u8 digest[LRNG_MAX_DIGESTSIZE]; -+ int ret; -+ -+ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) -+ return -EOPNOTSUPP; -+ -+ if (unlikely(!pool->initialized)) -+ return 0; -+ -+ /* We only switch if the processed DRNG is the initial DRNG. */ -+ if (init_drng != drng) -+ return 0; -+ -+ /* Get the aux pool hash with old digest ... */ -+ ret = old_cb->hash_final(shash, digest) ?: -+ /* ... re-initialize the hash with the new digest ... */ -+ new_cb->hash_init(shash, new_hash) ?: -+ /* -+ * ... feed the old hash into the new state. We may feed -+ * uninitialized memory into the new state, but this is -+ * considered no issue and even good as we have some more -+ * uncertainty here. -+ */ -+ new_cb->hash_update(shash, digest, sizeof(digest)); -+ if (!ret) { -+ lrng_set_digestsize(new_cb->hash_digestsize(new_hash)); -+ pr_debug("Re-initialize aux entropy pool with hash %s\n", -+ new_cb->hash_name()); -+ } -+ -+ memzero_explicit(digest, sizeof(digest)); -+ return ret; -+} -+ -+/* Insert data into auxiliary pool by using the hash update function. */ -+static int -+lrng_aux_pool_insert_locked(const u8 *inbuf, u32 inbuflen, u32 entropy_bits) -+{ -+ struct lrng_pool *pool = &lrng_pool; -+ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; -+ struct lrng_drng *drng = lrng_drng_init_instance(); -+ const struct lrng_hash_cb *hash_cb; -+ unsigned long flags; -+ void *hash; -+ int ret; -+ -+ entropy_bits = min_t(u32, entropy_bits, inbuflen << 3); -+ -+ read_lock_irqsave(&drng->hash_lock, flags); -+ hash_cb = drng->hash_cb; -+ hash = drng->hash; -+ -+ if (unlikely(!pool->initialized)) { -+ ret = hash_cb->hash_init(shash, hash); -+ if (ret) -+ goto out; -+ pool->initialized = true; -+ } -+ -+ ret = hash_cb->hash_update(shash, inbuf, inbuflen); -+ if (ret) -+ goto out; -+ -+ /* -+ * Cap the available entropy to the hash output size compliant to -+ * SP800-90B section 3.1.5.1 table 1. -+ */ -+ entropy_bits += atomic_read_u32(&pool->aux_entropy_bits); -+ atomic_set(&pool->aux_entropy_bits, -+ min_t(u32, entropy_bits, -+ hash_cb->hash_digestsize(hash) << 3)); -+ -+out: -+ read_unlock_irqrestore(&drng->hash_lock, flags); -+ return ret; -+} -+ -+int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits) -+{ -+ struct lrng_pool *pool = &lrng_pool; -+ unsigned long flags; -+ int ret; -+ -+ spin_lock_irqsave(&pool->lock, flags); -+ ret = lrng_aux_pool_insert_locked(inbuf, inbuflen, entropy_bits); -+ spin_unlock_irqrestore(&pool->lock, flags); -+ -+ lrng_es_add_entropy(); -+ -+ return ret; -+} -+EXPORT_SYMBOL(lrng_pool_insert_aux); -+ -+/************************* Get data from entropy pool *************************/ -+ -+/* -+ * Get auxiliary entropy pool and its entropy content for seed buffer. -+ * Caller must hold lrng_pool.pool->lock. -+ * @outbuf: buffer to store data in with size requested_bits -+ * @requested_bits: Requested amount of entropy -+ * @return: amount of entropy in outbuf in bits. -+ */ -+static u32 lrng_aux_get_pool(u8 *outbuf, u32 requested_bits) -+{ -+ struct lrng_pool *pool = &lrng_pool; -+ struct shash_desc *shash = (struct shash_desc *)pool->aux_pool; -+ struct lrng_drng *drng = lrng_drng_init_instance(); -+ const struct lrng_hash_cb *hash_cb; -+ unsigned long flags; -+ void *hash; -+ u32 collected_ent_bits, returned_ent_bits, unused_bits = 0, -+ digestsize, digestsize_bits, requested_bits_osr; -+ u8 aux_output[LRNG_MAX_DIGESTSIZE]; -+ -+ if (unlikely(!pool->initialized)) -+ return 0; -+ -+ read_lock_irqsave(&drng->hash_lock, flags); -+ -+ hash_cb = drng->hash_cb; -+ hash = drng->hash; -+ digestsize = hash_cb->hash_digestsize(hash); -+ digestsize_bits = digestsize << 3; -+ -+ /* Cap to maximum entropy that can ever be generated with given hash */ -+ lrng_cap_requested(digestsize_bits, requested_bits); -+ -+ /* Ensure that no more than the size of aux_pool can be requested */ -+ requested_bits = min_t(u32, requested_bits, (LRNG_MAX_DIGESTSIZE << 3)); -+ requested_bits_osr = requested_bits + lrng_compress_osr(); -+ -+ /* Cap entropy with entropy counter from aux pool and the used digest */ -+ collected_ent_bits = min_t(u32, digestsize_bits, -+ atomic_xchg_relaxed(&pool->aux_entropy_bits, 0)); -+ -+ /* We collected too much entropy and put the overflow back */ -+ if (collected_ent_bits > requested_bits_osr) { -+ /* Amount of bits we collected too much */ -+ unused_bits = collected_ent_bits - requested_bits_osr; -+ /* Put entropy back */ -+ atomic_add(unused_bits, &pool->aux_entropy_bits); -+ /* Fix collected entropy */ -+ collected_ent_bits = requested_bits_osr; -+ } -+ -+ /* Apply oversampling: discount requested oversampling rate */ -+ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits); -+ -+ pr_debug("obtained %u bits by collecting %u bits of entropy from aux pool, %u bits of entropy remaining\n", -+ returned_ent_bits, collected_ent_bits, unused_bits); -+ -+ /* Get the digest for the aux pool to be returned to the caller ... */ -+ if (hash_cb->hash_final(shash, aux_output) || -+ /* -+ * ... and re-initialize the aux state. Do not add the aux pool -+ * digest for backward secrecy as it will be added with the -+ * insertion of the complete seed buffer after it has been filled. -+ */ -+ hash_cb->hash_init(shash, hash)) { -+ returned_ent_bits = 0; -+ } else { -+ /* -+ * Do not truncate the output size exactly to collected_ent_bits -+ * as the aux pool may contain data that is not credited with -+ * entropy, but we want to use them to stir the DRNG state. -+ */ -+ memcpy(outbuf, aux_output, requested_bits >> 3); -+ } -+ -+ read_unlock_irqrestore(&drng->hash_lock, flags); -+ memzero_explicit(aux_output, digestsize); -+ return returned_ent_bits; -+} -+ -+static void lrng_aux_get_backtrack(struct entropy_buf *eb, u32 requested_bits, -+ bool __unused) -+{ -+ struct lrng_pool *pool = &lrng_pool; -+ unsigned long flags; -+ -+ /* Ensure aux pool extraction and backtracking op are atomic */ -+ spin_lock_irqsave(&pool->lock, flags); -+ -+ eb->e_bits[lrng_ext_es_aux] = lrng_aux_get_pool(eb->e[lrng_ext_es_aux], -+ requested_bits); -+ -+ /* Mix the extracted data back into pool for backtracking resistance */ -+ if (lrng_aux_pool_insert_locked((u8 *)eb, -+ sizeof(struct entropy_buf), 0)) -+ pr_warn("Backtracking resistance operation failed\n"); -+ -+ spin_unlock_irqrestore(&pool->lock, flags); -+} -+ -+static void lrng_aux_es_state(unsigned char *buf, size_t buflen) -+{ -+ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ -+ /* Assume the lrng_drng_init lock is taken by caller */ -+ snprintf(buf, buflen, -+ " Hash for operating entropy pool: %s\n" -+ " Available entropy: %u\n", -+ lrng_drng_init->hash_cb->hash_name(), -+ lrng_aux_avail_entropy(0)); -+} -+ -+struct lrng_es_cb lrng_es_aux = { -+ .name = "Auxiliary", -+ .get_ent = lrng_aux_get_backtrack, -+ .curr_entropy = lrng_aux_avail_entropy, -+ .max_entropy = lrng_get_digestsize, -+ .state = lrng_aux_es_state, -+ .reset = lrng_aux_reset, -+ .switch_hash = lrng_aux_switch_hash, -+}; ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_aux.h -@@ -0,0 +1,44 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_AUX_H -+#define _LRNG_ES_AUX_H -+ -+#include "lrng_drng_mgr.h" -+#include "lrng_es_mgr_cb.h" -+ -+u32 lrng_get_digestsize(void); -+void lrng_pool_set_entropy(u32 entropy_bits); -+int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits); -+ -+extern struct lrng_es_cb lrng_es_aux; -+ -+/****************************** Helper code ***********************************/ -+ -+/* Obtain the security strength of the LRNG in bits */ -+static inline u32 lrng_security_strength(void) -+{ -+ /* -+ * We use a hash to read the entropy in the entropy pool. According to -+ * SP800-90B table 1, the entropy can be at most the digest size. -+ * Considering this together with the last sentence in section 3.1.5.1.2 -+ * the security strength of a (approved) hash is equal to its output -+ * size. On the other hand the entropy cannot be larger than the -+ * security strength of the used DRBG. -+ */ -+ return min_t(u32, LRNG_FULL_SEED_ENTROPY_BITS, lrng_get_digestsize()); -+} -+ -+static inline u32 lrng_get_seed_entropy_osr(bool fully_seeded) -+{ -+ u32 requested_bits = lrng_security_strength(); -+ -+ /* Apply oversampling during initialization according to SP800-90C */ -+ if (lrng_sp80090c_compliant() && !fully_seeded) -+ requested_bits += LRNG_SEED_BUFFER_INIT_ADD_BITS; -+ return requested_bits; -+} -+ -+#endif /* _LRNG_ES_AUX_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_cpu.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_CPU_H -+#define _LRNG_ES_CPU_H -+ -+#include "lrng_es_mgr_cb.h" -+ -+#ifdef CONFIG_LRNG_CPU -+ -+extern struct lrng_es_cb lrng_es_cpu; -+ -+#endif /* CONFIG_LRNG_CPU */ -+ -+#endif /* _LRNG_ES_CPU_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_irq.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_IRQ_H -+#define _LRNG_ES_IRQ_H -+ -+#include -+ -+#include "lrng_es_mgr_cb.h" -+ -+#ifdef CONFIG_LRNG_IRQ -+void lrng_irq_es_init(bool highres_timer); -+void lrng_irq_array_add_u32(u32 data); -+ -+extern struct lrng_es_cb lrng_es_irq; -+ -+#else /* CONFIG_LRNG_IRQ */ -+static inline void lrng_irq_es_init(bool highres_timer) { } -+static inline void lrng_irq_array_add_u32(u32 data) { } -+#endif /* CONFIG_LRNG_IRQ */ -+ -+#endif /* _LRNG_ES_IRQ_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_jent.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_JENT_H -+#define _LRNG_ES_JENT_H -+ -+#include "lrng_es_mgr_cb.h" -+ -+#ifdef CONFIG_LRNG_JENT -+ -+extern struct lrng_es_cb lrng_es_jent; -+ -+#endif /* CONFIG_LRNG_JENT */ -+ -+#endif /* _LRNG_ES_JENT_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_krng.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_RANDOM_H -+#define _LRNG_ES_RANDOM_H -+ -+#include "lrng_es_mgr_cb.h" -+ -+#ifdef CONFIG_LRNG_KERNEL_RNG -+ -+extern struct lrng_es_cb lrng_es_krng; -+ -+#endif /* CONFIG_LRNG_KERNEL_RNG */ -+ -+#endif /* _LRNG_ES_RANDOM_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_mgr.c -@@ -0,0 +1,506 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Entropy sources management -+ * -+ * Copyright (C) 2022 - 2023, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_drng_atomic.h" -+#include "lrng_drng_mgr.h" -+#include "lrng_es_aux.h" -+#include "lrng_es_cpu.h" -+#include "lrng_es_irq.h" -+#include "lrng_es_jent.h" -+#include "lrng_es_krng.h" -+#include "lrng_es_mgr.h" -+#include "lrng_es_sched.h" -+#include "lrng_interface_dev_common.h" -+#include "lrng_interface_random_kernel.h" -+ -+struct lrng_state { -+ bool can_invalidate; /* Can invalidate batched entropy? */ -+ bool perform_seedwork; /* Can seed work be performed? */ -+ bool lrng_operational; /* Is DRNG operational? */ -+ bool lrng_fully_seeded; /* Is DRNG fully seeded? */ -+ bool lrng_min_seeded; /* Is DRNG minimally seeded? */ -+ bool all_online_numa_node_seeded;/* All NUMA DRNGs seeded? */ -+ -+ /* -+ * To ensure that external entropy providers cannot dominate the -+ * internal noise sources but yet cannot be dominated by internal -+ * noise sources, the following booleans are intended to allow -+ * external to provide seed once when a DRNG reseed occurs. This -+ * triggering of external noise source is performed even when the -+ * entropy pool has sufficient entropy. -+ */ -+ -+ atomic_t boot_entropy_thresh; /* Reseed threshold */ -+ struct mutex reseed_in_progress; /* Flag for on executing reseed */ -+ struct work_struct lrng_seed_work; /* (re)seed work queue */ -+}; -+ -+static struct lrng_state lrng_state = { -+ false, false, false, false, false, false, -+ .boot_entropy_thresh = ATOMIC_INIT(LRNG_INIT_ENTROPY_BITS), -+ .reseed_in_progress = -+ __MUTEX_INITIALIZER(lrng_state.reseed_in_progress), -+}; -+ -+/* -+ * If the entropy count falls under this number of bits, then we -+ * should wake up processes which are selecting or polling on write -+ * access to /dev/random. -+ */ -+u32 lrng_write_wakeup_bits = (LRNG_WRITE_WAKEUP_ENTROPY << 3); -+ -+/* -+ * The entries must be in the same order as defined by enum lrng_internal_es and -+ * enum lrng_external_es -+ */ -+struct lrng_es_cb *lrng_es[] = { -+#ifdef CONFIG_LRNG_IRQ -+ &lrng_es_irq, -+#endif -+#ifdef CONFIG_LRNG_SCHED -+ &lrng_es_sched, -+#endif -+#ifdef CONFIG_LRNG_JENT -+ &lrng_es_jent, -+#endif -+#ifdef CONFIG_LRNG_CPU -+ &lrng_es_cpu, -+#endif -+#ifdef CONFIG_LRNG_KERNEL_RNG -+ &lrng_es_krng, -+#endif -+ &lrng_es_aux -+}; -+ -+static bool ntg1 = false; -+#ifdef CONFIG_LRNG_AIS2031_NTG1_SEEDING_STRATEGY -+module_param(ntg1, bool, 0444); -+MODULE_PARM_DESC(ntg1, "Enable AIS20/31 NTG.1 compliant seeding strategy\n"); -+#endif -+ -+/* Only panic the kernel on permanent health failure if this variable is true */ -+static bool lrng_panic_on_permanent_health_failure = false; -+module_param(lrng_panic_on_permanent_health_failure, bool, 0444); -+MODULE_PARM_DESC(lrng_panic_on_permanent_health_failure, "Panic on reaching permanent health failure - only required if LRNG is part of a FIPS 140-3 module\n"); -+ -+/********************************** Helper ***********************************/ -+ -+bool lrng_enforce_panic_on_permanent_health_failure(void) -+{ -+ return lrng_panic_on_permanent_health_failure; -+} -+ -+bool lrng_ntg1_2022_compliant(void) -+{ -+ /* Implies use of /dev/random w/ O_SYNC / getrandom w/ GRND_RANDOM */ -+ return ntg1; -+} -+ -+void lrng_debug_report_seedlevel(const char *name) -+{ -+#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM -+ static void *previous = NULL; -+ void *caller = (void *) _RET_IP_; -+ struct lrng_drng *atomic = lrng_get_atomic(); -+ -+ if (READ_ONCE(previous) == caller) -+ return; -+ -+ if (atomic && !atomic->fully_seeded) -+ pr_notice("%pS %s called without reaching minimally seeded level (available entropy %u)\n", -+ caller, name, lrng_avail_entropy()); -+ -+ WRITE_ONCE(previous, caller); -+#endif -+} -+ -+/* -+ * Reading of the LRNG pool is only allowed by one caller. The reading is -+ * only performed to (re)seed DRNGs. Thus, if this "lock" is already taken, -+ * the reseeding operation is in progress. The caller is not intended to wait -+ * but continue with its other operation. -+ */ -+int lrng_pool_trylock(void) -+{ -+ return mutex_trylock(&lrng_state.reseed_in_progress); -+} -+ -+void lrng_pool_lock(void) -+{ -+ mutex_lock(&lrng_state.reseed_in_progress); -+} -+ -+void lrng_pool_unlock(void) -+{ -+ mutex_unlock(&lrng_state.reseed_in_progress); -+} -+ -+/* Set new entropy threshold for reseeding during boot */ -+void lrng_set_entropy_thresh(u32 new_entropy_bits) -+{ -+ atomic_set(&lrng_state.boot_entropy_thresh, new_entropy_bits); -+} -+ -+/* -+ * Reset LRNG state - the entropy counters are reset, but the data that may -+ * or may not have entropy remains in the pools as this data will not hurt. -+ */ -+void lrng_reset_state(void) -+{ -+ u32 i; -+ -+ for_each_lrng_es(i) { -+ if (lrng_es[i]->reset) -+ lrng_es[i]->reset(); -+ } -+ lrng_state.lrng_operational = false; -+ lrng_state.lrng_fully_seeded = false; -+ lrng_state.lrng_min_seeded = false; -+ lrng_state.all_online_numa_node_seeded = false; -+ pr_debug("reset LRNG\n"); -+} -+ -+/* Set flag that all DRNGs are fully seeded */ -+void lrng_pool_all_numa_nodes_seeded(bool set) -+{ -+ lrng_state.all_online_numa_node_seeded = set; -+ if (set) -+ wake_up_all(&lrng_init_wait); -+} -+ -+bool lrng_pool_all_numa_nodes_seeded_get(void) -+{ -+ return lrng_state.all_online_numa_node_seeded; -+} -+ -+/* Return boolean whether LRNG reached minimally seed level */ -+bool lrng_state_min_seeded(void) -+{ -+ return lrng_state.lrng_min_seeded; -+} -+ -+/* Return boolean whether LRNG reached fully seed level */ -+bool lrng_state_fully_seeded(void) -+{ -+ return lrng_state.lrng_fully_seeded; -+} -+ -+/* Return boolean whether LRNG is considered fully operational */ -+bool lrng_state_operational(void) -+{ -+ return lrng_state.lrng_operational; -+} -+ -+static void lrng_init_wakeup(void) -+{ -+ wake_up_all(&lrng_init_wait); -+ lrng_init_wakeup_dev(); -+ lrng_kick_random_ready(); -+} -+ -+static u32 lrng_avail_entropy_thresh(void) -+{ -+ u32 ent_thresh = lrng_security_strength(); -+ -+ /* -+ * Apply oversampling during initialization according to SP800-90C as -+ * we request a larger buffer from the ES. -+ */ -+ if (lrng_sp80090c_compliant() && -+ !lrng_state.all_online_numa_node_seeded) -+ ent_thresh += LRNG_SEED_BUFFER_INIT_ADD_BITS; -+ -+ return ent_thresh; -+} -+ -+bool lrng_fully_seeded(bool fully_seeded, u32 collected_entropy, -+ struct entropy_buf *eb) -+{ -+ /* AIS20/31 NTG.1: two entropy sources with each delivering 220 bits */ -+ if (ntg1) { -+ u32 i, result = 0, ent_thresh = lrng_avail_entropy_thresh(); -+ -+ for_each_lrng_es(i) { -+ result += (eb ? eb->e_bits[i] : -+ lrng_es[i]->curr_entropy(ent_thresh)) >= -+ LRNG_AIS2031_NPTRNG_MIN_ENTROPY; -+ } -+ -+ return (result >= 2); -+ } -+ -+ return (collected_entropy >= lrng_get_seed_entropy_osr(fully_seeded)); -+} -+ -+u32 lrng_entropy_rate_eb(struct entropy_buf *eb) -+{ -+ u32 i, collected_entropy = 0; -+ -+ for_each_lrng_es(i) -+ collected_entropy += eb->e_bits[i]; -+ -+ return collected_entropy; -+} -+ -+/* Mark one DRNG as not fully seeded */ -+void lrng_unset_fully_seeded(struct lrng_drng *drng) -+{ -+ drng->fully_seeded = false; -+ lrng_pool_all_numa_nodes_seeded(false); -+ -+ /* -+ * The init DRNG instance must always be fully seeded as this instance -+ * is the fall-back if any of the per-NUMA node DRNG instances is -+ * insufficiently seeded. Thus, we mark the entire LRNG as -+ * non-operational if the initial DRNG becomes not fully seeded. -+ */ -+ if (drng == lrng_drng_init_instance() && lrng_state_operational()) { -+ pr_debug("LRNG set to non-operational\n"); -+ lrng_state.lrng_operational = false; -+ lrng_state.lrng_fully_seeded = false; -+ -+ /* If sufficient entropy is available, reseed now. */ -+ lrng_es_add_entropy(); -+ } -+} -+ -+/* Policy to enable LRNG operational mode */ -+static void lrng_set_operational(void) -+{ -+ /* -+ * LRNG is operational if the initial DRNG is fully seeded. This state -+ * can only occur if either the external entropy sources provided -+ * sufficient entropy, or the SP800-90B startup test completed for -+ * the internal ES to supply also entropy data. -+ */ -+ if (lrng_state.lrng_fully_seeded) { -+ lrng_state.lrng_operational = true; -+ lrng_init_wakeup(); -+ pr_info("LRNG fully operational\n"); -+ } -+} -+ -+/* Available entropy in the entire LRNG considering all entropy sources */ -+u32 lrng_avail_entropy(void) -+{ -+ u32 i, ent = 0, ent_thresh = lrng_avail_entropy_thresh(); -+ -+ BUILD_BUG_ON(ARRAY_SIZE(lrng_es) != lrng_ext_es_last); -+ for_each_lrng_es(i) -+ ent += lrng_es[i]->curr_entropy(ent_thresh); -+ return ent; -+} -+ -+u32 lrng_avail_entropy_aux(void) -+{ -+ u32 ent_thresh = lrng_avail_entropy_thresh(); -+ -+ return lrng_es[lrng_ext_es_aux]->curr_entropy(ent_thresh); -+} -+ -+/* -+ * lrng_init_ops() - Set seed stages of LRNG -+ * -+ * Set the slow noise source reseed trigger threshold. The initial threshold -+ * is set to the minimum data size that can be read from the pool: a word. Upon -+ * reaching this value, the next seed threshold of 128 bits is set followed -+ * by 256 bits. -+ * -+ * @eb: buffer containing the size of entropy currently injected into DRNG - if -+ * NULL, the function obtains the available entropy from the ES. -+ */ -+void lrng_init_ops(struct entropy_buf *eb) -+{ -+ struct lrng_state *state = &lrng_state; -+ u32 i, requested_bits, seed_bits = 0; -+ -+ if (state->lrng_operational) -+ return; -+ -+ requested_bits = ntg1 ? -+ /* Approximation so that two ES should deliver 220 bits each */ -+ (lrng_avail_entropy() + LRNG_AIS2031_NPTRNG_MIN_ENTROPY) : -+ /* Apply SP800-90C oversampling if applicable */ -+ lrng_get_seed_entropy_osr(state->all_online_numa_node_seeded); -+ -+ if (eb) { -+ seed_bits = lrng_entropy_rate_eb(eb); -+ } else { -+ u32 ent_thresh = lrng_avail_entropy_thresh(); -+ -+ for_each_lrng_es(i) -+ seed_bits += lrng_es[i]->curr_entropy(ent_thresh); -+ } -+ -+ /* DRNG is seeded with full security strength */ -+ if (state->lrng_fully_seeded) { -+ lrng_set_operational(); -+ lrng_set_entropy_thresh(requested_bits); -+ } else if (lrng_fully_seeded(state->all_online_numa_node_seeded, -+ seed_bits, eb)) { -+ if (state->can_invalidate) -+ invalidate_batched_entropy(); -+ -+ state->lrng_fully_seeded = true; -+ lrng_set_operational(); -+ state->lrng_min_seeded = true; -+ pr_info("LRNG fully seeded with %u bits of entropy\n", -+ seed_bits); -+ lrng_set_entropy_thresh(requested_bits); -+ } else if (!state->lrng_min_seeded) { -+ -+ /* DRNG is seeded with at least 128 bits of entropy */ -+ if (seed_bits >= LRNG_MIN_SEED_ENTROPY_BITS) { -+ if (state->can_invalidate) -+ invalidate_batched_entropy(); -+ -+ state->lrng_min_seeded = true; -+ pr_info("LRNG minimally seeded with %u bits of entropy\n", -+ seed_bits); -+ lrng_set_entropy_thresh(requested_bits); -+ lrng_init_wakeup(); -+ -+ /* DRNG is seeded with at least LRNG_INIT_ENTROPY_BITS bits */ -+ } else if (seed_bits >= LRNG_INIT_ENTROPY_BITS) { -+ pr_info("LRNG initial entropy level %u bits of entropy\n", -+ seed_bits); -+ lrng_set_entropy_thresh(LRNG_MIN_SEED_ENTROPY_BITS); -+ } -+ } -+} -+ -+void __init lrng_rand_initialize_early(void) -+{ -+ struct seed { -+ unsigned long data[((LRNG_MAX_DIGESTSIZE + -+ sizeof(unsigned long) - 1) / -+ sizeof(unsigned long))]; -+ struct new_utsname utsname; -+ } seed __aligned(LRNG_KCAPI_ALIGN); -+ size_t longs = 0; -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(seed.data); i += longs) { -+ longs = arch_get_random_seed_longs(seed.data + i, -+ ARRAY_SIZE(seed.data) - i); -+ if (longs) -+ continue; -+ longs = arch_get_random_longs(seed.data + i, -+ ARRAY_SIZE(seed.data) - i); -+ if (longs) -+ continue; -+ longs = 1; -+ } -+ memcpy(&seed.utsname, init_utsname(), sizeof(*(init_utsname()))); -+ -+ lrng_pool_insert_aux((u8 *)&seed, sizeof(seed), 0); -+ memzero_explicit(&seed, sizeof(seed)); -+ -+ lrng_force_fully_seeded(); -+} -+ -+void __init lrng_rand_initialize(void) -+{ -+ unsigned long entropy = random_get_entropy(); -+ ktime_t time = ktime_get_real(); -+ -+ lrng_pool_insert_aux((u8 *)&entropy, sizeof(entropy), 0); -+ lrng_pool_insert_aux((u8 *)&time, sizeof(time), 0); -+ -+ /* Initialize the seed work queue */ -+ INIT_WORK(&lrng_state.lrng_seed_work, lrng_drng_seed_work); -+ lrng_state.perform_seedwork = true; -+ -+ invalidate_batched_entropy(); -+ -+ lrng_state.can_invalidate = true; -+} -+ -+#ifndef CONFIG_LRNG_RANDOM_IF -+static int __init lrng_rand_initialize_call(void) -+{ -+ lrng_rand_initialize_early(); -+ lrng_rand_initialize(); -+ return 0; -+} -+ -+early_initcall(lrng_rand_initialize_call); -+#endif -+ -+/* Interface requesting a reseed of the DRNG */ -+void lrng_es_add_entropy(void) -+{ -+ /* -+ * Once all DRNGs are fully seeded, the system-triggered arrival of -+ * entropy will not cause any reseeding any more. -+ */ -+ if (likely(lrng_state.all_online_numa_node_seeded)) -+ return; -+ -+ /* Only trigger the DRNG reseed if we have collected entropy. */ -+ if (lrng_avail_entropy() < -+ atomic_read_u32(&lrng_state.boot_entropy_thresh)) -+ return; -+ -+ /* Ensure that the seeding only occurs once at any given time. */ -+ if (!lrng_pool_trylock()) -+ return; -+ -+ /* Seed the DRNG with any available noise. */ -+ if (lrng_state.perform_seedwork) -+ schedule_work(&lrng_state.lrng_seed_work); -+ else -+ lrng_drng_seed_work(NULL); -+} -+ -+/* Fill the seed buffer with data from the noise sources */ -+void lrng_fill_seed_buffer(struct entropy_buf *eb, u32 requested_bits, -+ bool force) -+{ -+ struct lrng_state *state = &lrng_state; -+ u32 i, req_ent = lrng_sp80090c_compliant() ? -+ lrng_security_strength() : LRNG_MIN_SEED_ENTROPY_BITS; -+ -+ /* Guarantee that requested bits is a multiple of bytes */ -+ BUILD_BUG_ON(LRNG_DRNG_SECURITY_STRENGTH_BITS % 8); -+ -+ /* always reseed the DRNG with the current time stamp */ -+ eb->now = random_get_entropy(); -+ -+ /* -+ * Require at least 128 bits of entropy for any reseed. If the LRNG is -+ * operated SP800-90C compliant we want to comply with SP800-90A section -+ * 9.2 mandating that DRNG is reseeded with the security strength. -+ */ -+ if (!force && -+ state->lrng_fully_seeded && (lrng_avail_entropy() < req_ent)) { -+ for_each_lrng_es(i) -+ eb->e_bits[i] = 0; -+ -+ goto wakeup; -+ } -+ -+ /* Concatenate the output of the entropy sources. */ -+ for_each_lrng_es(i) { -+ lrng_es[i]->get_ent(eb, requested_bits, -+ state->lrng_fully_seeded); -+ } -+ -+ /* allow external entropy provider to provide seed */ -+ lrng_state_exseed_allow_all(); -+ -+wakeup: -+ lrng_writer_wakeup(); -+} ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_mgr.h -@@ -0,0 +1,56 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_MGR_H -+#define _LRNG_ES_MGR_H -+ -+#include "lrng_es_mgr_cb.h" -+ -+/*************************** General LRNG parameter ***************************/ -+ -+#define LRNG_DRNG_BLOCKSIZE 64 /* Maximum of DRNG block sizes */ -+ -+/* Helper to concatenate a macro with an integer type */ -+#define LRNG_PASTER(x, y) x ## y -+#define LRNG_UINT32_C(x) LRNG_PASTER(x, U) -+ -+/************************* Entropy sources management *************************/ -+ -+extern struct lrng_es_cb *lrng_es[]; -+ -+#define for_each_lrng_es(ctr) \ -+ for ((ctr) = 0; (ctr) < lrng_ext_es_last; (ctr)++) -+ -+bool lrng_enforce_panic_on_permanent_health_failure(void); -+bool lrng_ntg1_2022_compliant(void); -+bool lrng_pool_all_numa_nodes_seeded_get(void); -+bool lrng_state_min_seeded(void); -+void lrng_debug_report_seedlevel(const char *name); -+void lrng_rand_initialize_early(void); -+void lrng_rand_initialize(void); -+bool lrng_state_operational(void); -+ -+extern u32 lrng_write_wakeup_bits; -+void lrng_set_entropy_thresh(u32 new); -+u32 lrng_avail_entropy(void); -+u32 lrng_avail_entropy_aux(void); -+void lrng_reset_state(void); -+ -+bool lrng_state_fully_seeded(void); -+ -+int lrng_pool_trylock(void); -+void lrng_pool_lock(void); -+void lrng_pool_unlock(void); -+void lrng_pool_all_numa_nodes_seeded(bool set); -+ -+bool lrng_fully_seeded(bool fully_seeded, u32 collected_entropy, -+ struct entropy_buf *eb); -+u32 lrng_entropy_rate_eb(struct entropy_buf *eb); -+void lrng_unset_fully_seeded(struct lrng_drng *drng); -+void lrng_fill_seed_buffer(struct entropy_buf *eb, u32 requested_bits, -+ bool force); -+void lrng_init_ops(struct entropy_buf *eb); -+ -+#endif /* _LRNG_ES_MGR_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_mgr_cb.h -@@ -0,0 +1,87 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ * -+ * Definition of an entropy source. -+ */ -+ -+#ifndef _LRNG_ES_MGR_CB_H -+#define _LRNG_ES_MGR_CB_H -+ -+#include -+ -+#include "lrng_definitions.h" -+#include "lrng_drng_mgr.h" -+ -+enum lrng_internal_es { -+#ifdef CONFIG_LRNG_IRQ -+ lrng_int_es_irq, /* IRQ-based entropy source */ -+#endif -+#ifdef CONFIG_LRNG_SCHED -+ lrng_int_es_sched, /* Scheduler entropy source */ -+#endif -+ lrng_int_es_last, /* MUST be the last entry */ -+}; -+ -+enum lrng_external_es { -+ lrng_ext_link = lrng_int_es_last - 1, /* Link entry */ -+#ifdef CONFIG_LRNG_JENT -+ lrng_ext_es_jitter, /* Jitter RNG */ -+#endif -+#ifdef CONFIG_LRNG_CPU -+ lrng_ext_es_cpu, /* CPU-based, e.g. RDSEED */ -+#endif -+#ifdef CONFIG_LRNG_KERNEL_RNG -+ lrng_ext_es_krng, /* random.c */ -+#endif -+ lrng_ext_es_aux, /* MUST BE LAST ES! */ -+ lrng_ext_es_last /* MUST be the last entry */ -+}; -+ -+struct entropy_buf { -+ u8 e[lrng_ext_es_last][LRNG_DRNG_INIT_SEED_SIZE_BYTES]; -+ u32 now, e_bits[lrng_ext_es_last]; -+}; -+ -+/* -+ * struct lrng_es_cb - callback defining an entropy source -+ * @name: Name of the entropy source. -+ * @get_ent: Fetch entropy into the entropy_buf. The ES shall only deliver -+ * data if its internal initialization is complete, including any -+ * SP800-90B startup testing or similar. -+ * @curr_entropy: Return amount of currently available entropy. -+ * @max_entropy: Maximum amount of entropy the entropy source is able to -+ * maintain. -+ * @state: Buffer with human-readable ES state. -+ * @reset: Reset entropy source (drop all entropy and reinitialize). -+ * This callback may be NULL. -+ * @switch_hash: callback to switch from an old hash callback definition to -+ * a new one. This callback may be NULL. -+ */ -+struct lrng_es_cb { -+ const char *name; -+ void (*get_ent)(struct entropy_buf *eb, u32 requested_bits, -+ bool fully_seeded); -+ u32 (*curr_entropy)(u32 requested_bits); -+ u32 (*max_entropy)(void); -+ void (*state)(unsigned char *buf, size_t buflen); -+ void (*reset)(void); -+ int (*switch_hash)(struct lrng_drng *drng, int node, -+ const struct lrng_hash_cb *new_cb, void *new_hash, -+ const struct lrng_hash_cb *old_cb); -+}; -+ -+/* Allow entropy sources to tell the ES manager that new entropy is there */ -+void lrng_es_add_entropy(void); -+ -+/* Cap to maximum entropy that can ever be generated with given hash */ -+#define lrng_cap_requested(__digestsize_bits, __requested_bits) \ -+ do { \ -+ if (__digestsize_bits < __requested_bits) { \ -+ pr_debug("Cannot satisfy requested entropy %u due to insufficient hash size %u\n",\ -+ __requested_bits, __digestsize_bits); \ -+ __requested_bits = __digestsize_bits; \ -+ } \ -+ } while (0) -+ -+#endif /* _LRNG_ES_MGR_CB_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_sched.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_SCHED_H -+#define _LRNG_ES_SCHED_H -+ -+#include "lrng_es_mgr_cb.h" -+ -+#ifdef CONFIG_LRNG_SCHED -+void lrng_sched_es_init(bool highres_timer); -+ -+extern struct lrng_es_cb lrng_es_sched; -+ -+#else /* CONFIG_LRNG_SCHED */ -+static inline void lrng_sched_es_init(bool highres_timer) { } -+#endif /* CONFIG_LRNG_SCHED */ -+ -+#endif /* _LRNG_ES_SCHED_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_timer_common.h -@@ -0,0 +1,83 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * LRNG Slow Noise Source: Time stamp array handling -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_ES_TIMER_COMMON_H -+#define _LRNG_ES_TIMER_COMMON_H -+ -+bool lrng_gcd_tested(void); -+void lrng_gcd_set(u32 running_gcd); -+u32 lrng_gcd_get(void); -+u32 lrng_gcd_analyze(u32 *history, size_t nelem); -+void lrng_gcd_add_value(u32 time); -+bool lrng_highres_timer(void); -+ -+/* -+ * To limit the impact on the interrupt handling, the LRNG concatenates -+ * entropic LSB parts of the time stamps in a per-CPU array and only -+ * injects them into the entropy pool when the array is full. -+ */ -+ -+/* Store multiple integers in one u32 */ -+#define LRNG_DATA_SLOTSIZE_BITS (8) -+#define LRNG_DATA_SLOTSIZE_MASK ((1 << LRNG_DATA_SLOTSIZE_BITS) - 1) -+#define LRNG_DATA_ARRAY_MEMBER_BITS (4 << 3) /* ((sizeof(u32)) << 3) */ -+#define LRNG_DATA_SLOTS_PER_UINT (LRNG_DATA_ARRAY_MEMBER_BITS / \ -+ LRNG_DATA_SLOTSIZE_BITS) -+ -+/* -+ * Number of time values to store in the array - in small environments -+ * only one atomic_t variable per CPU is used. -+ */ -+#define LRNG_DATA_NUM_VALUES (CONFIG_LRNG_COLLECTION_SIZE) -+/* Mask of LSB of time stamp to store */ -+#define LRNG_DATA_WORD_MASK (LRNG_DATA_NUM_VALUES - 1) -+ -+#define LRNG_DATA_SLOTS_MASK (LRNG_DATA_SLOTS_PER_UINT - 1) -+#define LRNG_DATA_ARRAY_SIZE (LRNG_DATA_NUM_VALUES / \ -+ LRNG_DATA_SLOTS_PER_UINT) -+ -+/* Starting bit index of slot */ -+static inline unsigned int lrng_data_slot2bitindex(unsigned int slot) -+{ -+ return (LRNG_DATA_SLOTSIZE_BITS * slot); -+} -+ -+/* Convert index into the array index */ -+static inline unsigned int lrng_data_idx2array(unsigned int idx) -+{ -+ return idx / LRNG_DATA_SLOTS_PER_UINT; -+} -+ -+/* Convert index into the slot of a given array index */ -+static inline unsigned int lrng_data_idx2slot(unsigned int idx) -+{ -+ return idx & LRNG_DATA_SLOTS_MASK; -+} -+ -+/* Convert value into slot value */ -+static inline unsigned int lrng_data_slot_val(unsigned int val, -+ unsigned int slot) -+{ -+ return val << lrng_data_slot2bitindex(slot); -+} -+ -+/* -+ * Return the pointers for the previous and current units to inject a u32 into. -+ * Also return the mask which the u32 word is to be processed. -+ */ -+static inline void lrng_data_split_u32(u32 *ptr, u32 *pre_ptr, u32 *mask) -+{ -+ /* ptr to previous unit */ -+ *pre_ptr = (*ptr - LRNG_DATA_SLOTS_PER_UINT) & LRNG_DATA_WORD_MASK; -+ *ptr &= LRNG_DATA_WORD_MASK; -+ -+ /* mask to split data into the two parts for the two units */ -+ *mask = ((1 << (*pre_ptr & (LRNG_DATA_SLOTS_PER_UINT - 1)) * -+ LRNG_DATA_SLOTSIZE_BITS)) - 1; -+} -+ -+#endif /* _LRNG_ES_TIMER_COMMON_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_dev_common.h -@@ -0,0 +1,51 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_INTERFACE_DEV_COMMON_H -+#define _LRNG_INTERFACE_DEV_COMMON_H -+ -+#include -+#include -+ -+/******************* Upstream functions hooked into the LRNG ******************/ -+enum lrng_external_noise_source { -+ lrng_noise_source_hw, -+ lrng_noise_source_user -+}; -+ -+#ifdef CONFIG_LRNG_COMMON_DEV_IF -+void lrng_writer_wakeup(void); -+void lrng_init_wakeup_dev(void); -+void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type); -+void lrng_state_exseed_allow_all(void); -+#else /* CONFIG_LRNG_COMMON_DEV_IF */ -+static inline void lrng_writer_wakeup(void) { } -+static inline void lrng_init_wakeup_dev(void) { } -+static inline void -+lrng_state_exseed_set(enum lrng_external_noise_source source, bool type) { } -+static inline void lrng_state_exseed_allow_all(void) { } -+#endif /* CONFIG_LRNG_COMMON_DEV_IF */ -+ -+/****** Downstream service functions to actual interface implementations ******/ -+ -+bool lrng_state_exseed_allow(enum lrng_external_noise_source source); -+int lrng_fasync(int fd, struct file *filp, int on); -+long lrng_ioctl(struct file *f, unsigned int cmd, unsigned long arg); -+ssize_t lrng_drng_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos); -+ssize_t lrng_drng_write_common(const char __user *buffer, size_t count, -+ u32 entropy_bits); -+__poll_t lrng_random_poll(struct file *file, poll_table *wait); -+ssize_t lrng_read_common_block(int nonblock, int pr, -+ char __user *buf, size_t nbytes); -+ssize_t lrng_drng_read_block(struct file *file, char __user *buf, size_t nbytes, -+ loff_t *ppos); -+ssize_t lrng_read_seed(char __user *buf, size_t nbytes, unsigned int flags); -+ssize_t lrng_read_common(char __user *buf, size_t nbytes, bool pr); -+bool lrng_need_entropy(void); -+ -+extern struct wait_queue_head lrng_write_wait; -+ -+#endif /* _LRNG_INTERFACE_DEV_COMMON_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_random_kernel.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_INTERFACE_RANDOM_H -+#define _LRNG_INTERFACE_RANDOM_H -+ -+#ifdef CONFIG_LRNG_RANDOM_IF -+void invalidate_batched_entropy(void); -+void lrng_kick_random_ready(void); -+#else /* CONFIG_LRNG_RANDOM_IF */ -+static inline void invalidate_batched_entropy(void) { } -+static inline void lrng_kick_random_ready(void) { } -+#endif /* CONFIG_LRNG_RANDOM_IF */ -+ -+#endif /* _LRNG_INTERFACE_RANDOM_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_numa.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_NUMA_H -+#define _LRNG_NUMA_H -+ -+static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; } -+ -+#endif /* _LRNG_NUMA_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_sha.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * LRNG SHA definition usable in atomic contexts right from the start of the -+ * kernel. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_SHA_H -+#define _LRNG_SHA_H -+ -+extern const struct lrng_hash_cb lrng_sha_hash_cb; -+ -+#endif /* _LRNG_SHA_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_sha1.c -@@ -0,0 +1,88 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * Backend for the LRNG providing the SHA-1 implementation that can be used -+ * without the kernel crypto API available including during early boot and in -+ * atomic contexts. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+ -+#include "lrng_sha.h" -+ -+/* -+ * If the SHA-256 support is not compiled, we fall back to SHA-1 that is always -+ * compiled and present in the kernel. -+ */ -+static u32 lrng_sha1_hash_digestsize(void *hash) -+{ -+ return SHA1_DIGEST_SIZE; -+} -+ -+static void lrng_sha1_block_fn(struct sha1_state *sctx, const u8 *src, -+ int blocks) -+{ -+ u32 temp[SHA1_WORKSPACE_WORDS]; -+ -+ while (blocks--) { -+ sha1_transform(sctx->state, src, temp); -+ src += SHA1_BLOCK_SIZE; -+ } -+ memzero_explicit(temp, sizeof(temp)); -+} -+ -+static int lrng_sha1_hash_init(struct shash_desc *shash, void *hash) -+{ -+ /* -+ * We do not need a TFM - we only need sufficient space for -+ * struct sha1_state on the stack. -+ */ -+ sha1_base_init(shash); -+ return 0; -+} -+ -+static int lrng_sha1_hash_update(struct shash_desc *shash, -+ const u8 *inbuf, u32 inbuflen) -+{ -+ return sha1_base_do_update(shash, inbuf, inbuflen, lrng_sha1_block_fn); -+} -+ -+static int lrng_sha1_hash_final(struct shash_desc *shash, u8 *digest) -+{ -+ return sha1_base_do_finalize(shash, lrng_sha1_block_fn) ?: -+ sha1_base_finish(shash, digest); -+} -+ -+static const char *lrng_sha1_hash_name(void) -+{ -+ return "SHA-1"; -+} -+ -+static void lrng_sha1_hash_desc_zero(struct shash_desc *shash) -+{ -+ memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha1_state)); -+} -+ -+static void *lrng_sha1_hash_alloc(void) -+{ -+ pr_info("Hash %s allocated\n", lrng_sha1_hash_name()); -+ return NULL; -+} -+ -+static void lrng_sha1_hash_dealloc(void *hash) { } -+ -+const struct lrng_hash_cb lrng_sha_hash_cb = { -+ .hash_name = lrng_sha1_hash_name, -+ .hash_alloc = lrng_sha1_hash_alloc, -+ .hash_dealloc = lrng_sha1_hash_dealloc, -+ .hash_digestsize = lrng_sha1_hash_digestsize, -+ .hash_init = lrng_sha1_hash_init, -+ .hash_update = lrng_sha1_hash_update, -+ .hash_final = lrng_sha1_hash_final, -+ .hash_desc_zero = lrng_sha1_hash_desc_zero, -+}; ---- /dev/null -+++ b/drivers/char/lrng/lrng_sha256.c -@@ -0,0 +1,72 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * Backend for the LRNG providing the SHA-256 implementation that can be used -+ * without the kernel crypto API available including during early boot and in -+ * atomic contexts. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+ -+#include "lrng_sha.h" -+ -+static u32 lrng_sha256_hash_digestsize(void *hash) -+{ -+ return SHA256_DIGEST_SIZE; -+} -+ -+static int lrng_sha256_hash_init(struct shash_desc *shash, void *hash) -+{ -+ /* -+ * We do not need a TFM - we only need sufficient space for -+ * struct sha256_state on the stack. -+ */ -+ sha256_init(shash_desc_ctx(shash)); -+ return 0; -+} -+ -+static int lrng_sha256_hash_update(struct shash_desc *shash, -+ const u8 *inbuf, u32 inbuflen) -+{ -+ sha256_update(shash_desc_ctx(shash), inbuf, inbuflen); -+ return 0; -+} -+ -+static int lrng_sha256_hash_final(struct shash_desc *shash, u8 *digest) -+{ -+ sha256_final(shash_desc_ctx(shash), digest); -+ return 0; -+} -+ -+static const char *lrng_sha256_hash_name(void) -+{ -+ return "SHA-256"; -+} -+ -+static void lrng_sha256_hash_desc_zero(struct shash_desc *shash) -+{ -+ memzero_explicit(shash_desc_ctx(shash), sizeof(struct sha256_state)); -+} -+ -+static void *lrng_sha256_hash_alloc(void) -+{ -+ pr_info("Hash %s allocated\n", lrng_sha256_hash_name()); -+ return NULL; -+} -+ -+static void lrng_sha256_hash_dealloc(void *hash) { } -+ -+const struct lrng_hash_cb lrng_sha_hash_cb = { -+ .hash_name = lrng_sha256_hash_name, -+ .hash_alloc = lrng_sha256_hash_alloc, -+ .hash_dealloc = lrng_sha256_hash_dealloc, -+ .hash_digestsize = lrng_sha256_hash_digestsize, -+ .hash_init = lrng_sha256_hash_init, -+ .hash_update = lrng_sha256_hash_update, -+ .hash_final = lrng_sha256_hash_final, -+ .hash_desc_zero = lrng_sha256_hash_desc_zero, -+}; ---- /dev/null -+++ b/drivers/char/lrng/lrng_sysctl.h -@@ -0,0 +1,15 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_SYSCTL_H -+#define _LRNG_SYSCTL_H -+ -+#ifdef CONFIG_LRNG_SYSCTL -+void lrng_sysctl_update_max_write_thresh(u32 new_digestsize); -+#else -+static inline void lrng_sysctl_update_max_write_thresh(u32 new_digestsize) { } -+#endif -+ -+#endif /* _LRNG_SYSCTL_H */ ---- /dev/null -+++ b/include/linux/lrng.h -@@ -0,0 +1,251 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_H -+#define _LRNG_H -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * struct lrng_drng_cb - cryptographic callback functions defining a DRNG -+ * @drng_name Name of DRNG -+ * @drng_alloc: Allocate DRNG -- the provided integer should be used for -+ * sanity checks. -+ * return: allocated data structure or PTR_ERR on error -+ * @drng_dealloc: Deallocate DRNG -+ * @drng_seed: Seed the DRNG with data of arbitrary length drng: is -+ * pointer to data structure allocated with drng_alloc -+ * return: >= 0 on success, < 0 on error -+ * @drng_generate: Generate random numbers from the DRNG with arbitrary -+ * length -+ */ -+struct lrng_drng_cb { -+ const char *(*drng_name)(void); -+ void *(*drng_alloc)(u32 sec_strength); -+ void (*drng_dealloc)(void *drng); -+ int (*drng_seed)(void *drng, const u8 *inbuf, u32 inbuflen); -+ int (*drng_generate)(void *drng, u8 *outbuf, u32 outbuflen); -+}; -+ -+/* -+ * struct lrng_hash_cb - cryptographic callback functions defining a hash -+ * @hash_name Name of Hash used for reading entropy pool arbitrary -+ * length -+ * @hash_alloc: Allocate the hash for reading the entropy pool -+ * return: allocated data structure (NULL is success too) -+ * or ERR_PTR on error -+ * @hash_dealloc: Deallocate Hash -+ * @hash_digestsize: Return the digestsize for the used hash to read out -+ * entropy pool -+ * hash: is pointer to data structure allocated with -+ * hash_alloc -+ * return: size of digest of hash in bytes -+ * @hash_init: Initialize hash -+ * hash: is pointer to data structure allocated with -+ * hash_alloc -+ * return: 0 on success, < 0 on error -+ * @hash_update: Update hash operation -+ * hash: is pointer to data structure allocated with -+ * hash_alloc -+ * return: 0 on success, < 0 on error -+ * @hash_final Final hash operation -+ * hash: is pointer to data structure allocated with -+ * hash_alloc -+ * return: 0 on success, < 0 on error -+ * @hash_desc_zero Zeroization of hash state buffer -+ * -+ * Assumptions: -+ * -+ * 1. Hash operation will not sleep -+ * 2. The hash' volatile state information is provided with *shash by caller. -+ */ -+struct lrng_hash_cb { -+ const char *(*hash_name)(void); -+ void *(*hash_alloc)(void); -+ void (*hash_dealloc)(void *hash); -+ u32 (*hash_digestsize)(void *hash); -+ int (*hash_init)(struct shash_desc *shash, void *hash); -+ int (*hash_update)(struct shash_desc *shash, const u8 *inbuf, -+ u32 inbuflen); -+ int (*hash_final)(struct shash_desc *shash, u8 *digest); -+ void (*hash_desc_zero)(struct shash_desc *shash); -+}; -+ -+/* Register cryptographic backend */ -+#ifdef CONFIG_LRNG_SWITCH -+int lrng_set_drng_cb(const struct lrng_drng_cb *cb); -+int lrng_set_hash_cb(const struct lrng_hash_cb *cb); -+#else /* CONFIG_LRNG_SWITCH */ -+static inline int -+lrng_set_drng_cb(const struct lrng_drng_cb *cb) { return -EOPNOTSUPP; } -+static inline int -+lrng_set_hash_cb(const struct lrng_hash_cb *cb) { return -EOPNOTSUPP; } -+#endif /* CONFIG_LRNG_SWITCH */ -+ -+/* Callback to feed events to the scheduler entropy source */ -+#ifdef CONFIG_LRNG_SCHED -+extern void add_sched_randomness(const struct task_struct *p, int cpu); -+#else -+static inline void -+add_sched_randomness(const struct task_struct *p, int cpu) { } -+#endif -+ -+/* -+ * lrng_get_random_bytes() - Provider of cryptographic strong random numbers -+ * for kernel-internal usage. -+ * -+ * This function is appropriate for in-kernel use cases operating in atomic -+ * contexts. It will always use the ChaCha20 DRNG and it may be the case that -+ * it is not fully seeded when being used. -+ * -+ * @buf: buffer to store the random bytes -+ * @nbytes: size of the buffer -+ */ -+#ifdef CONFIG_LRNG_DRNG_ATOMIC -+void lrng_get_random_bytes(void *buf, int nbytes); -+#endif -+ -+/* -+ * lrng_get_random_bytes_full() - Provider of cryptographic strong -+ * random numbers for kernel-internal usage from a fully initialized LRNG. -+ * -+ * This function will always return random numbers from a fully seeded and -+ * fully initialized LRNG. -+ * -+ * This function is appropriate only for non-atomic use cases as this -+ * function may sleep. It provides access to the full functionality of LRNG -+ * including the switchable DRNG support, that may support other DRNGs such -+ * as the SP800-90A DRBG. -+ * -+ * @buf: buffer to store the random bytes -+ * @nbytes: size of the buffer -+ */ -+#ifdef CONFIG_LRNG -+void lrng_get_random_bytes_full(void *buf, int nbytes); -+#endif -+ -+/* -+ * lrng_get_random_bytes_min() - Provider of cryptographic strong -+ * random numbers for kernel-internal usage from at least a minimally seeded -+ * LRNG, which is not necessarily fully initialized yet (e.g. SP800-90C -+ * oversampling applied in FIPS mode is not applied yet). -+ * -+ * This function is appropriate only for non-atomic use cases as this -+ * function may sleep. It provides access to the full functionality of LRNG -+ * including the switchable DRNG support, that may support other DRNGs such -+ * as the SP800-90A DRBG. -+ * -+ * @buf: buffer to store the random bytes -+ * @nbytes: size of the buffer -+ */ -+#ifdef CONFIG_LRNG -+void lrng_get_random_bytes_min(void *buf, int nbytes); -+#endif -+ -+/* -+ * lrng_get_random_bytes_pr() - Provider of cryptographic strong -+ * random numbers for kernel-internal usage from a fully initialized LRNG and -+ * requiring a reseed from the entropy sources before. -+ * -+ * This function will always return random numbers from a fully seeded and -+ * fully initialized LRNG. -+ * -+ * This function is appropriate only for non-atomic use cases as this -+ * function may sleep. It provides access to the full functionality of LRNG -+ * including the switchable DRNG support, that may support other DRNGs such -+ * as the SP800-90A DRBG. -+ * -+ * This call only returns no more data than entropy was pulled from the -+ * entropy sources. Thus, it is likely that this call returns less data -+ * than requested by the caller. Also, the caller MUST be prepared that this -+ * call returns 0 bytes, i.e. it did not generate data. -+ * -+ * @buf: buffer to store the random bytes -+ * @nbytes: size of the buffer -+ * -+ * @return: positive number indicates amount of generated bytes, < 0 on error -+ */ -+#ifdef CONFIG_LRNG -+int lrng_get_random_bytes_pr(void *buf, int nbytes); -+#endif -+ -+/* -+ * lrng_get_seed() - Fill buffer with data from entropy sources -+ * -+ * This call allows accessing the entropy sources directly and fill the buffer -+ * with data from all available entropy sources. This filled buffer is -+ * identical to the temporary seed buffer used by the LRNG to seed its DRNGs. -+ * -+ * The call is to allows users to seed their DRNG directly from the entropy -+ * sources in case the caller does not want to use the LRNG's DRNGs. This -+ * buffer can be directly used to seed the caller's DRNG from. -+ * -+ * The call blocks as long as one LRNG DRNG is not yet fully seeded. If -+ * LRNG_GET_SEED_NONBLOCK is specified, it does not block in this case, but -+ * returns with an error. -+ * -+ * Considering SP800-90C, there is a differentiation between the seeding -+ * requirements during instantiating a DRNG and at runtime of the DRNG. When -+ * specifying LRNG_GET_SEED_FULLY_SEEDED the caller indicates the DRNG was -+ * already fully seeded and the regular amount of entropy is requested. -+ * Otherwise, the LRNG will obtain the entropy rate required for initial -+ * seeding. The following minimum entropy rates will be obtained: -+ * -+ * * FIPS mode: -+ * * Initial seeding: 384 bits of entropy -+ * * Runtime seeding: 256 bits of entropy -+ * * Non-FIPS mode: -+ * * 128 bits of entropy in any case -+ * -+ * Albeit these are minimum entropy rates, the LRNG tries to request the -+ * given amount of entropy from each entropy source individually. If the -+ * minimum amount of entropy cannot be obtained collectively by all entropy -+ * sources, the LRNG will not fill the buffer. -+ * -+ * The return data in buf is structurally equivalent to the following -+ * definition: -+ * -+ * struct { -+ * u64 seedlen; -+ * u64 entropy_rate; -+ * struct entropy_buf seed; -+ * } __attribute((__packed__)); -+ * -+ * As struct entropy_buf is not known outsize of the LRNG, the LRNG fills -+ * seedlen first with the size of struct entropy_buf. If the caller-provided -+ * buffer buf is smaller than u64, then -EINVAL is returned -+ * and buf is not touched. If it is u64 or larger but smaller -+ * than the size of the structure above, -EMSGSIZE is returned and seedlen -+ * is filled with the size of the buffer. Finally, if buf is large -+ * enough to hold all data, it is filled with the seed data and the seedlen -+ * is set to sizeof(struct entropy_buf). The entropy rate is returned with -+ * the variable entropy_rate and provides the value in bits. -+ * -+ * The seed buffer is the data that should be handed to the caller's DRNG as -+ * seed data. -+ * -+ * @buf [out] Buffer to be filled with data from the entropy sources - note, the -+ * buffer is marked as u64 to ensure it is aligned to 64 bits. -+ * @nbytes [in] Size of the buffer allocated by the caller - this value -+ * provides size of @param buf in bytes. -+ * @flags [in] Flags field to adjust the behavior -+ * -+ * @return -EINVAL or -EMSGSIZE indicating the buffer is too small, -EAGAIN when -+ * the call would block, but NONBLOCK is specified, > 0 the size of -+ * the filled buffer. -+ */ -+#ifdef CONFIG_LRNG -+enum lrng_get_seed_flags { -+ LRNG_GET_SEED_NONBLOCK = 0x0001, /**< Do not block the call */ -+ LRNG_GET_SEED_FULLY_SEEDED = 0x0002, /**< DRNG is fully seeded */ -+}; -+ -+ssize_t lrng_get_seed(u64 *buf, size_t nbytes, unsigned int flags); -+#endif -+ -+#endif /* _LRNG_H */ diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch deleted file mode 100644 index 09d9b8ec8..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch +++ /dev/null @@ -1,194 +0,0 @@ -From af8b9713b5ad9aaa67e604c494c0098fccf915a1 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 15:40:46 +0200 -Subject: [PATCH 02/25] LRNG - allocate one DRNG instance per NUMA node - -In order to improve NUMA-locality when serving getrandom(2) requests, -allocate one DRNG instance per node. - -The DRNG instance that is present right from the start of the kernel is -reused as the first per-NUMA-node DRNG. For all remaining online NUMA -nodes a new DRNG instance is allocated. - -During boot time, the multiple DRNG instances are seeded sequentially. -With this, the first DRNG instance (referenced as the initial DRNG -in the code) is completely seeded with 256 bits of entropy before the -next DRNG instance is completely seeded. - -When random numbers are requested, the NUMA-node-local DRNG is checked -whether it has been already fully seeded. If this is not the case, the -initial DRNG is used to serve the request. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Makefile | 2 + - drivers/char/lrng/lrng_numa.c | 124 ++++++++++++++++++++++++++++++++++ - drivers/char/lrng/lrng_numa.h | 4 ++ - drivers/char/lrng/lrng_proc.h | 11 +++ - 4 files changed, 141 insertions(+) - create mode 100644 drivers/char/lrng/lrng_numa.c - create mode 100644 drivers/char/lrng/lrng_proc.h - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -8,4 +8,6 @@ obj-y += lrng_es_mgr.o lrng_drng_mgr - obj-$(CONFIG_LRNG_SHA256) += lrng_sha256.o - obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o - -+obj-$(CONFIG_NUMA) += lrng_numa.o -+ - obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_numa.c -@@ -0,0 +1,124 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG NUMA support -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+ -+#include "lrng_drng_mgr.h" -+#include "lrng_es_irq.h" -+#include "lrng_es_mgr.h" -+#include "lrng_numa.h" -+#include "lrng_proc.h" -+ -+static struct lrng_drng **lrng_drng __read_mostly = NULL; -+ -+struct lrng_drng **lrng_drng_instances(void) -+{ -+ /* counterpart to cmpxchg_release in _lrng_drngs_numa_alloc */ -+ return READ_ONCE(lrng_drng); -+} -+ -+/* Allocate the data structures for the per-NUMA node DRNGs */ -+static void _lrng_drngs_numa_alloc(struct work_struct *work) -+{ -+ struct lrng_drng **drngs; -+ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ u32 node; -+ bool init_drng_used = false; -+ -+ mutex_lock(&lrng_crypto_cb_update); -+ -+ /* per-NUMA-node DRNGs are already present */ -+ if (lrng_drng) -+ goto unlock; -+ -+ /* Make sure the initial DRNG is initialized and its drng_cb is set */ -+ if (lrng_drng_initalize()) -+ goto err; -+ -+ drngs = kcalloc(nr_node_ids, sizeof(void *), GFP_KERNEL|__GFP_NOFAIL); -+ for_each_online_node(node) { -+ struct lrng_drng *drng; -+ -+ if (!init_drng_used) { -+ drngs[node] = lrng_drng_init; -+ init_drng_used = true; -+ continue; -+ } -+ -+ drng = kmalloc_node(sizeof(struct lrng_drng), -+ GFP_KERNEL|__GFP_NOFAIL, node); -+ memset(drng, 0, sizeof(lrng_drng)); -+ -+ if (lrng_drng_alloc_common(drng, lrng_drng_init->drng_cb)) { -+ kfree(drng); -+ goto err; -+ } -+ -+ drng->hash_cb = lrng_drng_init->hash_cb; -+ drng->hash = lrng_drng_init->hash_cb->hash_alloc(); -+ if (IS_ERR(drng->hash)) { -+ lrng_drng_init->drng_cb->drng_dealloc(drng->drng); -+ kfree(drng); -+ goto err; -+ } -+ -+ mutex_init(&drng->lock); -+ rwlock_init(&drng->hash_lock); -+ -+ /* -+ * No reseeding of NUMA DRNGs from previous DRNGs as this -+ * would complicate the code. Let it simply reseed. -+ */ -+ drngs[node] = drng; -+ -+ lrng_pool_inc_numa_node(); -+ pr_info("DRNG and entropy pool read hash for NUMA node %d allocated\n", -+ node); -+ } -+ -+ /* counterpart to READ_ONCE in lrng_drng_instances */ -+ if (!cmpxchg_release(&lrng_drng, NULL, drngs)) { -+ lrng_pool_all_numa_nodes_seeded(false); -+ goto unlock; -+ } -+ -+err: -+ for_each_online_node(node) { -+ struct lrng_drng *drng = drngs[node]; -+ -+ if (drng == lrng_drng_init) -+ continue; -+ -+ if (drng) { -+ drng->hash_cb->hash_dealloc(drng->hash); -+ drng->drng_cb->drng_dealloc(drng->drng); -+ kfree(drng); -+ } -+ } -+ kfree(drngs); -+ -+unlock: -+ mutex_unlock(&lrng_crypto_cb_update); -+} -+ -+static DECLARE_WORK(lrng_drngs_numa_alloc_work, _lrng_drngs_numa_alloc); -+ -+static void lrng_drngs_numa_alloc(void) -+{ -+ schedule_work(&lrng_drngs_numa_alloc_work); -+} -+ -+static int __init lrng_numa_init(void) -+{ -+ lrng_drngs_numa_alloc(); -+ return 0; -+} -+ -+late_initcall(lrng_numa_init); ---- a/drivers/char/lrng/lrng_numa.h -+++ b/drivers/char/lrng/lrng_numa.h -@@ -6,6 +6,10 @@ - #ifndef _LRNG_NUMA_H - #define _LRNG_NUMA_H - -+#ifdef CONFIG_NUMA -+struct lrng_drng **lrng_drng_instances(void); -+#else /* CONFIG_NUMA */ - static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; } -+#endif /* CONFIG_NUMA */ - - #endif /* _LRNG_NUMA_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_proc.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_PROC_H -+#define _LRNG_PROC_H -+ -+static inline void lrng_pool_inc_numa_node(void) { } -+ -+#endif /* _LRNG_PROC_H */ diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0003-LRNG-proc-interface.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0003-LRNG-proc-interface.patch deleted file mode 100644 index 8201bf4dd..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0003-LRNG-proc-interface.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 25710c7badb8f60dbc18ab7f7beb95a4cfd978fc Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 18 Dec 2022 21:12:42 +0100 -Subject: [PATCH 03/25] LRNG - /proc interface - -The patch adds the file lrng_type which provides details about -the LRNG: - -- the name of the DRNG that produces the random numbers for /dev/random, -/dev/urandom, getrandom(2) - -- the hash used to produce random numbers from the entropy pool - -- the number of secondary DRNG instances - -- indicator whether the LRNG operates SP800-90B compliant - -- indicator whether a high-resolution timer is identified - only with a -high-resolution timer the interrupt noise source will deliver sufficient -entropy - -- indicator whether the LRNG has been minimally seeded (i.e. is the -secondary DRNG seeded with at least 128 bits of entropy) - -- indicator whether the LRNG has been fully seeded (i.e. is the -secondary DRNG seeded with at least 256 bits of entropy) - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_proc.c | 74 +++++++++++++++++++++++++++++++++++ - drivers/char/lrng/lrng_proc.h | 4 ++ - 3 files changed, 79 insertions(+) - create mode 100644 drivers/char/lrng/lrng_proc.c - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -8,6 +8,7 @@ obj-y += lrng_es_mgr.o lrng_drng_mgr - obj-$(CONFIG_LRNG_SHA256) += lrng_sha256.o - obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o - -+obj-$(CONFIG_SYSCTL) += lrng_proc.o - obj-$(CONFIG_NUMA) += lrng_numa.o - - obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_proc.c -@@ -0,0 +1,74 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG proc interfaces -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "lrng_drng_mgr.h" -+#include "lrng_es_aux.h" -+#include "lrng_es_mgr.h" -+#include "lrng_proc.h" -+ -+/* Number of online DRNGs */ -+static u32 numa_drngs = 1; -+ -+void lrng_pool_inc_numa_node(void) -+{ -+ numa_drngs++; -+} -+ -+static int lrng_proc_type_show(struct seq_file *m, void *v) -+{ -+ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ unsigned char buf[270]; -+ u32 i; -+ -+ mutex_lock(&lrng_drng_init->lock); -+ snprintf(buf, sizeof(buf), -+ "DRNG name: %s\n" -+ "LRNG security strength in bits: %d\n" -+ "Number of DRNG instances: %u\n" -+ "Standards compliance: %sNTG.1 (2011%s)\n" -+ "LRNG minimally seeded: %s\n" -+ "LRNG fully seeded: %s\n" -+ "LRNG entropy level: %u\n", -+ lrng_drng_init->drng_cb->drng_name(), -+ lrng_security_strength(), -+ numa_drngs, -+ lrng_sp80090c_compliant() ? "SP800-90C, " : "", -+ lrng_ntg1_2022_compliant() ? " / 2022" : "", -+ lrng_state_min_seeded() ? "true" : "false", -+ lrng_state_fully_seeded() ? "true" : "false", -+ lrng_avail_entropy()); -+ seq_write(m, buf, strlen(buf)); -+ -+ for_each_lrng_es(i) { -+ snprintf(buf, sizeof(buf), -+ "Entropy Source %u properties:\n" -+ " Name: %s\n", -+ i, lrng_es[i]->name); -+ seq_write(m, buf, strlen(buf)); -+ -+ buf[0] = '\0'; -+ lrng_es[i]->state(buf, sizeof(buf)); -+ seq_write(m, buf, strlen(buf)); -+ } -+ -+ mutex_unlock(&lrng_drng_init->lock); -+ -+ return 0; -+} -+ -+static int __init lrng_proc_type_init(void) -+{ -+ proc_create_single("lrng_type", 0444, NULL, &lrng_proc_type_show); -+ return 0; -+} -+ -+module_init(lrng_proc_type_init); ---- a/drivers/char/lrng/lrng_proc.h -+++ b/drivers/char/lrng/lrng_proc.h -@@ -6,6 +6,10 @@ - #ifndef _LRNG_PROC_H - #define _LRNG_PROC_H - -+#ifdef CONFIG_SYSCTL -+void lrng_pool_inc_numa_node(void); -+#else - static inline void lrng_pool_inc_numa_node(void) { } -+#endif - - #endif /* _LRNG_PROC_H */ diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch deleted file mode 100644 index 59160913b..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch +++ /dev/null @@ -1,363 +0,0 @@ -From 3c33dfe027fca31d07e48e24c041a2f1706a4c07 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Mon, 20 Feb 2023 22:02:06 +0100 -Subject: [PATCH 04/25] LRNG - add switchable DRNG support - -The DRNG switch support allows replacing the DRNG mechanism of the -LRNG. The switching support rests on the interface definition of -include/linux/lrng.h. A new DRNG is implemented by filling in the -interface defined in this header file. - -In addition to the DRNG, the extension also has to provide a hash -implementation that is used to hash the entropy pool for random number -extraction. - -Note: It is permissible to implement a DRNG whose operations may sleep. -However, the hash function must not sleep. - -The switchable DRNG support allows replacing the DRNG at runtime. -However, only one DRNG extension is allowed to be loaded at any given -time. Before replacing it with another DRNG implementation, the possibly -existing DRNG extension must be unloaded. - -The switchable DRNG extension activates the new DRNG during load time. -It is expected, however, that such a DRNG switch would be done only once -by an administrator to load the intended DRNG implementation. - -It is permissible to compile DRNG extensions either as kernel modules or -statically. The initialization of the DRNG extension should be performed -with a late_initcall to ensure the extension is available when user -space starts but after all other initialization completed. -The initialization is performed by registering the function call data -structure with the lrng_set_drng_cb function. In order to unload the -DRNG extension, lrng_set_drng_cb must be invoked with the NULL -parameter. - -The DRNG extension should always provide a security strength that is at -least as strong as LRNG_DRNG_SECURITY_STRENGTH_BITS. - -The hash extension must not sleep and must not maintain a separate -state. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 8 +- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_switch.c | 286 ++++++++++++++++++++++++++++++++ - 3 files changed, 291 insertions(+), 4 deletions(-) - create mode 100644 drivers/char/lrng/lrng_switch.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -629,10 +629,10 @@ config LRNG_DRNG_CHACHA20 - # tristate - # depends on CRYPTO - # select CRYPTO_RNG --# --# config LRNG_SWITCH --# bool --# -+ -+config LRNG_SWITCH -+ bool -+ - # menuconfig LRNG_SWITCH_HASH - # bool "Support conditioning hash runtime switching" - # select LRNG_SWITCH ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -11,4 +11,5 @@ obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o - obj-$(CONFIG_SYSCTL) += lrng_proc.o - obj-$(CONFIG_NUMA) += lrng_numa.o - -+obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o - obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_switch.c -@@ -0,0 +1,286 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG DRNG switching support -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+ -+#include "lrng_es_aux.h" -+#include "lrng_es_mgr.h" -+#include "lrng_interface_dev_common.h" -+#include "lrng_numa.h" -+ -+static int __maybe_unused -+lrng_hash_switch(struct lrng_drng *drng_store, const void *cb, int node) -+{ -+ const struct lrng_hash_cb *new_cb = (const struct lrng_hash_cb *)cb; -+ const struct lrng_hash_cb *old_cb = drng_store->hash_cb; -+ unsigned long flags; -+ u32 i; -+ void *new_hash, *old_hash; -+ int ret; -+ -+ if (node == -1) -+ return 0; -+ -+ new_hash = new_cb->hash_alloc(); -+ old_hash = drng_store->hash; -+ -+ if (IS_ERR(new_hash)) { -+ pr_warn("could not allocate new LRNG pool hash (%ld)\n", -+ PTR_ERR(new_hash)); -+ return PTR_ERR(new_hash); -+ } -+ -+ if (new_cb->hash_digestsize(new_hash) > LRNG_MAX_DIGESTSIZE) { -+ pr_warn("digest size of newly requested hash too large\n"); -+ new_cb->hash_dealloc(new_hash); -+ return -EINVAL; -+ } -+ -+ write_lock_irqsave(&drng_store->hash_lock, flags); -+ -+ /* Trigger the switch for each entropy source */ -+ for_each_lrng_es(i) { -+ if (!lrng_es[i]->switch_hash) -+ continue; -+ ret = lrng_es[i]->switch_hash(drng_store, node, new_cb, -+ new_hash, old_cb); -+ if (ret) { -+ u32 j; -+ -+ /* Revert all already executed operations */ -+ for (j = 0; j < i; j++) { -+ if (!lrng_es[j]->switch_hash) -+ continue; -+ WARN_ON(lrng_es[j]->switch_hash(drng_store, -+ node, old_cb, -+ old_hash, -+ new_cb)); -+ } -+ goto err; -+ } -+ } -+ -+ drng_store->hash = new_hash; -+ drng_store->hash_cb = new_cb; -+ old_cb->hash_dealloc(old_hash); -+ pr_info("Conditioning function allocated for DRNG for NUMA node %d\n", -+ node); -+ -+err: -+ write_unlock_irqrestore(&drng_store->hash_lock, flags); -+ return ret; -+} -+ -+static int __maybe_unused -+lrng_drng_switch(struct lrng_drng *drng_store, const void *cb, int node) -+{ -+ const struct lrng_drng_cb *new_cb = (const struct lrng_drng_cb *)cb; -+ const struct lrng_drng_cb *old_cb = drng_store->drng_cb; -+ int ret; -+ u8 seed[LRNG_DRNG_SECURITY_STRENGTH_BYTES]; -+ void *new_drng = new_cb->drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES); -+ void *old_drng = drng_store->drng; -+ u32 current_security_strength; -+ bool reset_drng = !lrng_get_available(); -+ -+ if (IS_ERR(new_drng)) { -+ pr_warn("could not allocate new DRNG for NUMA node %d (%ld)\n", -+ node, PTR_ERR(new_drng)); -+ return PTR_ERR(new_drng); -+ } -+ -+ current_security_strength = lrng_security_strength(); -+ mutex_lock(&drng_store->lock); -+ -+ /* -+ * Pull from existing DRNG to seed new DRNG regardless of seed status -+ * of old DRNG -- the entropy state for the DRNG is left unchanged which -+ * implies that als the new DRNG is reseeded when deemed necessary. This -+ * seeding of the new DRNG shall only ensure that the new DRNG has the -+ * same entropy as the old DRNG. -+ */ -+ ret = old_cb->drng_generate(old_drng, seed, sizeof(seed)); -+ mutex_unlock(&drng_store->lock); -+ -+ if (ret < 0) { -+ reset_drng = true; -+ pr_warn("getting random data from DRNG failed for NUMA node %d (%d)\n", -+ node, ret); -+ } else { -+ /* seed new DRNG with data */ -+ ret = new_cb->drng_seed(new_drng, seed, ret); -+ memzero_explicit(seed, sizeof(seed)); -+ if (ret < 0) { -+ reset_drng = true; -+ pr_warn("seeding of new DRNG failed for NUMA node %d (%d)\n", -+ node, ret); -+ } else { -+ pr_debug("seeded new DRNG of NUMA node %d instance from old DRNG instance\n", -+ node); -+ } -+ } -+ -+ mutex_lock(&drng_store->lock); -+ -+ if (reset_drng) -+ lrng_drng_reset(drng_store); -+ -+ drng_store->drng = new_drng; -+ drng_store->drng_cb = new_cb; -+ -+ /* Reseed if previous LRNG security strength was insufficient */ -+ if (current_security_strength < lrng_security_strength()) -+ drng_store->force_reseed = true; -+ -+ /* Force oversampling seeding as we initialize DRNG */ -+ if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) -+ lrng_unset_fully_seeded(drng_store); -+ -+ if (lrng_state_min_seeded()) -+ lrng_set_entropy_thresh(lrng_get_seed_entropy_osr( -+ drng_store->fully_seeded)); -+ -+ old_cb->drng_dealloc(old_drng); -+ -+ pr_info("DRNG of NUMA node %d switched\n", node); -+ -+ mutex_unlock(&drng_store->lock); -+ return ret; -+} -+ -+/* -+ * Switch the existing DRNG and hash instances with new using the new crypto -+ * callbacks. The caller must hold the lrng_crypto_cb_update lock. -+ */ -+static int lrng_switch(const void *cb, -+ int (*switcher)(struct lrng_drng *drng_store, -+ const void *cb, int node)) -+{ -+ struct lrng_drng **lrng_drng = lrng_drng_instances(); -+ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ struct lrng_drng *lrng_drng_pr = lrng_drng_pr_instance(); -+ int ret = 0; -+ -+ if (lrng_drng) { -+ u32 node; -+ -+ for_each_online_node(node) { -+ if (lrng_drng[node]) -+ ret |= switcher(lrng_drng[node], cb, node); -+ } -+ } else { -+ ret |= switcher(lrng_drng_init, cb, 0); -+ } -+ -+ ret |= switcher(lrng_drng_pr, cb, -1); -+ -+ return ret; -+} -+ -+/* -+ * lrng_set_drng_cb - Register new cryptographic callback functions for DRNG -+ * The registering implies that all old DRNG states are replaced with new -+ * DRNG states. -+ * -+ * drng_cb: Callback functions to be registered -- if NULL, use the default -+ * callbacks defined at compile time. -+ * -+ * Return: -+ * * 0 on success -+ * * < 0 on error -+ */ -+int lrng_set_drng_cb(const struct lrng_drng_cb *drng_cb) -+{ -+ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ int ret; -+ -+ if (!IS_ENABLED(CONFIG_LRNG_SWITCH_DRNG)) -+ return -EOPNOTSUPP; -+ -+ if (!drng_cb) -+ drng_cb = lrng_default_drng_cb; -+ -+ mutex_lock(&lrng_crypto_cb_update); -+ -+ /* -+ * If a callback other than the default is set, allow it only to be -+ * set back to the default callback. This ensures that multiple -+ * different callbacks can be registered at the same time. If a -+ * callback different from the current callback and the default -+ * callback shall be set, the current callback must be deregistered -+ * (e.g. the kernel module providing it must be unloaded) and the new -+ * implementation can be registered. -+ */ -+ if ((drng_cb != lrng_default_drng_cb) && -+ (lrng_drng_init->drng_cb != lrng_default_drng_cb)) { -+ pr_warn("disallow setting new DRNG callbacks, unload the old callbacks first!\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ ret = lrng_switch(drng_cb, lrng_drng_switch); -+ /* The switch may imply new entropy due to larger DRNG sec strength. */ -+ if (!ret) -+ lrng_es_add_entropy(); -+ -+out: -+ mutex_unlock(&lrng_crypto_cb_update); -+ return ret; -+} -+EXPORT_SYMBOL(lrng_set_drng_cb); -+ -+/* -+ * lrng_set_hash_cb - Register new cryptographic callback functions for hash -+ * The registering implies that all old hash states are replaced with new -+ * hash states. -+ * -+ * @hash_cb: Callback functions to be registered -- if NULL, use the default -+ * callbacks defined at compile time. -+ * -+ * Return: -+ * * 0 on success -+ * * < 0 on error -+ */ -+int lrng_set_hash_cb(const struct lrng_hash_cb *hash_cb) -+{ -+ struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ int ret; -+ -+ if (!IS_ENABLED(CONFIG_LRNG_SWITCH_HASH)) -+ return -EOPNOTSUPP; -+ -+ if (!hash_cb) -+ hash_cb = lrng_default_hash_cb; -+ -+ mutex_lock(&lrng_crypto_cb_update); -+ -+ /* Comment from lrng_set_drng_cb applies. */ -+ if ((hash_cb != lrng_default_hash_cb) && -+ (lrng_drng_init->hash_cb != lrng_default_hash_cb)) { -+ pr_warn("disallow setting new hash callbacks, unload the old callbacks first!\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ ret = lrng_switch(hash_cb, lrng_hash_switch); -+ /* -+ * The switch may imply new entropy due to larger digest size. But -+ * it may also offer more room in the aux pool which means we ping -+ * any waiting entropy providers. -+ */ -+ if (!ret) { -+ lrng_es_add_entropy(); -+ lrng_writer_wakeup(); -+ } -+ -+out: -+ mutex_unlock(&lrng_crypto_cb_update); -+ return ret; -+} -+EXPORT_SYMBOL(lrng_set_hash_cb); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch deleted file mode 100644 index c9d5dd278..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch +++ /dev/null @@ -1,221 +0,0 @@ -From 5888ed6bedc139ed500bf9fe46761e2f0838d987 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 16:01:44 +0200 -Subject: [PATCH 05/25] LRNG - add common generic hash support - -The LRNG switchable DRNG support also allows the replacement of the hash -implementation used as conditioning component. The common generic hash -support code provides the required callbacks using the synchronous hash -implementations of the kernel crypto API. - -All synchronous hash implementations supported by the kernel crypto API -can be used as part of the LRNG with this generic support. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 40 ++++---- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_hash_kcapi.c | 140 ++++++++++++++++++++++++++++ - 3 files changed, 161 insertions(+), 20 deletions(-) - create mode 100644 drivers/char/lrng/lrng_hash_kcapi.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -633,26 +633,26 @@ config LRNG_DRNG_CHACHA20 - config LRNG_SWITCH - bool - --# menuconfig LRNG_SWITCH_HASH --# bool "Support conditioning hash runtime switching" --# select LRNG_SWITCH --# help --# The LRNG uses a default message digest. With this --# configuration option other message digests can be selected --# and loaded at runtime. --# --# if LRNG_SWITCH_HASH --# --# config LRNG_HASH_KCAPI --# tristate "Kernel crypto API hashing support for LRNG" --# select CRYPTO_HASH --# select CRYPTO_SHA512 --# help --# Enable the kernel crypto API support for entropy compression --# and conditioning functions. --# --# endif # LRNG_SWITCH_HASH --# -+menuconfig LRNG_SWITCH_HASH -+ bool "Support conditioning hash runtime switching" -+ select LRNG_SWITCH -+ help -+ The LRNG uses a default message digest. With this -+ configuration option other message digests can be selected -+ and loaded at runtime. -+ -+if LRNG_SWITCH_HASH -+ -+config LRNG_HASH_KCAPI -+ tristate "Kernel crypto API hashing support for LRNG" -+ select CRYPTO_HASH -+ select CRYPTO_SHA512 -+ help -+ Enable the kernel crypto API support for entropy compression -+ and conditioning functions. -+ -+endif # LRNG_SWITCH_HASH -+ - # menuconfig LRNG_SWITCH_DRNG - # bool "Support DRNG runtime switching" - # select LRNG_SWITCH ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -12,4 +12,5 @@ obj-$(CONFIG_SYSCTL) += lrng_proc.o - obj-$(CONFIG_NUMA) += lrng_numa.o - - obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o -+obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_hash_kcapi.o - obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_hash_kcapi.c -@@ -0,0 +1,140 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * Backend for providing the hash primitive using the kernel crypto API. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+ -+ -+static char *lrng_hash_name = "sha512"; -+ -+/* The parameter must be r/o in sysfs as otherwise races appear. */ -+module_param(lrng_hash_name, charp, 0444); -+MODULE_PARM_DESC(lrng_hash_name, "Kernel crypto API hash name"); -+ -+struct lrng_hash_info { -+ struct crypto_shash *tfm; -+}; -+ -+static const char *lrng_kcapi_hash_name(void) -+{ -+ return lrng_hash_name; -+} -+ -+static void _lrng_kcapi_hash_free(struct lrng_hash_info *lrng_hash) -+{ -+ struct crypto_shash *tfm = lrng_hash->tfm; -+ -+ crypto_free_shash(tfm); -+ kfree(lrng_hash); -+} -+ -+static void *lrng_kcapi_hash_alloc(const char *name) -+{ -+ struct lrng_hash_info *lrng_hash; -+ struct crypto_shash *tfm; -+ int ret; -+ -+ if (!name) { -+ pr_err("Hash name missing\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ tfm = crypto_alloc_shash(name, 0, 0); -+ if (IS_ERR(tfm)) { -+ pr_err("could not allocate hash %s\n", name); -+ return ERR_CAST(tfm); -+ } -+ -+ ret = sizeof(struct lrng_hash_info); -+ lrng_hash = kmalloc(ret, GFP_KERNEL); -+ if (!lrng_hash) { -+ crypto_free_shash(tfm); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ lrng_hash->tfm = tfm; -+ -+ pr_info("Hash %s allocated\n", name); -+ -+ return lrng_hash; -+} -+ -+static void *lrng_kcapi_hash_name_alloc(void) -+{ -+ return lrng_kcapi_hash_alloc(lrng_kcapi_hash_name()); -+} -+ -+static u32 lrng_kcapi_hash_digestsize(void *hash) -+{ -+ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; -+ struct crypto_shash *tfm = lrng_hash->tfm; -+ -+ return crypto_shash_digestsize(tfm); -+} -+ -+static void lrng_kcapi_hash_dealloc(void *hash) -+{ -+ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; -+ -+ _lrng_kcapi_hash_free(lrng_hash); -+ pr_info("Hash deallocated\n"); -+} -+ -+static int lrng_kcapi_hash_init(struct shash_desc *shash, void *hash) -+{ -+ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; -+ struct crypto_shash *tfm = lrng_hash->tfm; -+ -+ shash->tfm = tfm; -+ return crypto_shash_init(shash); -+} -+ -+static int lrng_kcapi_hash_update(struct shash_desc *shash, const u8 *inbuf, -+ u32 inbuflen) -+{ -+ return crypto_shash_update(shash, inbuf, inbuflen); -+} -+ -+static int lrng_kcapi_hash_final(struct shash_desc *shash, u8 *digest) -+{ -+ return crypto_shash_final(shash, digest); -+} -+ -+static void lrng_kcapi_hash_zero(struct shash_desc *shash) -+{ -+ shash_desc_zero(shash); -+} -+ -+static const struct lrng_hash_cb lrng_kcapi_hash_cb = { -+ .hash_name = lrng_kcapi_hash_name, -+ .hash_alloc = lrng_kcapi_hash_name_alloc, -+ .hash_dealloc = lrng_kcapi_hash_dealloc, -+ .hash_digestsize = lrng_kcapi_hash_digestsize, -+ .hash_init = lrng_kcapi_hash_init, -+ .hash_update = lrng_kcapi_hash_update, -+ .hash_final = lrng_kcapi_hash_final, -+ .hash_desc_zero = lrng_kcapi_hash_zero, -+}; -+ -+static int __init lrng_kcapi_init(void) -+{ -+ return lrng_set_hash_cb(&lrng_kcapi_hash_cb); -+} -+ -+static void __exit lrng_kcapi_exit(void) -+{ -+ lrng_set_hash_cb(NULL); -+} -+ -+late_initcall(lrng_kcapi_init); -+module_exit(lrng_kcapi_exit); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Stephan Mueller "); -+MODULE_DESCRIPTION("Entropy Source and DRNG Manager - Kernel crypto API hash backend"); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch deleted file mode 100644 index c6293a6c3..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 457a18d887ffb7555838e65505a6a8a72a5e0ae0 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Thu, 21 Mar 2024 14:17:33 +0100 -Subject: [PATCH 06/25] crypto: DRBG - externalize DRBG functions for LRNG - -This patch allows several DRBG functions to be called by the LRNG kernel -code paths outside the drbg.c file. - -Signed-off-by: Stephan Mueller ---- - crypto/drbg.c | 16 ++++++++++------ - include/crypto/drbg.h | 7 +++++++ - 2 files changed, 17 insertions(+), 6 deletions(-) - ---- a/crypto/drbg.c -+++ b/crypto/drbg.c -@@ -115,7 +115,7 @@ - * the SHA256 / AES 256 over other ciphers. Thus, the favored - * DRBGs are the latest entries in this array. - */ --static const struct drbg_core drbg_cores[] = { -+const struct drbg_core drbg_cores[] = { - #ifdef CONFIG_CRYPTO_DRBG_CTR - { - .flags = DRBG_CTR | DRBG_STRENGTH128, -@@ -192,6 +192,7 @@ static const struct drbg_core drbg_cores - }, - #endif /* CONFIG_CRYPTO_DRBG_HMAC */ - }; -+EXPORT_SYMBOL(drbg_cores); - - static int drbg_uninstantiate(struct drbg_state *drbg); - -@@ -207,7 +208,7 @@ static int drbg_uninstantiate(struct drb - * Return: normalized strength in *bytes* value or 32 as default - * to counter programming errors - */ --static inline unsigned short drbg_sec_strength(drbg_flag_t flags) -+unsigned short drbg_sec_strength(drbg_flag_t flags) - { - switch (flags & DRBG_STRENGTH_MASK) { - case DRBG_STRENGTH128: -@@ -220,6 +221,7 @@ static inline unsigned short drbg_sec_st - return 32; - } - } -+EXPORT_SYMBOL(drbg_sec_strength); - - /* - * FIPS 140-2 continuous self test for the noise source -@@ -1252,7 +1254,7 @@ out: - } - - /* Free all substructures in a DRBG state without the DRBG state structure */ --static inline void drbg_dealloc_state(struct drbg_state *drbg) -+void drbg_dealloc_state(struct drbg_state *drbg) - { - if (!drbg) - return; -@@ -1273,12 +1275,13 @@ static inline void drbg_dealloc_state(st - drbg->fips_primed = false; - } - } -+EXPORT_SYMBOL(drbg_dealloc_state); - - /* - * Allocate all sub-structures for a DRBG state. - * The DRBG state structure must already be allocated. - */ --static inline int drbg_alloc_state(struct drbg_state *drbg) -+int drbg_alloc_state(struct drbg_state *drbg) - { - int ret = -ENOMEM; - unsigned int sb_size = 0; -@@ -1359,6 +1362,7 @@ err: - drbg_dealloc_state(drbg); - return ret; - } -+EXPORT_SYMBOL(drbg_alloc_state); - - /************************************************************************* - * DRBG interface functions -@@ -1893,8 +1897,7 @@ out: - * - * return: flags - */ --static inline void drbg_convert_tfm_core(const char *cra_driver_name, -- int *coreref, bool *pr) -+void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, bool *pr) - { - int i = 0; - size_t start = 0; -@@ -1921,6 +1924,7 @@ static inline void drbg_convert_tfm_core - } - } - } -+EXPORT_SYMBOL(drbg_convert_tfm_core); - - static int drbg_kcapi_init(struct crypto_tfm *tfm) - { ---- a/include/crypto/drbg.h -+++ b/include/crypto/drbg.h -@@ -283,4 +283,11 @@ enum drbg_prefixes { - DRBG_PREFIX3 - }; - -+extern int drbg_alloc_state(struct drbg_state *drbg); -+extern void drbg_dealloc_state(struct drbg_state *drbg); -+extern void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, -+ bool *pr); -+extern const struct drbg_core drbg_cores[]; -+extern unsigned short drbg_sec_strength(drbg_flag_t flags); -+ - #endif /* _DRBG_H */ diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch deleted file mode 100644 index bf7dbdb15..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch +++ /dev/null @@ -1,327 +0,0 @@ -From a214000d457a567900e3b08bb22cae627633ba48 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Mon, 20 Feb 2023 22:22:25 +0100 -Subject: [PATCH 07/25] LRNG - add SP800-90A DRBG extension - -Using the LRNG switchable DRNG support, the SP800-90A DRBG extension is -implemented. - -The DRBG uses the kernel crypto API DRBG implementation. In addition, it -uses the kernel crypto API SHASH support to provide the hashing -operation. - -The DRBG supports the choice of either a CTR DRBG using AES-256, HMAC -DRBG with SHA-512 core or Hash DRBG with SHA-512 core. The used core can -be selected with the module parameter lrng_drbg_type. The default is the -CTR DRBG. - -When compiling the DRBG extension statically, the DRBG is loaded at -late_initcall stage which implies that with the start of user space, the -user space interfaces of getrandom(2), /dev/random and /dev/urandom -provide random data produced by an SP800-90A DRBG. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 78 ++++++------- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_drng_drbg.c | 179 +++++++++++++++++++++++++++++ - 3 files changed, 219 insertions(+), 39 deletions(-) - create mode 100644 drivers/char/lrng/lrng_drng_drbg.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -620,11 +620,11 @@ endmenu # "Specific DRNG seeding strateg - config LRNG_DRNG_CHACHA20 - tristate - --# config LRNG_DRBG --# tristate --# depends on CRYPTO --# select CRYPTO_DRBG_MENU --# -+config LRNG_DRBG -+ tristate -+ depends on CRYPTO -+ select CRYPTO_DRBG_MENU -+ - # config LRNG_DRNG_KCAPI - # tristate - # depends on CRYPTO -@@ -653,33 +653,33 @@ config LRNG_HASH_KCAPI - - endif # LRNG_SWITCH_HASH - --# menuconfig LRNG_SWITCH_DRNG --# bool "Support DRNG runtime switching" --# select LRNG_SWITCH --# help --# The LRNG uses a default DRNG With this configuration --# option other DRNGs or message digests can be selected and --# loaded at runtime. --# --# if LRNG_SWITCH_DRNG --# --# config LRNG_SWITCH_DRNG_CHACHA20 --# tristate "ChaCha20-based DRNG support for LRNG" --# depends on !LRNG_DFLT_DRNG_CHACHA20 --# select LRNG_DRNG_CHACHA20 --# help --# Enable the ChaCha20-based DRNG. This DRNG implementation --# does not depend on the kernel crypto API presence. --# --# config LRNG_SWITCH_DRBG --# tristate "SP800-90A support for the LRNG" --# depends on !LRNG_DFLT_DRNG_DRBG --# select LRNG_DRBG --# help --# Enable the SP800-90A DRBG support for the LRNG. Once the --# module is loaded, output from /dev/random, /dev/urandom, --# getrandom(2), or get_random_bytes_full is provided by a DRBG. --# -+menuconfig LRNG_SWITCH_DRNG -+ bool "Support DRNG runtime switching" -+ select LRNG_SWITCH -+ help -+ The LRNG uses a default DRNG With this configuration -+ option other DRNGs or message digests can be selected and -+ loaded at runtime. -+ -+if LRNG_SWITCH_DRNG -+ -+config LRNG_SWITCH_DRNG_CHACHA20 -+ tristate "ChaCha20-based DRNG support for LRNG" -+ depends on !LRNG_DFLT_DRNG_CHACHA20 -+ select LRNG_DRNG_CHACHA20 -+ help -+ Enable the ChaCha20-based DRNG. This DRNG implementation -+ does not depend on the kernel crypto API presence. -+ -+config LRNG_SWITCH_DRBG -+ tristate "SP800-90A support for the LRNG" -+ depends on !LRNG_DFLT_DRNG_DRBG -+ select LRNG_DRBG -+ help -+ Enable the SP800-90A DRBG support for the LRNG. Once the -+ module is loaded, output from /dev/random, /dev/urandom, -+ getrandom(2), or get_random_bytes_full is provided by a DRBG. -+ - # config LRNG_SWITCH_DRNG_KCAPI - # tristate "Kernel Crypto API support for the LRNG" - # depends on !LRNG_DFLT_DRNG_KCAPI -@@ -691,8 +691,8 @@ endif # LRNG_SWITCH_HASH - # LRNG. Once the module is loaded, output from /dev/random, - # /dev/urandom, getrandom(2), or get_random_bytes is - # provided by the selected kernel crypto API RNG. --# --# endif # LRNG_SWITCH_DRNG -+ -+endif # LRNG_SWITCH_DRNG - - choice - prompt "LRNG Default DRNG" -@@ -707,11 +707,11 @@ choice - bool "ChaCha20-based DRNG" - select LRNG_DRNG_CHACHA20 - --# config LRNG_DFLT_DRNG_DRBG --# depends on RANDOM_DEFAULT_IMPL --# bool "SP800-90A DRBG" --# select LRNG_DRBG --# -+ config LRNG_DFLT_DRNG_DRBG -+ depends on RANDOM_DEFAULT_IMPL -+ bool "SP800-90A DRBG" -+ select LRNG_DRBG -+ - # config LRNG_DFLT_DRNG_KCAPI - # depends on RANDOM_DEFAULT_IMPL - # bool "Kernel Crypto API DRNG" ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -14,3 +14,4 @@ obj-$(CONFIG_NUMA) += lrng_numa.o - obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o - obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_hash_kcapi.o - obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o -+obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_drbg.c -@@ -0,0 +1,179 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * Backend for the LRNG providing the cryptographic primitives using the -+ * kernel crypto API and its DRBG. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+ -+#include "lrng_drng_drbg.h" -+ -+/* -+ * Define a DRBG plus a hash / MAC used to extract data from the entropy pool. -+ * For LRNG_HASH_NAME you can use a hash or a MAC (HMAC or CMAC) of your choice -+ * (Note, you should use the suggested selections below -- using SHA-1 or MD5 -+ * is not wise). The idea is that the used cipher primitive can be selected to -+ * be the same as used for the DRBG. I.e. the LRNG only uses one cipher -+ * primitive using the same cipher implementation with the options offered in -+ * the following. This means, if the CTR DRBG is selected and AES-NI is present, -+ * both the CTR DRBG and the selected cmac(aes) use AES-NI. -+ * -+ * The security strengths of the DRBGs are all 256 bits according to -+ * SP800-57 section 5.6.1. -+ * -+ * This definition is allowed to be changed. -+ */ -+#ifdef CONFIG_CRYPTO_DRBG_CTR -+static unsigned int lrng_drbg_type = 0; -+#elif defined CONFIG_CRYPTO_DRBG_HMAC -+static unsigned int lrng_drbg_type = 1; -+#elif defined CONFIG_CRYPTO_DRBG_HASH -+static unsigned int lrng_drbg_type = 2; -+#else -+#error "Unknown DRBG in use" -+#endif -+ -+/* The parameter must be r/o in sysfs as otherwise races appear. */ -+module_param(lrng_drbg_type, uint, 0444); -+MODULE_PARM_DESC(lrng_drbg_type, "DRBG type used for LRNG (0->CTR_DRBG, 1->HMAC_DRBG, 2->Hash_DRBG)"); -+ -+struct lrng_drbg { -+ const char *hash_name; -+ const char *drbg_core; -+}; -+ -+static const struct lrng_drbg lrng_drbg_types[] = { -+ { /* CTR_DRBG with AES-256 using derivation function */ -+ .drbg_core = "drbg_nopr_ctr_aes256", -+ }, { /* HMAC_DRBG with SHA-512 */ -+ .drbg_core = "drbg_nopr_hmac_sha512", -+ }, { /* Hash_DRBG with SHA-512 using derivation function */ -+ .drbg_core = "drbg_nopr_sha512" -+ } -+}; -+ -+static int lrng_drbg_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen) -+{ -+ struct drbg_state *drbg = (struct drbg_state *)drng; -+ LIST_HEAD(seedlist); -+ struct drbg_string data; -+ int ret; -+ -+ drbg_string_fill(&data, inbuf, inbuflen); -+ list_add_tail(&data.list, &seedlist); -+ ret = drbg->d_ops->update(drbg, &seedlist, drbg->seeded); -+ -+ if (ret >= 0) -+ drbg->seeded = DRBG_SEED_STATE_FULL; -+ -+ return ret; -+} -+ -+static int lrng_drbg_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen) -+{ -+ struct drbg_state *drbg = (struct drbg_state *)drng; -+ -+ return drbg->d_ops->generate(drbg, outbuf, outbuflen, NULL); -+} -+ -+static void *lrng_drbg_drng_alloc(u32 sec_strength) -+{ -+ struct drbg_state *drbg; -+ int coreref = -1; -+ bool pr = false; -+ int ret; -+ -+ drbg_convert_tfm_core(lrng_drbg_types[lrng_drbg_type].drbg_core, -+ &coreref, &pr); -+ if (coreref < 0) -+ return ERR_PTR(-EFAULT); -+ -+ drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); -+ if (!drbg) -+ return ERR_PTR(-ENOMEM); -+ -+ drbg->core = &drbg_cores[coreref]; -+ drbg->seeded = DRBG_SEED_STATE_UNSEEDED; -+ ret = drbg_alloc_state(drbg); -+ if (ret) -+ goto err; -+ -+ if (sec_strength > drbg_sec_strength(drbg->core->flags)) { -+ pr_err("Security strength of DRBG (%u bits) lower than requested by LRNG (%u bits)\n", -+ drbg_sec_strength(drbg->core->flags) * 8, -+ sec_strength * 8); -+ goto dealloc; -+ } -+ -+ if (sec_strength < drbg_sec_strength(drbg->core->flags)) -+ pr_warn("Security strength of DRBG (%u bits) higher than requested by LRNG (%u bits)\n", -+ drbg_sec_strength(drbg->core->flags) * 8, -+ sec_strength * 8); -+ -+ pr_info("DRBG with %s core allocated\n", drbg->core->backend_cra_name); -+ -+ return drbg; -+ -+dealloc: -+ if (drbg->d_ops) -+ drbg->d_ops->crypto_fini(drbg); -+ drbg_dealloc_state(drbg); -+err: -+ kfree(drbg); -+ return ERR_PTR(-EINVAL); -+} -+ -+static void lrng_drbg_drng_dealloc(void *drng) -+{ -+ struct drbg_state *drbg = (struct drbg_state *)drng; -+ -+ if (drbg && drbg->d_ops) -+ drbg->d_ops->crypto_fini(drbg); -+ drbg_dealloc_state(drbg); -+ kfree_sensitive(drbg); -+ pr_info("DRBG deallocated\n"); -+} -+ -+static const char *lrng_drbg_name(void) -+{ -+ return lrng_drbg_types[lrng_drbg_type].drbg_core; -+} -+ -+const struct lrng_drng_cb lrng_drbg_cb = { -+ .drng_name = lrng_drbg_name, -+ .drng_alloc = lrng_drbg_drng_alloc, -+ .drng_dealloc = lrng_drbg_drng_dealloc, -+ .drng_seed = lrng_drbg_drng_seed_helper, -+ .drng_generate = lrng_drbg_drng_generate_helper, -+}; -+ -+#ifndef CONFIG_LRNG_DFLT_DRNG_DRBG -+static int __init lrng_drbg_init(void) -+{ -+ if (lrng_drbg_type >= ARRAY_SIZE(lrng_drbg_types)) { -+ pr_err("lrng_drbg_type parameter too large (given %u - max: %lu)", -+ lrng_drbg_type, -+ (unsigned long)ARRAY_SIZE(lrng_drbg_types) - 1); -+ return -EAGAIN; -+ } -+ return lrng_set_drng_cb(&lrng_drbg_cb); -+} -+ -+static void __exit lrng_drbg_exit(void) -+{ -+ lrng_set_drng_cb(NULL); -+} -+ -+late_initcall(lrng_drbg_init); -+module_exit(lrng_drbg_exit); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Stephan Mueller "); -+MODULE_DESCRIPTION("Entropy Source and DRNG Manager - SP800-90A DRBG backend"); -+#endif /* CONFIG_LRNG_DFLT_DRNG_DRBG */ diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch deleted file mode 100644 index 8e81dce1f..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch +++ /dev/null @@ -1,305 +0,0 @@ -From 983913a3320a0ae53a430234be5fc5af1017f7af Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Mon, 20 Feb 2023 22:23:59 +0100 -Subject: [PATCH 08/25] LRNG - add kernel crypto API PRNG extension - -Add runtime-pluggable support for all PRNGs that are accessible via -the kernel crypto API, including hardware PRNGs. The PRNG is selected -with the module parameter drng_name where the name must be one that the -kernel crypto API can resolve into an RNG. - -This allows using of the kernel crypto API PRNG implementations that -provide an interface to hardware PRNGs. Using this extension, -the LRNG uses the hardware PRNGs to generate random numbers. An -example is the S390 CPACF support providing such a PRNG. - -The hash is provided by a kernel crypto API SHASH whose digest size -complies with the seedsize of the PRNG. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 38 ++--- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_drng_kcapi.c | 208 ++++++++++++++++++++++++++++ - 3 files changed, 228 insertions(+), 19 deletions(-) - create mode 100644 drivers/char/lrng/lrng_drng_kcapi.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -625,10 +625,10 @@ config LRNG_DRBG - depends on CRYPTO - select CRYPTO_DRBG_MENU - --# config LRNG_DRNG_KCAPI --# tristate --# depends on CRYPTO --# select CRYPTO_RNG -+config LRNG_DRNG_KCAPI -+ tristate -+ depends on CRYPTO -+ select CRYPTO_RNG - - config LRNG_SWITCH - bool -@@ -680,17 +680,17 @@ config LRNG_SWITCH_DRBG - module is loaded, output from /dev/random, /dev/urandom, - getrandom(2), or get_random_bytes_full is provided by a DRBG. - --# config LRNG_SWITCH_DRNG_KCAPI --# tristate "Kernel Crypto API support for the LRNG" --# depends on !LRNG_DFLT_DRNG_KCAPI --# depends on !LRNG_SWITCH_DRBG --# select LRNG_DRNG_KCAPI --# help --# Enable the support for generic pseudo-random number --# generators offered by the kernel crypto API with the --# LRNG. Once the module is loaded, output from /dev/random, --# /dev/urandom, getrandom(2), or get_random_bytes is --# provided by the selected kernel crypto API RNG. -+config LRNG_SWITCH_DRNG_KCAPI -+ tristate "Kernel Crypto API support for the LRNG" -+ depends on !LRNG_DFLT_DRNG_KCAPI -+ depends on !LRNG_SWITCH_DRBG -+ select LRNG_DRNG_KCAPI -+ help -+ Enable the support for generic pseudo-random number -+ generators offered by the kernel crypto API with the -+ LRNG. Once the module is loaded, output from /dev/random, -+ /dev/urandom, getrandom(2), or get_random_bytes is -+ provided by the selected kernel crypto API RNG. - - endif # LRNG_SWITCH_DRNG - -@@ -712,10 +712,10 @@ choice - bool "SP800-90A DRBG" - select LRNG_DRBG - --# config LRNG_DFLT_DRNG_KCAPI --# depends on RANDOM_DEFAULT_IMPL --# bool "Kernel Crypto API DRNG" --# select LRNG_DRNG_KCAPI -+ config LRNG_DFLT_DRNG_KCAPI -+ depends on RANDOM_DEFAULT_IMPL -+ bool "Kernel Crypto API DRNG" -+ select LRNG_DRNG_KCAPI - endchoice - - # menuconfig LRNG_TESTING_MENU ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -15,3 +15,4 @@ obj-$(CONFIG_LRNG_SWITCH) += lrng_switc - obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_hash_kcapi.o - obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o - obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o -+obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_drng_kcapi.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_kcapi.c -@@ -0,0 +1,208 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * Backend for the LRNG providing the cryptographic primitives using the -+ * kernel crypto API. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_drng_kcapi.h" -+ -+static char *drng_name = NULL; -+module_param(drng_name, charp, 0444); -+MODULE_PARM_DESC(drng_name, "Kernel crypto API name of DRNG"); -+ -+static char *seed_hash = NULL; -+module_param(seed_hash, charp, 0444); -+MODULE_PARM_DESC(seed_hash, -+ "Kernel crypto API name of hash with output size equal to seedsize of DRNG to bring seed string to the size required by the DRNG"); -+ -+struct lrng_drng_info { -+ struct crypto_rng *kcapi_rng; -+ struct crypto_shash *hash_tfm; -+}; -+ -+static int lrng_kcapi_drng_seed_helper(void *drng, const u8 *inbuf, -+ u32 inbuflen) -+{ -+ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng; -+ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; -+ struct crypto_shash *hash_tfm = lrng_drng_info->hash_tfm; -+ SHASH_DESC_ON_STACK(shash, hash_tfm); -+ u32 digestsize; -+ u8 digest[HASH_MAX_DIGESTSIZE] __aligned(8); -+ int ret; -+ -+ if (!hash_tfm) -+ return crypto_rng_reset(kcapi_rng, inbuf, inbuflen); -+ -+ shash->tfm = hash_tfm; -+ digestsize = crypto_shash_digestsize(hash_tfm); -+ -+ ret = crypto_shash_digest(shash, inbuf, inbuflen, digest); -+ shash_desc_zero(shash); -+ if (ret) -+ return ret; -+ -+ ret = crypto_rng_reset(kcapi_rng, digest, digestsize); -+ if (ret) -+ return ret; -+ -+ memzero_explicit(digest, digestsize); -+ return 0; -+} -+ -+static int lrng_kcapi_drng_generate_helper(void *drng, u8 *outbuf, -+ u32 outbuflen) -+{ -+ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng; -+ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; -+ int ret = crypto_rng_get_bytes(kcapi_rng, outbuf, outbuflen); -+ -+ if (ret < 0) -+ return ret; -+ -+ return outbuflen; -+} -+ -+static void *lrng_kcapi_drng_alloc(u32 sec_strength) -+{ -+ struct lrng_drng_info *lrng_drng_info; -+ struct crypto_rng *kcapi_rng; -+ u32 time = random_get_entropy(); -+ int seedsize, rv; -+ void *ret = ERR_PTR(-ENOMEM); -+ -+ if (!drng_name) { -+ pr_err("DRNG name missing\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ if (!memcmp(drng_name, "stdrng", 6) || -+ !memcmp(drng_name, "lrng", 4) || -+ !memcmp(drng_name, "drbg", 4) || -+ !memcmp(drng_name, "jitterentropy_rng", 17)) { -+ pr_err("Refusing to load the requested random number generator\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ lrng_drng_info = kzalloc(sizeof(*lrng_drng_info), GFP_KERNEL); -+ if (!lrng_drng_info) -+ return ERR_PTR(-ENOMEM); -+ -+ kcapi_rng = crypto_alloc_rng(drng_name, 0, 0); -+ if (IS_ERR(kcapi_rng)) { -+ pr_err("DRNG %s cannot be allocated\n", drng_name); -+ ret = ERR_CAST(kcapi_rng); -+ goto free; -+ } -+ -+ lrng_drng_info->kcapi_rng = kcapi_rng; -+ -+ seedsize = crypto_rng_seedsize(kcapi_rng); -+ if (seedsize) { -+ struct crypto_shash *hash_tfm; -+ -+ if (!seed_hash) { -+ switch (seedsize) { -+ case 32: -+ seed_hash = "sha256"; -+ break; -+ case 48: -+ seed_hash = "sha384"; -+ break; -+ case 64: -+ seed_hash = "sha512"; -+ break; -+ default: -+ pr_err("Seed size %d cannot be processed\n", -+ seedsize); -+ goto dealloc; -+ } -+ } -+ -+ hash_tfm = crypto_alloc_shash(seed_hash, 0, 0); -+ if (IS_ERR(hash_tfm)) { -+ ret = ERR_CAST(hash_tfm); -+ goto dealloc; -+ } -+ -+ if (seedsize != crypto_shash_digestsize(hash_tfm)) { -+ pr_err("Seed hash output size not equal to DRNG seed size\n"); -+ crypto_free_shash(hash_tfm); -+ ret = ERR_PTR(-EINVAL); -+ goto dealloc; -+ } -+ -+ lrng_drng_info->hash_tfm = hash_tfm; -+ -+ pr_info("Seed hash %s allocated\n", seed_hash); -+ } -+ -+ rv = lrng_kcapi_drng_seed_helper(lrng_drng_info, (u8 *)(&time), -+ sizeof(time)); -+ if (rv) { -+ ret = ERR_PTR(rv); -+ goto dealloc; -+ } -+ -+ pr_info("Kernel crypto API DRNG %s allocated\n", drng_name); -+ -+ return lrng_drng_info; -+ -+dealloc: -+ crypto_free_rng(kcapi_rng); -+free: -+ kfree(lrng_drng_info); -+ return ret; -+} -+ -+static void lrng_kcapi_drng_dealloc(void *drng) -+{ -+ struct lrng_drng_info *lrng_drng_info = (struct lrng_drng_info *)drng; -+ struct crypto_rng *kcapi_rng = lrng_drng_info->kcapi_rng; -+ -+ crypto_free_rng(kcapi_rng); -+ if (lrng_drng_info->hash_tfm) -+ crypto_free_shash(lrng_drng_info->hash_tfm); -+ kfree(lrng_drng_info); -+ pr_info("DRNG %s deallocated\n", drng_name); -+} -+ -+static const char *lrng_kcapi_drng_name(void) -+{ -+ return drng_name; -+} -+ -+const struct lrng_drng_cb lrng_kcapi_drng_cb = { -+ .drng_name = lrng_kcapi_drng_name, -+ .drng_alloc = lrng_kcapi_drng_alloc, -+ .drng_dealloc = lrng_kcapi_drng_dealloc, -+ .drng_seed = lrng_kcapi_drng_seed_helper, -+ .drng_generate = lrng_kcapi_drng_generate_helper, -+}; -+ -+#ifndef CONFIG_LRNG_DFLT_DRNG_KCAPI -+static int __init lrng_kcapi_init(void) -+{ -+ return lrng_set_drng_cb(&lrng_kcapi_drng_cb); -+} -+static void __exit lrng_kcapi_exit(void) -+{ -+ lrng_set_drng_cb(NULL); -+} -+ -+late_initcall(lrng_kcapi_init); -+module_exit(lrng_kcapi_exit); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Stephan Mueller "); -+MODULE_DESCRIPTION("Entropy Source and DRNG Manager - kernel crypto API DRNG backend"); -+#endif /* CONFIG_LRNG_DFLT_DRNG_KCAPI */ diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch deleted file mode 100644 index 052474bcd..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 6b2fe42773ad58268176809bb2030acbf8395a02 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Mon, 20 Feb 2023 22:05:24 +0100 -Subject: [PATCH 09/25] LRNG - add atomic DRNG implementation - -The atomic DRNG implementation supports the in-kernel use cases which -request random numbers in atomic contexts. It uses the ChaCha20 DRNG -which is a code base that does not sleep and it provides an interface to -callers that does not sleep. This code will only be compiled when the -LRNG enables the in-kernel drop-in replacement APIs for the existing -random.c code base. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_drng_atomic.c | 130 +++++++++++++++++++++++++++ - 2 files changed, 131 insertions(+) - create mode 100644 drivers/char/lrng/lrng_drng_atomic.c - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -16,3 +16,4 @@ obj-$(CONFIG_LRNG_HASH_KCAPI) += lrng_h - obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng_drng_chacha20.o - obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o - obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_drng_kcapi.o -+obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_drng_atomic.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_drng_atomic.c -@@ -0,0 +1,130 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG DRNG for atomic contexts -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+ -+#include "lrng_drng_atomic.h" -+#include "lrng_drng_chacha20.h" -+#include "lrng_es_aux.h" -+#include "lrng_es_mgr.h" -+#include "lrng_sha.h" -+ -+static struct chacha20_state chacha20_atomic = { -+ LRNG_CC20_INIT_RFC7539(.block) -+}; -+ -+/* -+ * DRNG usable in atomic context. This DRNG will always use the ChaCha20 -+ * DRNG. It will never benefit from a DRNG switch like the "regular" DRNG. If -+ * there was no DRNG switch, the atomic DRNG is identical to the "regular" DRNG. -+ * -+ * The reason for having this is due to the fact that DRNGs other than -+ * the ChaCha20 DRNG may sleep. -+ */ -+static struct lrng_drng lrng_drng_atomic = { -+ LRNG_DRNG_STATE_INIT(lrng_drng_atomic, -+ &chacha20_atomic, NULL, -+ &lrng_cc20_drng_cb, &lrng_sha_hash_cb), -+ .spin_lock = __SPIN_LOCK_UNLOCKED(lrng_drng_atomic.spin_lock) -+}; -+ -+struct lrng_drng *lrng_get_atomic(void) -+{ -+ return &lrng_drng_atomic; -+} -+ -+void lrng_drng_atomic_reset(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&lrng_drng_atomic.spin_lock, flags); -+ lrng_drng_reset(&lrng_drng_atomic); -+ spin_unlock_irqrestore(&lrng_drng_atomic.spin_lock, flags); -+} -+ -+void lrng_drng_atomic_force_reseed(void) -+{ -+ lrng_drng_atomic.force_reseed = lrng_drng_atomic.fully_seeded; -+} -+ -+static bool lrng_drng_atomic_must_reseed(struct lrng_drng *drng) -+{ -+ return (!drng->fully_seeded || -+ atomic_read(&lrng_drng_atomic.requests) == 0 || -+ drng->force_reseed || -+ time_after(jiffies, -+ drng->last_seeded + lrng_drng_reseed_max_time * HZ)); -+} -+ -+void lrng_drng_atomic_seed_drng(struct lrng_drng *regular_drng) -+{ -+ u8 seedbuf[LRNG_DRNG_SECURITY_STRENGTH_BYTES] -+ __aligned(LRNG_KCAPI_ALIGN); -+ int ret; -+ -+ if (!lrng_drng_atomic_must_reseed(&lrng_drng_atomic)) -+ return; -+ -+ /* -+ * Reseed atomic DRNG another DRNG "regular" while this regular DRNG -+ * is reseeded. Therefore, this code operates in non-atomic context and -+ * thus can use the lrng_drng_get function to get random numbers from -+ * the just freshly seeded DRNG. -+ */ -+ ret = lrng_drng_get(regular_drng, seedbuf, sizeof(seedbuf)); -+ -+ if (ret < 0) { -+ pr_warn("Error generating random numbers for atomic DRNG: %d\n", -+ ret); -+ } else { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&lrng_drng_atomic.spin_lock, flags); -+ lrng_drng_inject(&lrng_drng_atomic, seedbuf, ret, -+ regular_drng->fully_seeded, "atomic"); -+ spin_unlock_irqrestore(&lrng_drng_atomic.spin_lock, flags); -+ } -+ memzero_explicit(&seedbuf, sizeof(seedbuf)); -+} -+ -+static void lrng_drng_atomic_get(u8 *outbuf, u32 outbuflen) -+{ -+ struct lrng_drng *drng = &lrng_drng_atomic; -+ unsigned long flags; -+ -+ if (!outbuf || !outbuflen) -+ return; -+ -+ outbuflen = min_t(size_t, outbuflen, INT_MAX); -+ -+ while (outbuflen) { -+ u32 todo = min_t(u32, outbuflen, LRNG_DRNG_MAX_REQSIZE); -+ int ret; -+ -+ atomic_dec(&drng->requests); -+ -+ spin_lock_irqsave(&drng->spin_lock, flags); -+ ret = drng->drng_cb->drng_generate(drng->drng, outbuf, todo); -+ spin_unlock_irqrestore(&drng->spin_lock, flags); -+ if (ret <= 0) { -+ pr_warn("getting random data from DRNG failed (%d)\n", -+ ret); -+ return; -+ } -+ outbuflen -= ret; -+ outbuf += ret; -+ } -+} -+ -+void lrng_get_random_bytes(void *buf, int nbytes) -+{ -+ lrng_drng_atomic_get((u8 *)buf, (u32)nbytes); -+ lrng_debug_report_seedlevel("lrng_get_random_bytes"); -+} -+EXPORT_SYMBOL(lrng_get_random_bytes); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch deleted file mode 100644 index 081734f6a..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 0223535aa1cbc2f22bb55179dcf8829939686baf Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 16:21:44 +0200 -Subject: [PATCH 10/25] LRNG - add common timer-based entropy source code - -The code shared for timer-based entropy sources offers the following -support: - -* It calculates the greatest common divisor (GCD) during startup time. - This allows diving the time stamp by this divisor to eliminate static - low-order bits. With the GCD only timer bits that move are considered - by the entropy sources. - -* It contains the detector code base to identify the presence of a - high-resolution timer. - -This code is only compiled when an entropy source is present that -is based on high-resolution time stamps - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 6 +- - drivers/char/lrng/Makefile | 2 + - drivers/char/lrng/lrng_es_timer_common.c | 144 +++++++++++++++++++++++ - 3 files changed, 149 insertions(+), 3 deletions(-) - create mode 100644 drivers/char/lrng/lrng_es_timer_common.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -144,9 +144,9 @@ endmenu # "Specific DRNG seeding strateg - # config LRNG_SCHED_DFLT_TIMER_ES - # bool - # --# config LRNG_TIMER_COMMON --# bool --# -+config LRNG_TIMER_COMMON -+ bool -+ - # choice - # prompt "Default Timer-based Entropy Source" - # default LRNG_IRQ_DFLT_TIMER_ES ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -17,3 +17,5 @@ obj-$(CONFIG_LRNG_DRNG_CHACHA20) += lrng - obj-$(CONFIG_LRNG_DRBG) += lrng_drng_drbg.o - obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_drng_kcapi.o - obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_drng_atomic.o -+ -+obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_timer_common.c -@@ -0,0 +1,144 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Slow Entropy Source: Interrupt data collection -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+ -+#include "lrng_es_irq.h" -+#include "lrng_es_sched.h" -+#include "lrng_es_timer_common.h" -+#include "lrng_health.h" -+ -+/* Is high-resolution timer present? */ -+static bool lrng_highres_timer_val = false; -+ -+/* Number of time stamps analyzed to calculate a GCD */ -+#define LRNG_GCD_WINDOW_SIZE 100 -+static u32 lrng_gcd_history[LRNG_GCD_WINDOW_SIZE]; -+static atomic_t lrng_gcd_history_ptr = ATOMIC_INIT(-1); -+ -+/* The common divisor for all timestamps */ -+static u32 lrng_gcd_timer = 0; -+ -+bool lrng_gcd_tested(void) -+{ -+ return (lrng_gcd_timer != 0); -+} -+ -+u32 lrng_gcd_get(void) -+{ -+ return lrng_gcd_timer; -+} -+ -+/* Set the GCD for use in IRQ ES - if 0, the GCD calculation is restarted. */ -+void lrng_gcd_set(u32 running_gcd) -+{ -+ lrng_gcd_timer = running_gcd; -+ /* Ensure that update to global variable lrng_gcd_timer is visible */ -+ mb(); -+} -+ -+static void lrng_gcd_set_check(u32 running_gcd) -+{ -+ if (!lrng_gcd_tested()) { -+ lrng_gcd_set(running_gcd); -+ pr_debug("Setting GCD to %u\n", running_gcd); -+ } -+} -+ -+u32 lrng_gcd_analyze(u32 *history, size_t nelem) -+{ -+ u32 running_gcd = 0; -+ size_t i; -+ -+ /* Now perform the analysis on the accumulated time data. */ -+ for (i = 0; i < nelem; i++) { -+ /* -+ * NOTE: this would be the place to add more analysis on the -+ * appropriateness of the timer like checking the presence -+ * of sufficient variations in the timer. -+ */ -+ -+ /* -+ * This calculates the gcd of all the time values. that is -+ * gcd(time_1, time_2, ..., time_nelem) -+ * -+ * Some timers increment by a fixed (non-1) amount each step. -+ * This code checks for such increments, and allows the library -+ * to output the number of such changes have occurred. -+ */ -+ running_gcd = (u32)gcd(history[i], running_gcd); -+ -+ /* Zeroize data */ -+ history[i] = 0; -+ } -+ -+ return running_gcd; -+} -+ -+void lrng_gcd_add_value(u32 time) -+{ -+ u32 ptr = (u32)atomic_inc_return_relaxed(&lrng_gcd_history_ptr); -+ -+ if (ptr < LRNG_GCD_WINDOW_SIZE) { -+ lrng_gcd_history[ptr] = time; -+ } else if (ptr == LRNG_GCD_WINDOW_SIZE) { -+ u32 gcd = lrng_gcd_analyze(lrng_gcd_history, -+ LRNG_GCD_WINDOW_SIZE); -+ -+ if (!gcd) -+ gcd = 1; -+ -+ /* -+ * Ensure that we have variations in the time stamp below the -+ * given value. This is just a safety measure to prevent the GCD -+ * becoming too large. -+ */ -+ if (gcd >= 1000) { -+ pr_warn("calculated GCD is larger than expected: %u\n", -+ gcd); -+ gcd = 1000; -+ } -+ -+ /* Adjust all deltas by the observed (small) common factor. */ -+ lrng_gcd_set_check(gcd); -+ atomic_set(&lrng_gcd_history_ptr, 0); -+ } -+} -+ -+/* Return boolean whether LRNG identified presence of high-resolution timer */ -+bool lrng_highres_timer(void) -+{ -+ return lrng_highres_timer_val; -+} -+ -+static int __init lrng_init_time_source(void) -+{ -+ if ((random_get_entropy() & LRNG_DATA_SLOTSIZE_MASK) || -+ (random_get_entropy() & LRNG_DATA_SLOTSIZE_MASK)) { -+ /* -+ * As the highres timer is identified here, previous interrupts -+ * obtained during boot time are treated like a lowres-timer -+ * would have been present. -+ */ -+ lrng_highres_timer_val = true; -+ } else { -+ lrng_health_disable(); -+ lrng_highres_timer_val = false; -+ } -+ -+ lrng_irq_es_init(lrng_highres_timer_val); -+ lrng_sched_es_init(lrng_highres_timer_val); -+ -+ /* Ensure that changes to global variables are visible */ -+ mb(); -+ -+ return 0; -+} -+core_initcall(lrng_init_time_source); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch deleted file mode 100644 index df7aa1596..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch +++ /dev/null @@ -1,1218 +0,0 @@ -From af37d0a2125fe1f7d7a60df6180dfbc237a48666 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Tue, 25 Apr 2023 23:03:39 +0200 -Subject: [PATCH 11/25] LRNG - add interrupt entropy source - -The interrupt entropy source (ES) consumes the events triggered by the -kernel invoked with the add_interrupt_randomness. Its main goal is: - -- to be extremely fast in the interrupt handler - This is guaranteed by - only concatenating the least significant bits of a time stamp into - CPU-local entropy pools. Thus, the operation is quasi-lockless. Also, - the concatenation is a very trivial operation. Finally, by discarding - the high-order bits, attacker-observable timing values are discarded. - -- to use only cryptographic primitives for compression. - -The IRQ entropy pool collects noise data from interrupt timing. -Any data received by the LRNG from the interrupt noise sources is -inserted into a per-CPU entropy pool using a hash operation that can -be changed during runtime. Per default, SHA-256 is used. - - (a) When an interrupt occurs, the 8 least significant bits of the - high-resolution time stamp divided by the greatest common divisor (GCD) - is mixed into the per-CPU entropy pool. This time stamp is credited with - heuristically implied entropy. - - (b) HID event data like the key stroke or the mouse coordinates are - mixed into the per-CPU entropy pool. This data is not credited with - entropy by the LRNG. - -To speed up the interrupt handling code of the LRNG, the time stamp -collected for an interrupt event is divided by the greatest common -divisor to eliminate fixed low bits and then truncated to the 8 least -significant bits. 1024 truncated time stamps are concatenated and then -jointly inserted into the per-CPU entropy pool. During boot time, -until the fully seeded stage is reached, each time stamp with its -32 least significant bits is are concatenated. When 1024/32 = 32 such -events are received, they are injected into the per-CPU entropy pool. - -The IRQ ES is only enabled if the existing random number generator -(random.c) is not compiled. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 386 ++++++++--------- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_es_irq.c | 730 ++++++++++++++++++++++++++++++++ - 3 files changed, 924 insertions(+), 193 deletions(-) - create mode 100644 drivers/char/lrng/lrng_es_irq.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -122,8 +122,8 @@ endmenu # "Specific DRNG seeding strateg - # - # endmenu # "LRNG Interfaces" - --# menu "Entropy Source Configuration" --# -+menu "Entropy Source Configuration" -+ - # config LRNG_RUNTIME_ES_CONFIG - # bool "Enable runtime configuration of entropy sources" - # help -@@ -135,100 +135,100 @@ endmenu # "Specific DRNG seeding strateg - # a kernel command line option. When not providing any - # option, the default specified during kernel compilation - # is applied. --# --# comment "Common Timer-based Entropy Source Configuration" --# --# config LRNG_IRQ_DFLT_TIMER_ES --# bool --# -+ -+comment "Common Timer-based Entropy Source Configuration" -+ -+config LRNG_IRQ_DFLT_TIMER_ES -+ bool -+ - # config LRNG_SCHED_DFLT_TIMER_ES - # bool - # - config LRNG_TIMER_COMMON - bool - --# choice --# prompt "Default Timer-based Entropy Source" --# default LRNG_IRQ_DFLT_TIMER_ES --# depends on LRNG_TIMER_COMMON --# help --# Select the timer-based entropy source that is credited --# with entropy. The other timer-based entropy sources may --# be operational and provide data, but are credited with no --# entropy. --# --# config LRNG_IRQ_DFLT_TIMER_ES --# bool "Interrupt Entropy Source" --# depends on LRNG_IRQ --# help --# The interrupt entropy source is selected as a timer-based --# entropy source to provide entropy. --# -+choice -+ prompt "Default Timer-based Entropy Source" -+ default LRNG_IRQ_DFLT_TIMER_ES -+ depends on LRNG_TIMER_COMMON -+ help -+ Select the timer-based entropy source that is credited -+ with entropy. The other timer-based entropy sources may -+ be operational and provide data, but are credited with no -+ entropy. -+ -+ config LRNG_IRQ_DFLT_TIMER_ES -+ bool "Interrupt Entropy Source" -+ depends on LRNG_IRQ -+ help -+ The interrupt entropy source is selected as a timer-based -+ entropy source to provide entropy. -+ - # config LRNG_SCHED_DFLT_TIMER_ES - # bool "Scheduler Entropy Source" - # depends on LRNG_SCHED - # help - # The scheduler entropy source is selected as timer-based - # entropy source to provide entropy. --# endchoice --# --# choice --# prompt "LRNG Entropy Collection Pool Size" --# default LRNG_COLLECTION_SIZE_1024 --# depends on LRNG_TIMER_COMMON --# help --# Select the size of the LRNG entropy collection pool --# storing data for the interrupt as well as the scheduler --# entropy sources without performing a compression --# operation. The larger the collection size is, the faster --# the average interrupt handling will be. The collection --# size represents the number of bytes of the per-CPU memory --# used to batch up entropy event data. --# --# The default value is good for regular operations. Choose --# larger sizes for servers that have no memory limitations. --# If runtime memory is precious, choose a smaller size. --# --# The collection size is unrelated to the entropy rate --# or the amount of entropy the LRNG can process. --# --# config LRNG_COLLECTION_SIZE_32 --# depends on LRNG_CONTINUOUS_COMPRESSION_ENABLED --# depends on !LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION --# depends on !CRYPTO_FIPS --# bool "32 interrupt events" --# --# config LRNG_COLLECTION_SIZE_256 --# depends on !CRYPTO_FIPS --# bool "256 interrupt events" --# --# config LRNG_COLLECTION_SIZE_512 --# bool "512 interrupt events" --# --# config LRNG_COLLECTION_SIZE_1024 --# bool "1024 interrupt events (default)" --# --# config LRNG_COLLECTION_SIZE_2048 --# bool "2048 interrupt events" --# --# config LRNG_COLLECTION_SIZE_4096 --# bool "4096 interrupt events" --# --# config LRNG_COLLECTION_SIZE_8192 --# bool "8192 interrupt events" --# --# endchoice --# --# config LRNG_COLLECTION_SIZE --# int --# default 32 if LRNG_COLLECTION_SIZE_32 --# default 256 if LRNG_COLLECTION_SIZE_256 --# default 512 if LRNG_COLLECTION_SIZE_512 --# default 1024 if LRNG_COLLECTION_SIZE_1024 --# default 2048 if LRNG_COLLECTION_SIZE_2048 --# default 4096 if LRNG_COLLECTION_SIZE_4096 --# default 8192 if LRNG_COLLECTION_SIZE_8192 --# -+endchoice -+ -+choice -+ prompt "LRNG Entropy Collection Pool Size" -+ default LRNG_COLLECTION_SIZE_1024 -+ depends on LRNG_TIMER_COMMON -+ help -+ Select the size of the LRNG entropy collection pool -+ storing data for the interrupt as well as the scheduler -+ entropy sources without performing a compression -+ operation. The larger the collection size is, the faster -+ the average interrupt handling will be. The collection -+ size represents the number of bytes of the per-CPU memory -+ used to batch up entropy event data. -+ -+ The default value is good for regular operations. Choose -+ larger sizes for servers that have no memory limitations. -+ If runtime memory is precious, choose a smaller size. -+ -+ The collection size is unrelated to the entropy rate -+ or the amount of entropy the LRNG can process. -+ -+ config LRNG_COLLECTION_SIZE_32 -+ depends on LRNG_CONTINUOUS_COMPRESSION_ENABLED -+ depends on !LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION -+ depends on !CRYPTO_FIPS -+ bool "32 interrupt events" -+ -+ config LRNG_COLLECTION_SIZE_256 -+ depends on !CRYPTO_FIPS -+ bool "256 interrupt events" -+ -+ config LRNG_COLLECTION_SIZE_512 -+ bool "512 interrupt events" -+ -+ config LRNG_COLLECTION_SIZE_1024 -+ bool "1024 interrupt events (default)" -+ -+ config LRNG_COLLECTION_SIZE_2048 -+ bool "2048 interrupt events" -+ -+ config LRNG_COLLECTION_SIZE_4096 -+ bool "4096 interrupt events" -+ -+ config LRNG_COLLECTION_SIZE_8192 -+ bool "8192 interrupt events" -+ -+endchoice -+ -+config LRNG_COLLECTION_SIZE -+ int -+ default 32 if LRNG_COLLECTION_SIZE_32 -+ default 256 if LRNG_COLLECTION_SIZE_256 -+ default 512 if LRNG_COLLECTION_SIZE_512 -+ default 1024 if LRNG_COLLECTION_SIZE_1024 -+ default 2048 if LRNG_COLLECTION_SIZE_2048 -+ default 4096 if LRNG_COLLECTION_SIZE_4096 -+ default 8192 if LRNG_COLLECTION_SIZE_8192 -+ - # config LRNG_HEALTH_TESTS - # bool "Enable internal entropy source online health tests" - # depends on LRNG_TIMER_COMMON -@@ -303,113 +303,113 @@ config LRNG_TIMER_COMMON - # int - # default 371 if !LRNG_APT_BROKEN - # default 33 if LRNG_APT_BROKEN --# --# comment "Interrupt Entropy Source" --# --# config LRNG_IRQ --# bool "Enable Interrupt Entropy Source as LRNG Seed Source" --# default y --# depends on !RANDOM_DEFAULT_IMPL --# select LRNG_TIMER_COMMON --# help --# The LRNG models an entropy source based on the timing of the --# occurrence of interrupts. Enable this option to enable this --# IRQ entropy source. --# --# The IRQ entropy source is triggered every time an interrupt --# arrives and thus causes the interrupt handler to execute --# slightly longer. Disabling the IRQ entropy source implies --# that the performance penalty on the interrupt handler added --# by the LRNG is eliminated. Yet, this entropy source is --# considered to be an internal entropy source of the LRNG. --# Thus, only disable it if you ensured that other entropy --# sources are available that supply the LRNG with entropy. --# --# If you disable the IRQ entropy source, you MUST ensure --# one or more entropy sources collectively have the --# capability to deliver sufficient entropy with one invocation --# at a rate compliant to the security strength of the DRNG --# (usually 256 bits of entropy). In addition, if those --# entropy sources do not deliver sufficient entropy during --# first request, the reseed must be triggered from user --# space or kernel space when sufficient entropy is considered --# to be present. --# --# If unsure, say Y. --# --# choice --# prompt "Continuous entropy compression boot time setting" --# default LRNG_CONTINUOUS_COMPRESSION_ENABLED --# depends on LRNG_IRQ --# help --# Select the default behavior of the interrupt entropy source --# continuous compression operation. --# --# The LRNG IRQ ES collects entropy data during each interrupt. --# For performance reasons, a amount of entropy data defined by --# the LRNG entropy collection pool size is concatenated into --# an array. When that array is filled up, a hash is calculated --# to compress the entropy. That hash is calculated in --# interrupt context. --# --# In case such hash calculation in interrupt context is deemed --# too time-consuming, the continuous compression operation --# can be disabled. If disabled, the collection of entropy will --# not trigger a hash compression operation in interrupt context. --# The compression happens only when the DRNG is reseeded which is --# in process context. This implies that old entropy data --# collected after the last DRNG-reseed is overwritten with newer --# entropy data once the collection pool is full instead of --# retaining its entropy with the compression operation. --# --# config LRNG_CONTINUOUS_COMPRESSION_ENABLED --# bool "Enable continuous compression (default)" --# --# config LRNG_CONTINUOUS_COMPRESSION_DISABLED --# bool "Disable continuous compression" --# --# endchoice --# --# config LRNG_ENABLE_CONTINUOUS_COMPRESSION --# bool --# default y if LRNG_CONTINUOUS_COMPRESSION_ENABLED --# default n if LRNG_CONTINUOUS_COMPRESSION_DISABLED --# --# config LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION --# bool "Runtime-switchable continuous entropy compression" --# depends on LRNG_IRQ --# help --# Per default, the interrupt entropy source continuous --# compression operation behavior is hard-wired into the kernel. --# Enable this option to allow it to be configurable at boot time. --# --# To modify the default behavior of the continuous --# compression operation, use the kernel command line option --# of lrng_sw_noise.lrng_pcpu_continuous_compression. --# --# If unsure, say N. --# --# config LRNG_IRQ_ENTROPY_RATE --# int "Interrupt Entropy Source Entropy Rate" --# depends on LRNG_IRQ --# range 256 4294967295 if LRNG_IRQ_DFLT_TIMER_ES --# range 4294967295 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES --# default 256 if LRNG_IRQ_DFLT_TIMER_ES --# default 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES --# help --# The LRNG will collect the configured number of interrupts to --# obtain 256 bits of entropy. This value can be set to any between --# 256 and 4294967295. The LRNG guarantees that this value is not --# lower than 256. This lower limit implies that one interrupt event --# is credited with one bit of entropy. This value is subject to the --# increase by the oversampling factor, if no high-resolution timer --# is found. --# --# In order to effectively disable the interrupt entropy source, --# the option has to be set to 4294967295. In this case, the --# interrupt entropy source will still deliver data but without --# being credited with entropy. --# -+ -+comment "Interrupt Entropy Source" -+ -+config LRNG_IRQ -+ bool "Enable Interrupt Entropy Source as LRNG Seed Source" -+ default y -+ depends on !RANDOM_DEFAULT_IMPL -+ select LRNG_TIMER_COMMON -+ help -+ The LRNG models an entropy source based on the timing of the -+ occurrence of interrupts. Enable this option to enable this -+ IRQ entropy source. -+ -+ The IRQ entropy source is triggered every time an interrupt -+ arrives and thus causes the interrupt handler to execute -+ slightly longer. Disabling the IRQ entropy source implies -+ that the performance penalty on the interrupt handler added -+ by the LRNG is eliminated. Yet, this entropy source is -+ considered to be an internal entropy source of the LRNG. -+ Thus, only disable it if you ensured that other entropy -+ sources are available that supply the LRNG with entropy. -+ -+ If you disable the IRQ entropy source, you MUST ensure -+ one or more entropy sources collectively have the -+ capability to deliver sufficient entropy with one invocation -+ at a rate compliant to the security strength of the DRNG -+ (usually 256 bits of entropy). In addition, if those -+ entropy sources do not deliver sufficient entropy during -+ first request, the reseed must be triggered from user -+ space or kernel space when sufficient entropy is considered -+ to be present. -+ -+ If unsure, say Y. -+ -+choice -+ prompt "Continuous entropy compression boot time setting" -+ default LRNG_CONTINUOUS_COMPRESSION_ENABLED -+ depends on LRNG_IRQ -+ help -+ Select the default behavior of the interrupt entropy source -+ continuous compression operation. -+ -+ The LRNG IRQ ES collects entropy data during each interrupt. -+ For performance reasons, a amount of entropy data defined by -+ the LRNG entropy collection pool size is concatenated into -+ an array. When that array is filled up, a hash is calculated -+ to compress the entropy. That hash is calculated in -+ interrupt context. -+ -+ In case such hash calculation in interrupt context is deemed -+ too time-consuming, the continuous compression operation -+ can be disabled. If disabled, the collection of entropy will -+ not trigger a hash compression operation in interrupt context. -+ The compression happens only when the DRNG is reseeded which is -+ in process context. This implies that old entropy data -+ collected after the last DRNG-reseed is overwritten with newer -+ entropy data once the collection pool is full instead of -+ retaining its entropy with the compression operation. -+ -+ config LRNG_CONTINUOUS_COMPRESSION_ENABLED -+ bool "Enable continuous compression (default)" -+ -+ config LRNG_CONTINUOUS_COMPRESSION_DISABLED -+ bool "Disable continuous compression" -+ -+endchoice -+ -+config LRNG_ENABLE_CONTINUOUS_COMPRESSION -+ bool -+ default y if LRNG_CONTINUOUS_COMPRESSION_ENABLED -+ default n if LRNG_CONTINUOUS_COMPRESSION_DISABLED -+ -+config LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION -+ bool "Runtime-switchable continuous entropy compression" -+ depends on LRNG_IRQ -+ help -+ Per default, the interrupt entropy source continuous -+ compression operation behavior is hard-wired into the kernel. -+ Enable this option to allow it to be configurable at boot time. -+ -+ To modify the default behavior of the continuous -+ compression operation, use the kernel command line option -+ of lrng_sw_noise.lrng_pcpu_continuous_compression. -+ -+ If unsure, say N. -+ -+config LRNG_IRQ_ENTROPY_RATE -+ int "Interrupt Entropy Source Entropy Rate" -+ depends on LRNG_IRQ -+ range 256 4294967295 if LRNG_IRQ_DFLT_TIMER_ES -+ range 4294967295 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES -+ default 256 if LRNG_IRQ_DFLT_TIMER_ES -+ default 4294967295 if !LRNG_IRQ_DFLT_TIMER_ES -+ help -+ The LRNG will collect the configured number of interrupts to -+ obtain 256 bits of entropy. This value can be set to any between -+ 256 and 4294967295. The LRNG guarantees that this value is not -+ lower than 256. This lower limit implies that one interrupt event -+ is credited with one bit of entropy. This value is subject to the -+ increase by the oversampling factor, if no high-resolution timer -+ is found. -+ -+ In order to effectively disable the interrupt entropy source, -+ the option has to be set to 4294967295. In this case, the -+ interrupt entropy source will still deliver data but without -+ being credited with entropy. -+ - # comment "Jitter RNG Entropy Source" - # - # config LRNG_JENT -@@ -614,8 +614,8 @@ config LRNG_TIMER_COMMON - # kernel in FIPS mode (with fips=1 kernel command line option). - # This is due to the fact that random.c is not SP800-90B - # compliant. --# --# endmenu # "Entropy Source Configuration" -+ -+endmenu # "Entropy Source Configuration" - - config LRNG_DRNG_CHACHA20 - tristate ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -19,3 +19,4 @@ obj-$(CONFIG_LRNG_DRNG_KCAPI) += lrng_d - obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_drng_atomic.o - - obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o -+obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_irq.c -@@ -0,0 +1,730 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Slow Entropy Source: Interrupt data collection -+ * -+ * Copyright (C) 2022 - 2023, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_es_aux.h" -+#include "lrng_es_irq.h" -+#include "lrng_es_timer_common.h" -+#include "lrng_health.h" -+#include "lrng_numa.h" -+#include "lrng_testing.h" -+ -+/* -+ * Number of interrupts to be recorded to assume that DRNG security strength -+ * bits of entropy are received. -+ * Note: a value below the DRNG security strength should not be defined as this -+ * may imply the DRNG can never be fully seeded in case other noise -+ * sources are unavailable. -+ */ -+#define LRNG_IRQ_ENTROPY_BITS LRNG_UINT32_C(CONFIG_LRNG_IRQ_ENTROPY_RATE) -+ -+ -+/* Number of interrupts required for LRNG_DRNG_SECURITY_STRENGTH_BITS entropy */ -+static u32 lrng_irq_entropy_bits = LRNG_IRQ_ENTROPY_BITS; -+ -+static u32 irq_entropy __read_mostly = LRNG_IRQ_ENTROPY_BITS; -+#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG -+module_param(irq_entropy, uint, 0444); -+MODULE_PARM_DESC(irq_entropy, -+ "How many interrupts must be collected for obtaining 256 bits of entropy\n"); -+#endif -+ -+/* Per-CPU array holding concatenated IRQ entropy events */ -+static DEFINE_PER_CPU(u32 [LRNG_DATA_ARRAY_SIZE], lrng_irq_array) -+ __aligned(LRNG_KCAPI_ALIGN); -+static DEFINE_PER_CPU(u32, lrng_irq_array_ptr) = 0; -+static DEFINE_PER_CPU(atomic_t, lrng_irq_array_irqs) = ATOMIC_INIT(0); -+ -+/* -+ * The entropy collection is performed by executing the following steps: -+ * 1. fill up the per-CPU array holding the time stamps -+ * 2. once the per-CPU array is full, a compression of the data into -+ * the entropy pool is performed - this happens in interrupt context -+ * -+ * If step 2 is not desired in interrupt context, the following boolean -+ * needs to be set to false. This implies that old entropy data in the -+ * per-CPU array collected since the last DRNG reseed is overwritten with -+ * new entropy data instead of retaining the entropy with the compression -+ * operation. -+ * -+ * Impact on entropy: -+ * -+ * If continuous compression is enabled, the maximum entropy that is collected -+ * per CPU between DRNG reseeds is equal to the digest size of the used hash. -+ * -+ * If continuous compression is disabled, the maximum number of entropy events -+ * that can be collected per CPU is equal to LRNG_DATA_ARRAY_SIZE. This amount -+ * of events is converted into an entropy statement which then represents the -+ * maximum amount of entropy collectible per CPU between DRNG reseeds. -+ */ -+static bool lrng_irq_continuous_compression __read_mostly = -+ IS_ENABLED(CONFIG_LRNG_ENABLE_CONTINUOUS_COMPRESSION); -+ -+#ifdef CONFIG_LRNG_SWITCHABLE_CONTINUOUS_COMPRESSION -+module_param(lrng_irq_continuous_compression, bool, 0444); -+MODULE_PARM_DESC(lrng_irq_continuous_compression, -+ "Perform entropy compression if per-CPU entropy data array is full\n"); -+#endif -+ -+/* -+ * Per-CPU entropy pool with compressed entropy event -+ * -+ * The per-CPU entropy pool is defined as the hash state. New data is simply -+ * inserted into the entropy pool by performing a hash update operation. -+ * To read the entropy pool, a hash final must be invoked. However, before -+ * the entropy pool is released again after a hash final, the hash init must -+ * be performed. -+ */ -+static DEFINE_PER_CPU(u8 [LRNG_POOL_SIZE], lrng_irq_pool) -+ __aligned(LRNG_KCAPI_ALIGN); -+/* -+ * Lock to allow other CPUs to read the pool - as this is only done during -+ * reseed which is infrequent, this lock is hardly contended. -+ */ -+static DEFINE_PER_CPU(spinlock_t, lrng_irq_lock); -+static DEFINE_PER_CPU(bool, lrng_irq_lock_init) = false; -+ -+static bool lrng_irq_pool_online(int cpu) -+{ -+ return per_cpu(lrng_irq_lock_init, cpu); -+} -+ -+static void __init lrng_irq_check_compression_state(void) -+{ -+ /* One pool must hold sufficient entropy for disabled compression */ -+ if (!lrng_irq_continuous_compression) { -+ u32 max_ent = min_t(u32, lrng_get_digestsize(), -+ lrng_data_to_entropy(LRNG_DATA_NUM_VALUES, -+ lrng_irq_entropy_bits)); -+ if (max_ent < lrng_security_strength()) { -+ pr_warn("Force continuous compression operation to ensure LRNG can hold enough entropy\n"); -+ lrng_irq_continuous_compression = true; -+ } -+ } -+} -+ -+void __init lrng_irq_es_init(bool highres_timer) -+{ -+ /* Set a minimum number of interrupts that must be collected */ -+ irq_entropy = max_t(u32, LRNG_IRQ_ENTROPY_BITS, irq_entropy); -+ -+ if (highres_timer) { -+ lrng_irq_entropy_bits = irq_entropy; -+ } else { -+ u32 new_entropy = irq_entropy * LRNG_ES_OVERSAMPLING_FACTOR; -+ -+ lrng_irq_entropy_bits = (irq_entropy < new_entropy) ? -+ new_entropy : irq_entropy; -+ pr_warn("operating without high-resolution timer and applying IRQ oversampling factor %u\n", -+ LRNG_ES_OVERSAMPLING_FACTOR); -+ } -+ -+ lrng_irq_check_compression_state(); -+} -+ -+/* -+ * Reset all per-CPU pools - reset entropy estimator but leave the pool data -+ * that may or may not have entropy unchanged. -+ */ -+static void lrng_irq_reset(void) -+{ -+ int cpu; -+ -+ /* Trigger GCD calculation anew. */ -+ lrng_gcd_set(0); -+ -+ for_each_online_cpu(cpu) -+ atomic_set(per_cpu_ptr(&lrng_irq_array_irqs, cpu), 0); -+} -+ -+static u32 lrng_irq_avail_pool_size(void) -+{ -+ u32 max_size = 0, max_pool = lrng_get_digestsize(); -+ int cpu; -+ -+ if (!lrng_irq_continuous_compression) -+ max_pool = min_t(u32, max_pool, LRNG_DATA_NUM_VALUES); -+ -+ for_each_online_cpu(cpu) { -+ if (lrng_irq_pool_online(cpu)) -+ max_size += max_pool; -+ } -+ -+ return max_size; -+} -+ -+/* Return entropy of unused IRQs present in all per-CPU pools. */ -+static u32 lrng_irq_avail_entropy(u32 __unused) -+{ -+ u32 digestsize_irqs, irq = 0; -+ int cpu; -+ -+ /* Only deliver entropy when SP800-90B self test is completed */ -+ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_irq)) -+ return 0; -+ -+ /* Obtain the cap of maximum numbers of IRQs we count */ -+ digestsize_irqs = lrng_entropy_to_data(lrng_get_digestsize(), -+ lrng_irq_entropy_bits); -+ if (!lrng_irq_continuous_compression) { -+ /* Cap to max. number of IRQs the array can hold */ -+ digestsize_irqs = min_t(u32, digestsize_irqs, -+ LRNG_DATA_NUM_VALUES); -+ } -+ -+ for_each_online_cpu(cpu) { -+ if (!lrng_irq_pool_online(cpu)) -+ continue; -+ irq += min_t(u32, digestsize_irqs, -+ atomic_read_u32(per_cpu_ptr(&lrng_irq_array_irqs, -+ cpu))); -+ } -+ -+ /* Consider oversampling rate */ -+ return lrng_reduce_by_osr(lrng_data_to_entropy(irq, -+ lrng_irq_entropy_bits)); -+} -+ -+/* -+ * Trigger a switch of the hash implementation for the per-CPU pool. -+ * -+ * For each per-CPU pool, obtain the message digest with the old hash -+ * implementation, initialize the per-CPU pool again with the new hash -+ * implementation and inject the message digest into the new state. -+ * -+ * Assumption: the caller must guarantee that the new_cb is available during the -+ * entire operation (e.g. it must hold the lock against pointer updating). -+ */ -+static int -+lrng_irq_switch_hash(struct lrng_drng *drng, int node, -+ const struct lrng_hash_cb *new_cb, void *new_hash, -+ const struct lrng_hash_cb *old_cb) -+{ -+ u8 digest[LRNG_MAX_DIGESTSIZE]; -+ u32 digestsize_irqs, found_irqs; -+ int ret = 0, cpu; -+ -+ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) -+ return -EOPNOTSUPP; -+ -+ for_each_online_cpu(cpu) { -+ struct shash_desc *pcpu_shash; -+ -+ /* -+ * Only switch the per-CPU pools for the current node because -+ * the hash_cb only applies NUMA-node-wide. -+ */ -+ if (cpu_to_node(cpu) != node || !lrng_irq_pool_online(cpu)) -+ continue; -+ -+ pcpu_shash = (struct shash_desc *)per_cpu_ptr(lrng_irq_pool, -+ cpu); -+ -+ digestsize_irqs = old_cb->hash_digestsize(pcpu_shash); -+ digestsize_irqs = lrng_entropy_to_data(digestsize_irqs << 3, -+ lrng_irq_entropy_bits); -+ -+ if (pcpu_shash->tfm == new_hash) -+ continue; -+ -+ /* Get the per-CPU pool hash with old digest ... */ -+ ret = old_cb->hash_final(pcpu_shash, digest) ?: -+ /* ... re-initialize the hash with the new digest ... */ -+ new_cb->hash_init(pcpu_shash, new_hash) ?: -+ /* -+ * ... feed the old hash into the new state. We may feed -+ * uninitialized memory into the new state, but this is -+ * considered no issue and even good as we have some more -+ * uncertainty here. -+ */ -+ new_cb->hash_update(pcpu_shash, digest, sizeof(digest)); -+ if (ret) -+ goto out; -+ -+ /* -+ * In case the new digest is larger than the old one, cap -+ * the available entropy to the old message digest used to -+ * process the existing data. -+ */ -+ found_irqs = atomic_xchg_relaxed( -+ per_cpu_ptr(&lrng_irq_array_irqs, cpu), 0); -+ found_irqs = min_t(u32, found_irqs, digestsize_irqs); -+ atomic_add_return_relaxed(found_irqs, -+ per_cpu_ptr(&lrng_irq_array_irqs, cpu)); -+ -+ pr_debug("Re-initialize per-CPU interrupt entropy pool for CPU %d on NUMA node %d with hash %s\n", -+ cpu, node, new_cb->hash_name()); -+ } -+ -+out: -+ memzero_explicit(digest, sizeof(digest)); -+ return ret; -+} -+ -+/* -+ * When reading the per-CPU message digest, make sure we use the crypto -+ * callbacks defined for the NUMA node the per-CPU pool is defined for because -+ * the LRNG crypto switch support is only atomic per NUMA node. -+ */ -+static u32 -+lrng_irq_pool_hash_one(const struct lrng_hash_cb *pcpu_hash_cb, -+ void *pcpu_hash, int cpu, u8 *digest, u32 *digestsize) -+{ -+ struct shash_desc *pcpu_shash = -+ (struct shash_desc *)per_cpu_ptr(lrng_irq_pool, cpu); -+ spinlock_t *lock = per_cpu_ptr(&lrng_irq_lock, cpu); -+ unsigned long flags; -+ u32 digestsize_irqs, found_irqs; -+ -+ /* Lock guarding against reading / writing to per-CPU pool */ -+ spin_lock_irqsave(lock, flags); -+ -+ *digestsize = pcpu_hash_cb->hash_digestsize(pcpu_hash); -+ digestsize_irqs = lrng_entropy_to_data(*digestsize << 3, -+ lrng_irq_entropy_bits); -+ -+ /* Obtain entropy statement like for the entropy pool */ -+ found_irqs = atomic_xchg_relaxed( -+ per_cpu_ptr(&lrng_irq_array_irqs, cpu), 0); -+ /* Cap to maximum amount of data we can hold in hash */ -+ found_irqs = min_t(u32, found_irqs, digestsize_irqs); -+ -+ /* Cap to maximum amount of data we can hold in array */ -+ if (!lrng_irq_continuous_compression) -+ found_irqs = min_t(u32, found_irqs, LRNG_DATA_NUM_VALUES); -+ -+ /* Store all not-yet compressed data in data array into hash, ... */ -+ if (pcpu_hash_cb->hash_update(pcpu_shash, -+ (u8 *)per_cpu_ptr(lrng_irq_array, cpu), -+ LRNG_DATA_ARRAY_SIZE * sizeof(u32)) ?: -+ /* ... get the per-CPU pool digest, ... */ -+ pcpu_hash_cb->hash_final(pcpu_shash, digest) ?: -+ /* ... re-initialize the hash, ... */ -+ pcpu_hash_cb->hash_init(pcpu_shash, pcpu_hash) ?: -+ /* ... feed the old hash into the new state. */ -+ pcpu_hash_cb->hash_update(pcpu_shash, digest, *digestsize)) -+ found_irqs = 0; -+ -+ spin_unlock_irqrestore(lock, flags); -+ return found_irqs; -+} -+ -+/* -+ * Hash all per-CPU pools and return the digest to be used as seed data for -+ * seeding a DRNG. The caller must guarantee backtracking resistance. -+ * The function will only copy as much data as entropy is available into the -+ * caller-provided output buffer. -+ * -+ * This function handles the translation from the number of received interrupts -+ * into an entropy statement. The conversion depends on LRNG_IRQ_ENTROPY_BITS -+ * which defines how many interrupts must be received to obtain 256 bits of -+ * entropy. With this value, the function lrng_data_to_entropy converts a given -+ * data size (received interrupts, requested amount of data, etc.) into an -+ * entropy statement. lrng_entropy_to_data does the reverse. -+ * -+ * @eb: entropy buffer to store entropy -+ * @requested_bits: Requested amount of entropy -+ * @fully_seeded: indicator whether LRNG is fully seeded -+ */ -+static void lrng_irq_pool_hash(struct entropy_buf *eb, u32 requested_bits, -+ bool fully_seeded) -+{ -+ SHASH_DESC_ON_STACK(shash, NULL); -+ const struct lrng_hash_cb *hash_cb; -+ struct lrng_drng **lrng_drng = lrng_drng_instances(); -+ struct lrng_drng *drng = lrng_drng_init_instance(); -+ u8 digest[LRNG_MAX_DIGESTSIZE]; -+ unsigned long flags, flags2; -+ u32 found_irqs, collected_irqs = 0, collected_ent_bits, requested_irqs, -+ returned_ent_bits; -+ int ret, cpu; -+ void *hash; -+ -+ /* Only deliver entropy when SP800-90B self test is completed */ -+ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_irq)) { -+ eb->e_bits[lrng_int_es_irq] = 0; -+ return; -+ } -+ -+ /* Lock guarding replacement of per-NUMA hash */ -+ read_lock_irqsave(&drng->hash_lock, flags); -+ -+ hash_cb = drng->hash_cb; -+ hash = drng->hash; -+ -+ /* The hash state of filled with all per-CPU pool hashes. */ -+ ret = hash_cb->hash_init(shash, hash); -+ if (ret) -+ goto err; -+ -+ /* Cap to maximum entropy that can ever be generated with given hash */ -+ lrng_cap_requested(hash_cb->hash_digestsize(hash) << 3, requested_bits); -+ requested_irqs = lrng_entropy_to_data(requested_bits + -+ lrng_compress_osr(), -+ lrng_irq_entropy_bits); -+ -+ /* -+ * Harvest entropy from each per-CPU hash state - even though we may -+ * have collected sufficient entropy, we will hash all per-CPU pools. -+ */ -+ for_each_online_cpu(cpu) { -+ struct lrng_drng *pcpu_drng = drng; -+ u32 digestsize, pcpu_unused_irqs = 0; -+ int node = cpu_to_node(cpu); -+ -+ /* If pool is not online, then no entropy is present. */ -+ if (!lrng_irq_pool_online(cpu)) -+ continue; -+ -+ if (lrng_drng && lrng_drng[node]) -+ pcpu_drng = lrng_drng[node]; -+ -+ if (pcpu_drng == drng) { -+ found_irqs = lrng_irq_pool_hash_one(hash_cb, hash, -+ cpu, digest, -+ &digestsize); -+ } else { -+ read_lock_irqsave(&pcpu_drng->hash_lock, flags2); -+ found_irqs = -+ lrng_irq_pool_hash_one(pcpu_drng->hash_cb, -+ pcpu_drng->hash, cpu, -+ digest, &digestsize); -+ read_unlock_irqrestore(&pcpu_drng->hash_lock, flags2); -+ } -+ -+ /* Inject the digest into the state of all per-CPU pools */ -+ ret = hash_cb->hash_update(shash, digest, digestsize); -+ if (ret) -+ goto err; -+ -+ collected_irqs += found_irqs; -+ if (collected_irqs > requested_irqs) { -+ pcpu_unused_irqs = collected_irqs - requested_irqs; -+ atomic_add_return_relaxed(pcpu_unused_irqs, -+ per_cpu_ptr(&lrng_irq_array_irqs, cpu)); -+ collected_irqs = requested_irqs; -+ } -+ pr_debug("%u interrupts used from entropy pool of CPU %d, %u interrupts remain unused\n", -+ found_irqs - pcpu_unused_irqs, cpu, pcpu_unused_irqs); -+ } -+ -+ ret = hash_cb->hash_final(shash, digest); -+ if (ret) -+ goto err; -+ -+ collected_ent_bits = lrng_data_to_entropy(collected_irqs, -+ lrng_irq_entropy_bits); -+ /* Apply oversampling: discount requested oversampling rate */ -+ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits); -+ -+ pr_debug("obtained %u bits by collecting %u bits of entropy from entropy pool noise source\n", -+ returned_ent_bits, collected_ent_bits); -+ -+ /* -+ * Truncate to available entropy as implicitly allowed by SP800-90B -+ * section 3.1.5.1.1 table 1 which awards truncated hashes full -+ * entropy. -+ * -+ * During boot time, we read requested_bits data with -+ * returned_ent_bits entropy. In case our conservative entropy -+ * estimate underestimates the available entropy we can transport as -+ * much available entropy as possible. -+ */ -+ memcpy(eb->e[lrng_int_es_irq], digest, -+ fully_seeded ? returned_ent_bits >> 3 : requested_bits >> 3); -+ eb->e_bits[lrng_int_es_irq] = returned_ent_bits; -+ -+out: -+ hash_cb->hash_desc_zero(shash); -+ read_unlock_irqrestore(&drng->hash_lock, flags); -+ memzero_explicit(digest, sizeof(digest)); -+ return; -+ -+err: -+ eb->e_bits[lrng_int_es_irq] = 0; -+ goto out; -+} -+ -+/* Compress the lrng_irq_array array into lrng_irq_pool */ -+static void lrng_irq_array_compress(void) -+{ -+ struct shash_desc *shash = -+ (struct shash_desc *)this_cpu_ptr(lrng_irq_pool); -+ struct lrng_drng *drng = lrng_drng_node_instance(); -+ const struct lrng_hash_cb *hash_cb; -+ spinlock_t *lock = this_cpu_ptr(&lrng_irq_lock); -+ unsigned long flags, flags2; -+ void *hash; -+ bool init = false; -+ -+ read_lock_irqsave(&drng->hash_lock, flags); -+ hash_cb = drng->hash_cb; -+ hash = drng->hash; -+ -+ if (unlikely(!this_cpu_read(lrng_irq_lock_init))) { -+ init = true; -+ spin_lock_init(lock); -+ this_cpu_write(lrng_irq_lock_init, true); -+ pr_debug("Initializing per-CPU entropy pool for CPU %d on NUMA node %d with hash %s\n", -+ raw_smp_processor_id(), numa_node_id(), -+ hash_cb->hash_name()); -+ } -+ -+ spin_lock_irqsave(lock, flags2); -+ -+ if (unlikely(init) && hash_cb->hash_init(shash, hash)) { -+ this_cpu_write(lrng_irq_lock_init, false); -+ pr_warn("Initialization of hash failed\n"); -+ } else if (lrng_irq_continuous_compression) { -+ /* Add entire per-CPU data array content into entropy pool. */ -+ if (hash_cb->hash_update(shash, -+ (u8 *)this_cpu_ptr(lrng_irq_array), -+ LRNG_DATA_ARRAY_SIZE * sizeof(u32))) -+ pr_warn_ratelimited("Hashing of entropy data failed\n"); -+ } -+ -+ spin_unlock_irqrestore(lock, flags2); -+ read_unlock_irqrestore(&drng->hash_lock, flags); -+} -+ -+/* Compress data array into hash */ -+static void lrng_irq_array_to_hash(u32 ptr) -+{ -+ u32 *array = this_cpu_ptr(lrng_irq_array); -+ -+ /* -+ * During boot time the hash operation is triggered more often than -+ * during regular operation. -+ */ -+ if (unlikely(!lrng_state_fully_seeded())) { -+ if ((ptr & 31) && (ptr < LRNG_DATA_WORD_MASK)) -+ return; -+ } else if (ptr < LRNG_DATA_WORD_MASK) { -+ return; -+ } -+ -+ if (lrng_raw_array_entropy_store(*array)) { -+ u32 i; -+ -+ /* -+ * If we fed even a part of the array to external analysis, we -+ * mark that the entire array and the per-CPU pool to have no -+ * entropy. This is due to the non-IID property of the data as -+ * we do not fully know whether the existing dependencies -+ * diminish the entropy beyond to what we expect it has. -+ */ -+ atomic_set(this_cpu_ptr(&lrng_irq_array_irqs), 0); -+ -+ for (i = 1; i < LRNG_DATA_ARRAY_SIZE; i++) -+ lrng_raw_array_entropy_store(*(array + i)); -+ } else { -+ lrng_irq_array_compress(); -+ /* Ping pool handler about received entropy */ -+ if (lrng_sp80090b_startup_complete_es(lrng_int_es_irq)) -+ lrng_es_add_entropy(); -+ } -+} -+ -+/* -+ * Concatenate full 32 bit word at the end of time array even when current -+ * ptr is not aligned to sizeof(data). -+ */ -+static void _lrng_irq_array_add_u32(u32 data) -+{ -+ /* Increment pointer by number of slots taken for input value */ -+ u32 pre_ptr, mask, ptr = this_cpu_add_return(lrng_irq_array_ptr, -+ LRNG_DATA_SLOTS_PER_UINT); -+ unsigned int pre_array; -+ -+ /* -+ * This function injects a unit into the array - guarantee that -+ * array unit size is equal to data type of input data. -+ */ -+ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS != (sizeof(data) << 3)); -+ -+ /* -+ * The following logic requires at least two units holding -+ * the data as otherwise the pointer would immediately wrap when -+ * injection an u32 word. -+ */ -+ BUILD_BUG_ON(LRNG_DATA_NUM_VALUES <= LRNG_DATA_SLOTS_PER_UINT); -+ -+ lrng_data_split_u32(&ptr, &pre_ptr, &mask); -+ -+ /* MSB of data go into previous unit */ -+ pre_array = lrng_data_idx2array(pre_ptr); -+ /* zeroization of slot to ensure the following OR adds the data */ -+ this_cpu_and(lrng_irq_array[pre_array], ~(0xffffffff & ~mask)); -+ this_cpu_or(lrng_irq_array[pre_array], data & ~mask); -+ -+ /* Invoke compression as we just filled data array completely */ -+ if (unlikely(pre_ptr > ptr)) -+ lrng_irq_array_to_hash(LRNG_DATA_WORD_MASK); -+ -+ /* LSB of data go into current unit */ -+ this_cpu_write(lrng_irq_array[lrng_data_idx2array(ptr)], -+ data & mask); -+ -+ if (likely(pre_ptr <= ptr)) -+ lrng_irq_array_to_hash(ptr); -+} -+ -+/* Concatenate a 32-bit word at the end of the per-CPU array */ -+void lrng_irq_array_add_u32(u32 data) -+{ -+ /* -+ * Disregard entropy-less data without continuous compression to -+ * avoid it overwriting data with entropy when array ptr wraps. -+ */ -+ if (lrng_irq_continuous_compression) -+ _lrng_irq_array_add_u32(data); -+} -+ -+/* Concatenate data of max LRNG_DATA_SLOTSIZE_MASK at the end of time array */ -+static void lrng_irq_array_add_slot(u32 data) -+{ -+ /* Get slot */ -+ u32 ptr = this_cpu_inc_return(lrng_irq_array_ptr) & -+ LRNG_DATA_WORD_MASK; -+ unsigned int array = lrng_data_idx2array(ptr); -+ unsigned int slot = lrng_data_idx2slot(ptr); -+ -+ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS % LRNG_DATA_SLOTSIZE_BITS); -+ /* Ensure consistency of values */ -+ BUILD_BUG_ON(LRNG_DATA_ARRAY_MEMBER_BITS != -+ sizeof(lrng_irq_array[0]) << 3); -+ -+ /* zeroization of slot to ensure the following OR adds the data */ -+ this_cpu_and(lrng_irq_array[array], -+ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK, -+ slot))); -+ /* Store data into slot */ -+ this_cpu_or(lrng_irq_array[array], lrng_data_slot_val(data, slot)); -+ -+ lrng_irq_array_to_hash(ptr); -+} -+ -+static void -+lrng_time_process_common(u32 time, void(*add_time)(u32 data)) -+{ -+ enum lrng_health_res health_test; -+ -+ if (lrng_raw_hires_entropy_store(time)) -+ return; -+ -+ health_test = lrng_health_test(time, lrng_int_es_irq); -+ if (health_test > lrng_health_fail_use) -+ return; -+ -+ if (health_test == lrng_health_pass) -+ atomic_inc_return(this_cpu_ptr(&lrng_irq_array_irqs)); -+ -+ add_time(time); -+} -+ -+/* -+ * Batching up of entropy in per-CPU array before injecting into entropy pool. -+ */ -+static void lrng_time_process(void) -+{ -+ u32 now_time = random_get_entropy(); -+ -+ if (unlikely(!lrng_gcd_tested())) { -+ /* When GCD is unknown, we process the full time stamp */ -+ lrng_time_process_common(now_time, _lrng_irq_array_add_u32); -+ lrng_gcd_add_value(now_time); -+ } else { -+ /* GCD is known and applied */ -+ lrng_time_process_common((now_time / lrng_gcd_get()) & -+ LRNG_DATA_SLOTSIZE_MASK, -+ lrng_irq_array_add_slot); -+ } -+ -+ lrng_perf_time(now_time); -+} -+ -+/* Hot code path - Callback for interrupt handler */ -+void add_interrupt_randomness(int irq) -+{ -+ if (lrng_highres_timer()) { -+ lrng_time_process(); -+ } else { -+ struct pt_regs *regs = get_irq_regs(); -+ static atomic_t reg_idx = ATOMIC_INIT(0); -+ u64 ip; -+ u32 tmp; -+ -+ if (regs) { -+ u32 *ptr = (u32 *)regs; -+ int reg_ptr = atomic_add_return_relaxed(1, ®_idx); -+ size_t n = (sizeof(struct pt_regs) / sizeof(u32)); -+ -+ ip = instruction_pointer(regs); -+ tmp = *(ptr + (reg_ptr % n)); -+ tmp = lrng_raw_regs_entropy_store(tmp) ? 0 : tmp; -+ _lrng_irq_array_add_u32(tmp); -+ } else { -+ ip = _RET_IP_; -+ } -+ -+ lrng_time_process(); -+ -+ /* -+ * The XOR operation combining the different values is not -+ * considered to destroy entropy since the entirety of all -+ * processed values delivers the entropy (and not each -+ * value separately of the other values). -+ */ -+ tmp = lrng_raw_jiffies_entropy_store(jiffies) ? 0 : jiffies; -+ tmp ^= lrng_raw_irq_entropy_store(irq) ? 0 : irq; -+ tmp ^= lrng_raw_retip_entropy_store(ip) ? 0 : ip; -+ tmp ^= ip >> 32; -+ _lrng_irq_array_add_u32(tmp); -+ } -+} -+EXPORT_SYMBOL(add_interrupt_randomness); -+ -+static void lrng_irq_es_state(unsigned char *buf, size_t buflen) -+{ -+ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ -+ /* Assume the lrng_drng_init lock is taken by caller */ -+ snprintf(buf, buflen, -+ " Hash for operating entropy pool: %s\n" -+ " Available entropy: %u\n" -+ " per-CPU interrupt collection size: %u\n" -+ " Standards compliance: %s\n" -+ " High-resolution timer: %s\n" -+ " Continuous compression: %s\n" -+ " Health test passed: %s\n", -+ lrng_drng_init->hash_cb->hash_name(), -+ lrng_irq_avail_entropy(0), -+ LRNG_DATA_NUM_VALUES, -+ lrng_sp80090b_compliant(lrng_int_es_irq) ? "SP800-90B " : "", -+ lrng_highres_timer() ? "true" : "false", -+ lrng_irq_continuous_compression ? "true" : "false", -+ lrng_sp80090b_startup_complete_es(lrng_int_es_irq) ? "true" : -+ "false"); -+} -+ -+struct lrng_es_cb lrng_es_irq = { -+ .name = "IRQ", -+ .get_ent = lrng_irq_pool_hash, -+ .curr_entropy = lrng_irq_avail_entropy, -+ .max_entropy = lrng_irq_avail_pool_size, -+ .state = lrng_irq_es_state, -+ .reset = lrng_irq_reset, -+ .switch_hash = lrng_irq_switch_hash, -+}; diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch deleted file mode 100644 index 066d521b0..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ /dev/null @@ -1,35 +0,0 @@ -From b583d31eb462ebe06e2364dd5c1d3fc108e0c8de Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 16:39:02 +0200 -Subject: [PATCH 12/25] scheduler - add entropy sampling hook - -The scheduler can be used as a source of entropy. This requires the -presence of a hook that invokes the entropy source implementation. - -When the scheduler-based entropy source is not compiled, the hook is -folded into a noop which does not affect the scheduler in any way. - -Signed-off-by: Stephan Mueller ---- - kernel/sched/core.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -6,6 +6,7 @@ - * - * Copyright (C) 1991-2002 Linus Torvalds - */ -+#include - #include - #include - #include -@@ -3720,6 +3721,8 @@ ttwu_stat(struct task_struct *p, int cpu - { - struct rq *rq; - -+ add_sched_randomness(p, cpu); -+ - if (!schedstat_enabled()) - return; - diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch deleted file mode 100644 index 7dd42f3f0..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch +++ /dev/null @@ -1,914 +0,0 @@ -From da3a883ae987c776c137b7f9e43e243b560dd1e8 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Wed, 22 Feb 2023 07:05:59 +0100 -Subject: [PATCH 13/25] LRNG - add scheduler-based entropy source - -The scheduler-based entropy source (ES) consumes the events triggered by -the kernel invoked with the add_sched_randomness. Its main goal is: - -- to be extremely fast in the scheduler context - This is guaranteed by - only concatenating the least significant bits of a time stamp into - CPU-local entropy pools. Thus, the operation is quasi-lockless. Also, - the concatenation is a very trivial operation. Finally, by discarding - the high-order bits, attacker-observable timing values are discarded. - -- to use only cryptographic primitives for compression. - -The scheduler entropy pool collects noise data from context-switch -timing. Any data received by the LRNG from the interrupt noise sources -is inserted into a per-CPU entropy pool using a concatenation operation. -The following processing concept is applied - - (a) When an interrupt occurs, the 8 least significant bits of the - high-resolution time stamp divided by the greatest common divisor (GCD) - is mixed into the per-CPU entropy pool. This time stamp is credited with - heuristically implied entropy. - - (b) Only in process context when a reseed of the DRNG is requested, - the compression of the entropy pool data is performed using a hash. - When the entropy pool is full (i.e. sufficient scheduling event data - is received and yet no compression is performed), the oldest entropy - pool entries are overwritten with the current entry. Thus, the entropy - pool acts as a ring buffer. - -To speed up the scheduling operation code of the LRNG, the time stamp -collected for an interrupt event is divided by the greatest common -divisor to eliminate fixed low bits and then truncated to the 8 least -significant bits. 1024 truncated time stamps are concatenated and then -jointly inserted into the per-CPU entropy pool. During boot time, -until the fully seeded stage is reached, each time stamp with its -32 least significant bits is are concatenated. When 1024/32 = 32 such -events are received, they are injected into the per-CPU entropy pool. - -Considering the possibility that IRQ events cause at the same time -scheduling events (e.g. the IRQ tasklet is executed), only one of those -two entropy sources can ever be configured to deliver entropy. The -respective other ES may deliver data, but never increases the entropy -estimator of the LRNG. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 122 +++---- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_es_sched.c | 566 ++++++++++++++++++++++++++++++ - drivers/char/lrng/lrng_health.h | 42 +++ - drivers/char/lrng/lrng_testing.h | 85 +++++ - 5 files changed, 755 insertions(+), 61 deletions(-) - create mode 100644 drivers/char/lrng/lrng_es_sched.c - create mode 100644 drivers/char/lrng/lrng_health.h - create mode 100644 drivers/char/lrng/lrng_testing.h - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -141,9 +141,9 @@ comment "Common Timer-based Entropy Sour - config LRNG_IRQ_DFLT_TIMER_ES - bool - --# config LRNG_SCHED_DFLT_TIMER_ES --# bool --# -+config LRNG_SCHED_DFLT_TIMER_ES -+ bool -+ - config LRNG_TIMER_COMMON - bool - -@@ -164,12 +164,12 @@ choice - The interrupt entropy source is selected as a timer-based - entropy source to provide entropy. - --# config LRNG_SCHED_DFLT_TIMER_ES --# bool "Scheduler Entropy Source" --# depends on LRNG_SCHED --# help --# The scheduler entropy source is selected as timer-based --# entropy source to provide entropy. -+ config LRNG_SCHED_DFLT_TIMER_ES -+ bool "Scheduler Entropy Source" -+ depends on LRNG_SCHED -+ help -+ The scheduler entropy source is selected as timer-based -+ entropy source to provide entropy. - endchoice - - choice -@@ -534,58 +534,58 @@ config LRNG_IRQ_ENTROPY_RATE - # Note, this option is overwritten when the option - # CONFIG_RANDOM_TRUST_CPU is set. - # --# comment "Scheduler Entropy Source" --# --# config LRNG_SCHED --# bool "Enable Scheduer Entropy Source as LRNG Seed Source" --# select LRNG_TIMER_COMMON --# help --# The LRNG models an entropy source based on the timing of the --# occurrence of scheduler-triggered context switches. Enable --# this option to enable this scheduler entropy source. --# --# The scheduler entropy source is triggered every time a --# context switch is triggered thus causes the scheduler to --# execute slightly longer. Disabling the scheduler entropy --# source implies that the performance penalty on the scheduler --# added by the LRNG is eliminated. Yet, this entropy source is --# considered to be an internal entropy source of the LRNG. --# Thus, only disable it if you ensured that other entropy --# sources are available that supply the LRNG with entropy. --# --# If you disable the scheduler entropy source, you MUST --# ensure one or more entropy sources collectively have the --# capability to deliver sufficient entropy with one invocation --# at a rate compliant to the security strength of the DRNG --# (usually 256 bits of entropy). In addition, if those --# entropy sources do not deliver sufficient entropy during --# first request, the reseed must be triggered from user --# space or kernel space when sufficient entropy is considered --# to be present. --# --# If unsure, say Y. --# --# config LRNG_SCHED_ENTROPY_RATE --# int "Scheduler Entropy Source Entropy Rate" --# depends on LRNG_SCHED --# range 256 4294967295 if LRNG_SCHED_DFLT_TIMER_ES --# range 4294967295 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES --# default 256 if LRNG_SCHED_DFLT_TIMER_ES --# default 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES --# help --# The LRNG will collect the configured number of context switches --# triggered by the scheduler to obtain 256 bits of entropy. This --# value can be set to any between 256 and 4294967295. The LRNG --# guarantees that this value is not lower than 256. This lower --# limit implies that one interrupt event is credited with one bit --# of entropy. This value is subject to the increase by the --# oversampling factor, if no high-resolution timer is found. --# --# In order to effectively disable the scheduler entropy source, --# the option has to be set to 4294967295. In this case, the --# scheduler entropy source will still deliver data but without --# being credited with entropy. --# -+comment "Scheduler Entropy Source" -+ -+config LRNG_SCHED -+ bool "Enable Scheduer Entropy Source as LRNG Seed Source" -+ select LRNG_TIMER_COMMON -+ help -+ The LRNG models an entropy source based on the timing of the -+ occurrence of scheduler-triggered context switches. Enable -+ this option to enable this scheduler entropy source. -+ -+ The scheduler entropy source is triggered every time a -+ context switch is triggered thus causes the scheduler to -+ execute slightly longer. Disabling the scheduler entropy -+ source implies that the performance penalty on the scheduler -+ added by the LRNG is eliminated. Yet, this entropy source is -+ considered to be an internal entropy source of the LRNG. -+ Thus, only disable it if you ensured that other entropy -+ sources are available that supply the LRNG with entropy. -+ -+ If you disable the scheduler entropy source, you MUST -+ ensure one or more entropy sources collectively have the -+ capability to deliver sufficient entropy with one invocation -+ at a rate compliant to the security strength of the DRNG -+ (usually 256 bits of entropy). In addition, if those -+ entropy sources do not deliver sufficient entropy during -+ first request, the reseed must be triggered from user -+ space or kernel space when sufficient entropy is considered -+ to be present. -+ -+ If unsure, say Y. -+ -+config LRNG_SCHED_ENTROPY_RATE -+ int "Scheduler Entropy Source Entropy Rate" -+ depends on LRNG_SCHED -+ range 256 4294967295 if LRNG_SCHED_DFLT_TIMER_ES -+ range 4294967295 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES -+ default 256 if LRNG_SCHED_DFLT_TIMER_ES -+ default 4294967295 if !LRNG_SCHED_DFLT_TIMER_ES -+ help -+ The LRNG will collect the configured number of context switches -+ triggered by the scheduler to obtain 256 bits of entropy. This -+ value can be set to any between 256 and 4294967295. The LRNG -+ guarantees that this value is not lower than 256. This lower -+ limit implies that one interrupt event is credited with one bit -+ of entropy. This value is subject to the increase by the -+ oversampling factor, if no high-resolution timer is found. -+ -+ In order to effectively disable the scheduler entropy source, -+ the option has to be set to 4294967295. In this case, the -+ scheduler entropy source will still deliver data but without -+ being credited with entropy. -+ - # comment "Kernel RNG Entropy Source" - # - # config LRNG_KERNEL_RNG ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -20,3 +20,4 @@ obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_ - - obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o - obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o -+obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_sched.c -@@ -0,0 +1,566 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Slow Entropy Source: Scheduler-based data collection -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_es_aux.h" -+#include "lrng_es_sched.h" -+#include "lrng_es_timer_common.h" -+#include "lrng_health.h" -+#include "lrng_numa.h" -+#include "lrng_testing.h" -+ -+/* -+ * Number of scheduler-based context switches to be recorded to assume that -+ * DRNG security strength bits of entropy are received. -+ * Note: a value below the DRNG security strength should not be defined as this -+ * may imply the DRNG can never be fully seeded in case other noise -+ * sources are unavailable. -+ */ -+#define LRNG_SCHED_ENTROPY_BITS \ -+ LRNG_UINT32_C(CONFIG_LRNG_SCHED_ENTROPY_RATE) -+ -+/* Number of events required for LRNG_DRNG_SECURITY_STRENGTH_BITS entropy */ -+static u32 lrng_sched_entropy_bits = LRNG_SCHED_ENTROPY_BITS; -+ -+static u32 sched_entropy __read_mostly = LRNG_SCHED_ENTROPY_BITS; -+#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG -+module_param(sched_entropy, uint, 0444); -+MODULE_PARM_DESC(sched_entropy, -+ "How many scheduler-based context switches must be collected for obtaining 256 bits of entropy\n"); -+#endif -+ -+/* Per-CPU array holding concatenated entropy events */ -+static DEFINE_PER_CPU(u32 [LRNG_DATA_ARRAY_SIZE], lrng_sched_array) -+ __aligned(LRNG_KCAPI_ALIGN); -+static DEFINE_PER_CPU(u32, lrng_sched_array_ptr) = 0; -+static DEFINE_PER_CPU(atomic_t, lrng_sched_array_events) = ATOMIC_INIT(0); -+ -+/* -+ * Per-CPU entropy pool with compressed entropy event -+ * -+ * The per-CPU entropy pool is defined as the hash state. New data is simply -+ * inserted into the entropy pool by performing a hash update operation. -+ * To read the entropy pool, a hash final must be invoked. However, before -+ * the entropy pool is released again after a hash final, the hash init must -+ * be performed. -+ */ -+static DEFINE_PER_CPU(u8 [LRNG_POOL_SIZE], lrng_sched_pool) -+ __aligned(LRNG_KCAPI_ALIGN); -+/* -+ * Lock to allow other CPUs to read the pool - as this is only done during -+ * reseed which is infrequent, this lock is hardly contended. -+ */ -+static DEFINE_PER_CPU(spinlock_t, lrng_sched_lock); -+static DEFINE_PER_CPU(bool, lrng_sched_lock_init) = false; -+ -+static bool lrng_sched_pool_online(int cpu) -+{ -+ return per_cpu(lrng_sched_lock_init, cpu); -+} -+ -+static void __init lrng_sched_check_compression_state(void) -+{ -+ /* One pool should hold sufficient entropy for disabled compression */ -+ u32 max_ent = min_t(u32, lrng_get_digestsize(), -+ lrng_data_to_entropy(LRNG_DATA_NUM_VALUES, -+ lrng_sched_entropy_bits)); -+ if (max_ent < lrng_security_strength()) { -+ pr_devel("Scheduler entropy source will never provide %u bits of entropy required for fully seeding the DRNG all by itself\n", -+ lrng_security_strength()); -+ } -+} -+ -+void __init lrng_sched_es_init(bool highres_timer) -+{ -+ /* Set a minimum number of scheduler events that must be collected */ -+ sched_entropy = max_t(u32, LRNG_SCHED_ENTROPY_BITS, sched_entropy); -+ -+ if (highres_timer) { -+ lrng_sched_entropy_bits = sched_entropy; -+ } else { -+ u32 new_entropy = sched_entropy * LRNG_ES_OVERSAMPLING_FACTOR; -+ -+ lrng_sched_entropy_bits = (sched_entropy < new_entropy) ? -+ new_entropy : sched_entropy; -+ pr_warn("operating without high-resolution timer and applying oversampling factor %u\n", -+ LRNG_ES_OVERSAMPLING_FACTOR); -+ } -+ -+ lrng_sched_check_compression_state(); -+} -+ -+static u32 lrng_sched_avail_pool_size(void) -+{ -+ u32 max_pool = lrng_get_digestsize(), -+ max_size = min_t(u32, max_pool, LRNG_DATA_NUM_VALUES); -+ int cpu; -+ -+ for_each_online_cpu(cpu) -+ max_size += max_pool; -+ -+ return max_size; -+} -+ -+/* Return entropy of unused scheduler events present in all per-CPU pools. */ -+static u32 lrng_sched_avail_entropy(u32 __unused) -+{ -+ u32 digestsize_events, events = 0; -+ int cpu; -+ -+ /* Only deliver entropy when SP800-90B self test is completed */ -+ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_sched)) -+ return 0; -+ -+ /* Obtain the cap of maximum numbers of scheduler events we count */ -+ digestsize_events = lrng_entropy_to_data(lrng_get_digestsize(), -+ lrng_sched_entropy_bits); -+ /* Cap to max. number of scheduler events the array can hold */ -+ digestsize_events = min_t(u32, digestsize_events, LRNG_DATA_NUM_VALUES); -+ -+ for_each_online_cpu(cpu) { -+ events += min_t(u32, digestsize_events, -+ atomic_read_u32(per_cpu_ptr(&lrng_sched_array_events, -+ cpu))); -+ } -+ -+ /* Consider oversampling rate */ -+ return lrng_reduce_by_osr( -+ lrng_data_to_entropy(events, lrng_sched_entropy_bits)); -+} -+ -+/* -+ * Reset all per-CPU pools - reset entropy estimator but leave the pool data -+ * that may or may not have entropy unchanged. -+ */ -+static void lrng_sched_reset(void) -+{ -+ int cpu; -+ -+ /* Trigger GCD calculation anew. */ -+ lrng_gcd_set(0); -+ -+ for_each_online_cpu(cpu) -+ atomic_set(per_cpu_ptr(&lrng_sched_array_events, cpu), 0); -+} -+ -+/* -+ * Trigger a switch of the hash implementation for the per-CPU pool. -+ * -+ * For each per-CPU pool, obtain the message digest with the old hash -+ * implementation, initialize the per-CPU pool again with the new hash -+ * implementation and inject the message digest into the new state. -+ * -+ * Assumption: the caller must guarantee that the new_cb is available during the -+ * entire operation (e.g. it must hold the lock against pointer updating). -+ */ -+static int -+lrng_sched_switch_hash(struct lrng_drng *drng, int node, -+ const struct lrng_hash_cb *new_cb, void *new_hash, -+ const struct lrng_hash_cb *old_cb) -+{ -+ u8 digest[LRNG_MAX_DIGESTSIZE]; -+ u32 digestsize_events, found_events; -+ int ret = 0, cpu; -+ -+ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) -+ return -EOPNOTSUPP; -+ -+ for_each_online_cpu(cpu) { -+ struct shash_desc *pcpu_shash; -+ -+ /* -+ * Only switch the per-CPU pools for the current node because -+ * the hash_cb only applies NUMA-node-wide. -+ */ -+ if (cpu_to_node(cpu) != node || !lrng_sched_pool_online(cpu)) -+ continue; -+ -+ pcpu_shash = (struct shash_desc *)per_cpu_ptr(lrng_sched_pool, -+ cpu); -+ -+ digestsize_events = old_cb->hash_digestsize(pcpu_shash); -+ digestsize_events = lrng_entropy_to_data(digestsize_events << 3, -+ lrng_sched_entropy_bits); -+ -+ if (pcpu_shash->tfm == new_hash) -+ continue; -+ -+ /* Get the per-CPU pool hash with old digest ... */ -+ ret = old_cb->hash_final(pcpu_shash, digest) ?: -+ /* ... re-initialize the hash with the new digest ... */ -+ new_cb->hash_init(pcpu_shash, new_hash) ?: -+ /* -+ * ... feed the old hash into the new state. We may feed -+ * uninitialized memory into the new state, but this is -+ * considered no issue and even good as we have some more -+ * uncertainty here. -+ */ -+ new_cb->hash_update(pcpu_shash, digest, sizeof(digest)); -+ if (ret) -+ goto out; -+ -+ /* -+ * In case the new digest is larger than the old one, cap -+ * the available entropy to the old message digest used to -+ * process the existing data. -+ */ -+ found_events = atomic_xchg_relaxed( -+ per_cpu_ptr(&lrng_sched_array_events, cpu), 0); -+ found_events = min_t(u32, found_events, digestsize_events); -+ atomic_add_return_relaxed(found_events, -+ per_cpu_ptr(&lrng_sched_array_events, cpu)); -+ -+ pr_debug("Re-initialize per-CPU scheduler entropy pool for CPU %d on NUMA node %d with hash %s\n", -+ cpu, node, new_cb->hash_name()); -+ } -+ -+out: -+ memzero_explicit(digest, sizeof(digest)); -+ return ret; -+} -+ -+static u32 -+lrng_sched_pool_hash_one(const struct lrng_hash_cb *pcpu_hash_cb, -+ void *pcpu_hash, int cpu, u8 *digest, u32 *digestsize) -+{ -+ struct shash_desc *pcpu_shash = -+ (struct shash_desc *)per_cpu_ptr(lrng_sched_pool, cpu); -+ spinlock_t *lock = per_cpu_ptr(&lrng_sched_lock, cpu); -+ unsigned long flags; -+ u32 digestsize_events, found_events; -+ -+ if (unlikely(!per_cpu(lrng_sched_lock_init, cpu))) { -+ if (pcpu_hash_cb->hash_init(pcpu_shash, pcpu_hash)) { -+ pr_warn("Initialization of hash failed\n"); -+ return 0; -+ } -+ spin_lock_init(lock); -+ per_cpu(lrng_sched_lock_init, cpu) = true; -+ pr_debug("Initializing per-CPU scheduler entropy pool for CPU %d with hash %s\n", -+ raw_smp_processor_id(), pcpu_hash_cb->hash_name()); -+ } -+ -+ /* Lock guarding against reading / writing to per-CPU pool */ -+ spin_lock_irqsave(lock, flags); -+ -+ *digestsize = pcpu_hash_cb->hash_digestsize(pcpu_hash); -+ digestsize_events = lrng_entropy_to_data(*digestsize << 3, -+ lrng_sched_entropy_bits); -+ -+ /* Obtain entropy statement like for the entropy pool */ -+ found_events = atomic_xchg_relaxed( -+ per_cpu_ptr(&lrng_sched_array_events, cpu), 0); -+ /* Cap to maximum amount of data we can hold in hash */ -+ found_events = min_t(u32, found_events, digestsize_events); -+ -+ /* Cap to maximum amount of data we can hold in array */ -+ found_events = min_t(u32, found_events, LRNG_DATA_NUM_VALUES); -+ -+ /* Store all not-yet compressed data in data array into hash, ... */ -+ if (pcpu_hash_cb->hash_update(pcpu_shash, -+ (u8 *)per_cpu_ptr(lrng_sched_array, cpu), -+ LRNG_DATA_ARRAY_SIZE * sizeof(u32)) ?: -+ /* ... get the per-CPU pool digest, ... */ -+ pcpu_hash_cb->hash_final(pcpu_shash, digest) ?: -+ /* ... re-initialize the hash, ... */ -+ pcpu_hash_cb->hash_init(pcpu_shash, pcpu_hash) ?: -+ /* ... feed the old hash into the new state. */ -+ pcpu_hash_cb->hash_update(pcpu_shash, digest, *digestsize)) -+ found_events = 0; -+ -+ spin_unlock_irqrestore(lock, flags); -+ return found_events; -+} -+ -+/* -+ * Hash all per-CPU arrays and return the digest to be used as seed data for -+ * seeding a DRNG. The caller must guarantee backtracking resistance. -+ * The function will only copy as much data as entropy is available into the -+ * caller-provided output buffer. -+ * -+ * This function handles the translation from the number of received scheduler -+ * events into an entropy statement. The conversion depends on -+ * LRNG_SCHED_ENTROPY_BITS which defines how many scheduler events must be -+ * received to obtain 256 bits of entropy. With this value, the function -+ * lrng_data_to_entropy converts a given data size (received scheduler events, -+ * requested amount of data, etc.) into an entropy statement. -+ * lrng_entropy_to_data does the reverse. -+ * -+ * @eb: entropy buffer to store entropy -+ * @requested_bits: Requested amount of entropy -+ * @fully_seeded: indicator whether LRNG is fully seeded -+ */ -+static void lrng_sched_pool_hash(struct entropy_buf *eb, u32 requested_bits, -+ bool fully_seeded) -+{ -+ SHASH_DESC_ON_STACK(shash, NULL); -+ const struct lrng_hash_cb *hash_cb; -+ struct lrng_drng **lrng_drng = lrng_drng_instances(); -+ struct lrng_drng *drng = lrng_drng_init_instance(); -+ u8 digest[LRNG_MAX_DIGESTSIZE]; -+ unsigned long flags, flags2; -+ u32 found_events, collected_events = 0, collected_ent_bits, -+ requested_events, returned_ent_bits; -+ int ret, cpu; -+ void *hash; -+ -+ /* Only deliver entropy when SP800-90B self test is completed */ -+ if (!lrng_sp80090b_startup_complete_es(lrng_int_es_sched)) { -+ eb->e_bits[lrng_int_es_sched] = 0; -+ return; -+ } -+ -+ /* Lock guarding replacement of per-NUMA hash */ -+ read_lock_irqsave(&drng->hash_lock, flags); -+ -+ hash_cb = drng->hash_cb; -+ hash = drng->hash; -+ -+ /* The hash state of filled with all per-CPU pool hashes. */ -+ ret = hash_cb->hash_init(shash, hash); -+ if (ret) -+ goto err; -+ -+ /* Cap to maximum entropy that can ever be generated with given hash */ -+ lrng_cap_requested(hash_cb->hash_digestsize(hash) << 3, requested_bits); -+ requested_events = lrng_entropy_to_data(requested_bits + -+ lrng_compress_osr(), -+ lrng_sched_entropy_bits); -+ -+ /* -+ * Harvest entropy from each per-CPU hash state - even though we may -+ * have collected sufficient entropy, we will hash all per-CPU pools. -+ */ -+ for_each_online_cpu(cpu) { -+ struct lrng_drng *pcpu_drng = drng; -+ u32 digestsize, unused_events = 0; -+ int node = cpu_to_node(cpu); -+ -+ if (lrng_drng && lrng_drng[node]) -+ pcpu_drng = lrng_drng[node]; -+ -+ if (pcpu_drng == drng) { -+ found_events = lrng_sched_pool_hash_one(hash_cb, hash, -+ cpu, digest, -+ &digestsize); -+ } else { -+ read_lock_irqsave(&pcpu_drng->hash_lock, flags2); -+ found_events = -+ lrng_sched_pool_hash_one(pcpu_drng->hash_cb, -+ pcpu_drng->hash, cpu, -+ digest, &digestsize); -+ read_unlock_irqrestore(&pcpu_drng->hash_lock, flags2); -+ } -+ -+ /* Store all not-yet compressed data in data array into hash */ -+ ret = hash_cb->hash_update(shash, digest, digestsize); -+ if (ret) -+ goto err; -+ -+ collected_events += found_events; -+ if (collected_events > requested_events) { -+ unused_events = collected_events - requested_events; -+ atomic_add_return_relaxed(unused_events, -+ per_cpu_ptr(&lrng_sched_array_events, cpu)); -+ collected_events = requested_events; -+ } -+ pr_debug("%u scheduler-based events used from entropy array of CPU %d, %u scheduler-based events remain unused\n", -+ found_events - unused_events, cpu, unused_events); -+ } -+ -+ ret = hash_cb->hash_final(shash, digest); -+ if (ret) -+ goto err; -+ -+ collected_ent_bits = lrng_data_to_entropy(collected_events, -+ lrng_sched_entropy_bits); -+ /* Apply oversampling: discount requested oversampling rate */ -+ returned_ent_bits = lrng_reduce_by_osr(collected_ent_bits); -+ -+ pr_debug("obtained %u bits by collecting %u bits of entropy from scheduler-based noise source\n", -+ returned_ent_bits, collected_ent_bits); -+ -+ /* -+ * Truncate to available entropy as implicitly allowed by SP800-90B -+ * section 3.1.5.1.1 table 1 which awards truncated hashes full -+ * entropy. -+ * -+ * During boot time, we read requested_bits data with -+ * returned_ent_bits entropy. In case our conservative entropy -+ * estimate underestimates the available entropy we can transport as -+ * much available entropy as possible. -+ */ -+ memcpy(eb->e[lrng_int_es_sched], digest, -+ fully_seeded ? returned_ent_bits >> 3 : requested_bits >> 3); -+ eb->e_bits[lrng_int_es_sched] = returned_ent_bits; -+ -+out: -+ hash_cb->hash_desc_zero(shash); -+ read_unlock_irqrestore(&drng->hash_lock, flags); -+ memzero_explicit(digest, sizeof(digest)); -+ return; -+ -+err: -+ eb->e_bits[lrng_int_es_sched] = 0; -+ goto out; -+} -+ -+/* -+ * Concatenate full 32 bit word at the end of time array even when current -+ * ptr is not aligned to sizeof(data). -+ */ -+static void lrng_sched_array_add_u32(u32 data) -+{ -+ /* Increment pointer by number of slots taken for input value */ -+ u32 pre_ptr, mask, ptr = this_cpu_add_return(lrng_sched_array_ptr, -+ LRNG_DATA_SLOTS_PER_UINT); -+ unsigned int pre_array; -+ -+ lrng_data_split_u32(&ptr, &pre_ptr, &mask); -+ -+ /* MSB of data go into previous unit */ -+ pre_array = lrng_data_idx2array(pre_ptr); -+ /* zeroization of slot to ensure the following OR adds the data */ -+ this_cpu_and(lrng_sched_array[pre_array], ~(0xffffffff & ~mask)); -+ this_cpu_or(lrng_sched_array[pre_array], data & ~mask); -+ -+ /* -+ * Continuous compression is not allowed for scheduler noise source, -+ * so do not call lrng_sched_array_to_hash here. -+ */ -+ -+ /* LSB of data go into current unit */ -+ this_cpu_write(lrng_sched_array[lrng_data_idx2array(ptr)], -+ data & mask); -+} -+ -+/* Concatenate data of max LRNG_DATA_SLOTSIZE_MASK at the end of time array */ -+static void lrng_sched_array_add_slot(u32 data) -+{ -+ /* Get slot */ -+ u32 ptr = this_cpu_inc_return(lrng_sched_array_ptr) & -+ LRNG_DATA_WORD_MASK; -+ unsigned int array = lrng_data_idx2array(ptr); -+ unsigned int slot = lrng_data_idx2slot(ptr); -+ -+ /* zeroization of slot to ensure the following OR adds the data */ -+ this_cpu_and(lrng_sched_array[array], -+ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK, -+ slot))); -+ /* Store data into slot */ -+ this_cpu_or(lrng_sched_array[array], lrng_data_slot_val(data, slot)); -+ -+ /* -+ * Continuous compression is not allowed for scheduler noise source, -+ * so do not call lrng_sched_array_to_hash here. -+ */ -+} -+ -+static void -+lrng_time_process_common(u32 time, void(*add_time)(u32 data)) -+{ -+ enum lrng_health_res health_test; -+ -+ if (lrng_raw_sched_hires_entropy_store(time)) -+ return; -+ -+ health_test = lrng_health_test(time, lrng_int_es_sched); -+ if (health_test > lrng_health_fail_use) -+ return; -+ -+ if (health_test == lrng_health_pass) -+ atomic_inc_return(this_cpu_ptr(&lrng_sched_array_events)); -+ -+ add_time(time); -+ -+ /* -+ * We cannot call lrng_es_add_entropy() as this would call a schedule -+ * operation that is not permissible in scheduler context. -+ * As the scheduler ES provides a high bandwidth of entropy, we assume -+ * that other reseed triggers happen to pick up the scheduler ES -+ * entropy in due time. -+ */ -+} -+ -+/* Batching up of entropy in per-CPU array */ -+static void lrng_sched_time_process(void) -+{ -+ u32 now_time = random_get_entropy(); -+ -+ if (unlikely(!lrng_gcd_tested())) { -+ /* When GCD is unknown, we process the full time stamp */ -+ lrng_time_process_common(now_time, lrng_sched_array_add_u32); -+ lrng_gcd_add_value(now_time); -+ } else { -+ /* GCD is known and applied */ -+ lrng_time_process_common((now_time / lrng_gcd_get()) & -+ LRNG_DATA_SLOTSIZE_MASK, -+ lrng_sched_array_add_slot); -+ } -+ -+ lrng_sched_perf_time(now_time); -+} -+ -+void add_sched_randomness(const struct task_struct *p, int cpu) -+{ -+ if (lrng_highres_timer()) { -+ lrng_sched_time_process(); -+ } else { -+ u32 tmp = cpu; -+ -+ tmp ^= lrng_raw_sched_pid_entropy_store(p->pid) ? -+ 0 : (u32)p->pid; -+ tmp ^= lrng_raw_sched_starttime_entropy_store(p->start_time) ? -+ 0 : (u32)p->start_time; -+ tmp ^= lrng_raw_sched_nvcsw_entropy_store(p->nvcsw) ? -+ 0 : (u32)p->nvcsw; -+ -+ lrng_sched_time_process(); -+ lrng_sched_array_add_u32(tmp); -+ } -+} -+EXPORT_SYMBOL(add_sched_randomness); -+ -+static void lrng_sched_es_state(unsigned char *buf, size_t buflen) -+{ -+ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ -+ /* Assume the lrng_drng_init lock is taken by caller */ -+ snprintf(buf, buflen, -+ " Hash for operating entropy pool: %s\n" -+ " Available entropy: %u\n" -+ " per-CPU scheduler event collection size: %u\n" -+ " Standards compliance: %s\n" -+ " High-resolution timer: %s\n" -+ " Health test passed: %s\n", -+ lrng_drng_init->hash_cb->hash_name(), -+ lrng_sched_avail_entropy(0), -+ LRNG_DATA_NUM_VALUES, -+ lrng_sp80090b_compliant(lrng_int_es_sched) ? "SP800-90B " : "", -+ lrng_highres_timer() ? "true" : "false", -+ lrng_sp80090b_startup_complete_es(lrng_int_es_sched) ? -+ "true" : -+ "false"); -+} -+ -+struct lrng_es_cb lrng_es_sched = { -+ .name = "Scheduler", -+ .get_ent = lrng_sched_pool_hash, -+ .curr_entropy = lrng_sched_avail_entropy, -+ .max_entropy = lrng_sched_avail_pool_size, -+ .state = lrng_sched_es_state, -+ .reset = lrng_sched_reset, -+ .switch_hash = lrng_sched_switch_hash, -+}; ---- /dev/null -+++ b/drivers/char/lrng/lrng_health.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_HEALTH_H -+#define _LRNG_HEALTH_H -+ -+#include "lrng_es_mgr.h" -+ -+enum lrng_health_res { -+ lrng_health_pass, /* Health test passes on time stamp */ -+ lrng_health_fail_use, /* Time stamp unhealthy, but mix in */ -+ lrng_health_fail_drop /* Time stamp unhealthy, drop it */ -+}; -+ -+#ifdef CONFIG_LRNG_HEALTH_TESTS -+bool lrng_sp80090b_startup_complete_es(enum lrng_internal_es es); -+bool lrng_sp80090b_compliant(enum lrng_internal_es es); -+ -+enum lrng_health_res lrng_health_test(u32 now_time, enum lrng_internal_es es); -+void lrng_health_disable(void); -+#else /* CONFIG_LRNG_HEALTH_TESTS */ -+static inline bool lrng_sp80090b_startup_complete_es(enum lrng_internal_es es) -+{ -+ return true; -+} -+ -+static inline bool lrng_sp80090b_compliant(enum lrng_internal_es es) -+{ -+ return false; -+} -+ -+static inline enum lrng_health_res -+lrng_health_test(u32 now_time, enum lrng_internal_es es) -+{ -+ return lrng_health_pass; -+} -+static inline void lrng_health_disable(void) { } -+#endif /* CONFIG_LRNG_HEALTH_TESTS */ -+ -+#endif /* _LRNG_HEALTH_H */ ---- /dev/null -+++ b/drivers/char/lrng/lrng_testing.h -@@ -0,0 +1,85 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+/* -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#ifndef _LRNG_TESTING_H -+#define _LRNG_TESTING_H -+ -+#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY -+bool lrng_raw_hires_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_HIRES_ENTROPY */ -+static inline bool lrng_raw_hires_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY -+bool lrng_raw_jiffies_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */ -+static inline bool lrng_raw_jiffies_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY -+bool lrng_raw_irq_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_IRQ_ENTROPY */ -+static inline bool lrng_raw_irq_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY -+bool lrng_raw_retip_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_RETIP_ENTROPY */ -+static inline bool lrng_raw_retip_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY -+bool lrng_raw_regs_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_REGS_ENTROPY */ -+static inline bool lrng_raw_regs_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_ARRAY -+bool lrng_raw_array_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_ARRAY */ -+static inline bool lrng_raw_array_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_ARRAY */ -+ -+#ifdef CONFIG_LRNG_IRQ_PERF -+bool lrng_perf_time(u32 start); -+#else /* CONFIG_LRNG_IRQ_PERF */ -+static inline bool lrng_perf_time(u32 start) { return false; } -+#endif /*CONFIG_LRNG_IRQ_PERF */ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY -+bool lrng_raw_sched_hires_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY */ -+static inline bool -+lrng_raw_sched_hires_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY -+bool lrng_raw_sched_pid_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_SCHED_PID_ENTROPY */ -+static inline bool -+lrng_raw_sched_pid_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_SCHED_PID_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY -+bool lrng_raw_sched_starttime_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY */ -+static inline bool -+lrng_raw_sched_starttime_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY -+bool lrng_raw_sched_nvcsw_entropy_store(u32 value); -+#else /* CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY */ -+static inline bool -+lrng_raw_sched_nvcsw_entropy_store(u32 value) { return false; } -+#endif /* CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY */ -+ -+#ifdef CONFIG_LRNG_SCHED_PERF -+bool lrng_sched_perf_time(u32 start); -+#else /* CONFIG_LRNG_SCHED_PERF */ -+static inline bool lrng_sched_perf_time(u32 start) { return false; } -+#endif /*CONFIG_LRNG_SCHED_PERF */ -+ -+#endif /* _LRNG_TESTING_H */ diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch deleted file mode 100644 index d71387ed7..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch +++ /dev/null @@ -1,731 +0,0 @@ -From 928092951a36dddf3b48438712735ff3052bb405 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Tue, 25 Apr 2023 23:13:30 +0200 -Subject: [PATCH 14/25] LRNG - add SP800-90B compliant health tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Implement health tests for LRNG's internal entropy sources as mandated -by SP-800-90B. These internal entropy sources (scheduler and IRQ ES) -both rest on high-resolution time stamps as their noise source. The patch -contains the following health tests which are independently enabled and -applied for the mentioned entropy sources.: - -- stuck test: The stuck test calculates the first, second and third - discrete derivative of the time stamp to be processed by the hash - for the per-CPU entropy pool. Only if all three values are non-zero, - the received time delta is considered to be non-stuck. - -- SP800-90B Repetition Count Test (RCT): The LRNG uses an enhanced - version of the RCT specified in SP800-90B section 4.4.1. Instead of - counting identical back-to-back values, the input to the RCT is the - counting of the stuck values during the processing of received - interrupt events. The RCT is applied with alpha=2^-30 compliant to - the recommendation of FIPS 140-2 IG 9.8. During the counting operation, - the LRNG always calculates the RCT cut-off value of C. If that value - exceeds the allowed cut-off value, the LRNG will trigger the health - test failure discussed below. An error is logged to the kernel log - that such RCT failure occurred. This test is only applied and - enforced in FIPS mode, i.e. when the kernel compiled with - CONFIG_CONFIG_FIPS is started with fips=1. - -- SP800-90B Adaptive Proportion Test (APT): The LRNG implements the - APT as defined in SP800-90B section 4.4.2. The applied significance - level again is alpha=2^-30 compliant to the recommendation of FIPS - 140-2 IG 9.8. - -The aforementioned health tests are applied to the first 1,024 time stamps -obtained from interrupt events. In case one error is identified for either -the RCT, or the APT, the collected entropy is invalidated and the -SP800-90B startup health test is restarted. - -As long as the SP800-90B startup health test is not completed, all LRNG -random number output interfaces that may block will block and not generate -any data. This implies that only those potentially blocking interfaces are -defined to provide random numbers that are seeded with the interrupt noise -source being SP800-90B compliant. All other output interfaces will not be -affected by the SP800-90B startup test and thus are not considered -SP800-90B compliant. - -At runtime, the SP800-90B APT and RCT are applied to each time stamp -generated for a received interrupt. When either the APT and RCT indicates -a noise source failure, the LRNG is reset to a state it has immediately -after boot: - -- all entropy counters are set to zero - -- the SP800-90B startup tests are re-performed which implies that -getrandom(2) would block again until new entropy was collected - -To summarize, the following rules apply: - -• SP800-90B compliant output interfaces - - - /dev/random - - - getrandom(2) system call - - - get_random_bytes kernel-internal interface when being triggered by - the callback registered with add_random_ready_callback - -• SP800-90B non-compliant output interfaces - - - /dev/urandom - - - get_random_bytes kernel-internal interface called directly - - - randomize_page kernel-internal interface - - - get_random_u32 and get_random_u64 kernel-internal interfaces - - - get_random_u32_wait, get_random_u64_wait, get_random_int_wait, and - get_random_long_wait kernel-internal interfaces - -If either the RCT, or the APT health test fails irrespective whether -during initialization or runtime, the following actions occur: - - 1. The entropy of the entire entropy pool is invalidated. - - 2. All DRNGs are reset which imply that they are treated as being - not seeded and require a reseed during next invocation. - - 3. The SP800-90B startup health test are initiated with all - implications of the startup tests. That implies that from that point - on, new events must be observed and its entropy must be inserted into - the entropy pool before random numbers are calculated from the - entropy pool. - -Further details on the SP800-90B compliance and the availability of all -test tools required to perform all tests mandated by SP800-90B are -provided at [1]. - -The entire health testing code is compile-time configurable. - -The patch provides a CONFIG_BROKEN configuration of the APT / RCT cutoff -values which have a high likelihood to trigger the health test failure. -The BROKEN APT cutoff is set to the exact mean of the expected value if -the time stamps are equally distributed (512 time stamps divided by 16 -possible values due to using the 4 LSB of the time stamp). The BROKEN -RCT cutoff value is set to 1 which is likely to be triggered during -regular operation. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 140 +++++----- - drivers/char/lrng/Makefile | 2 + - drivers/char/lrng/lrng_health.c | 447 ++++++++++++++++++++++++++++++++ - 3 files changed, 519 insertions(+), 70 deletions(-) - create mode 100644 drivers/char/lrng/lrng_health.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -229,80 +229,80 @@ config LRNG_COLLECTION_SIZE - default 4096 if LRNG_COLLECTION_SIZE_4096 - default 8192 if LRNG_COLLECTION_SIZE_8192 - --# config LRNG_HEALTH_TESTS --# bool "Enable internal entropy source online health tests" --# depends on LRNG_TIMER_COMMON --# help --# The online health tests applied to the interrupt entropy --# source and to the scheduler entropy source to validate --# the noise source at runtime for fatal errors. These tests --# include SP800-90B compliant tests which are invoked if --# the system is booted with fips=1. In case of fatal errors --# during active SP800-90B tests, the issue is logged and --# the noise data is discarded. These tests are required for --# full compliance of the interrupt entropy source with --# SP800-90B. --# --# If both, the scheduler and the interrupt entropy sources, --# are enabled, the health tests for both are applied --# independent of each other. --# --# If unsure, say Y. --# --# config LRNG_RCT_BROKEN --# bool "SP800-90B RCT with dangerous low cutoff value" --# depends on LRNG_HEALTH_TESTS --# depends on BROKEN --# default n --# help --# This option enables a dangerously low SP800-90B repetitive --# count test (RCT) cutoff value which makes it very likely --# that the RCT is triggered to raise a self test failure. --# --# This option is ONLY intended for developers wanting to --# test the effectiveness of the SP800-90B RCT health test. --# --# If unsure, say N. --# --# config LRNG_APT_BROKEN --# bool "SP800-90B APT with dangerous low cutoff value" --# depends on LRNG_HEALTH_TESTS --# depends on BROKEN --# default n --# help --# This option enables a dangerously low SP800-90B adaptive --# proportion test (APT) cutoff value which makes it very --# likely that the APT is triggered to raise a self test --# failure. --# --# This option is ONLY intended for developers wanting to --# test the effectiveness of the SP800-90B APT health test. --# --# If unsure, say N. --# -+config LRNG_HEALTH_TESTS -+ bool "Enable internal entropy source online health tests" -+ depends on LRNG_TIMER_COMMON -+ help -+ The online health tests applied to the interrupt entropy -+ source and to the scheduler entropy source to validate -+ the noise source at runtime for fatal errors. These tests -+ include SP800-90B compliant tests which are invoked if -+ the system is booted with fips=1. In case of fatal errors -+ during active SP800-90B tests, the issue is logged and -+ the noise data is discarded. These tests are required for -+ full compliance of the interrupt entropy source with -+ SP800-90B. -+ -+ If both, the scheduler and the interrupt entropy sources, -+ are enabled, the health tests for both are applied -+ independent of each other. -+ -+ If unsure, say Y. -+ -+config LRNG_RCT_BROKEN -+ bool "SP800-90B RCT with dangerous low cutoff value" -+ depends on LRNG_HEALTH_TESTS -+ depends on BROKEN -+ default n -+ help -+ This option enables a dangerously low SP800-90B repetitive -+ count test (RCT) cutoff value which makes it very likely -+ that the RCT is triggered to raise a self test failure. -+ -+ This option is ONLY intended for developers wanting to -+ test the effectiveness of the SP800-90B RCT health test. -+ -+ If unsure, say N. -+ -+config LRNG_APT_BROKEN -+ bool "SP800-90B APT with dangerous low cutoff value" -+ depends on LRNG_HEALTH_TESTS -+ depends on BROKEN -+ default n -+ help -+ This option enables a dangerously low SP800-90B adaptive -+ proportion test (APT) cutoff value which makes it very -+ likely that the APT is triggered to raise a self test -+ failure. -+ -+ This option is ONLY intended for developers wanting to -+ test the effectiveness of the SP800-90B APT health test. -+ -+ If unsure, say N. -+ - # Default taken from SP800-90B sec 4.4.1 - significance level 2^-30 --# config LRNG_RCT_CUTOFF --# int --# default 31 if !LRNG_RCT_BROKEN --# default 1 if LRNG_RCT_BROKEN --# -+config LRNG_RCT_CUTOFF -+ int -+ default 31 if !LRNG_RCT_BROKEN -+ default 1 if LRNG_RCT_BROKEN -+ - # Default taken from SP800-90B sec 4.4.1 - significance level 2^-80 --# config LRNG_RCT_CUTOFF_PERMANENT --# int --# default 81 if !LRNG_RCT_BROKEN --# default 2 if LRNG_RCT_BROKEN --# -+config LRNG_RCT_CUTOFF_PERMANENT -+ int -+ default 81 if !LRNG_RCT_BROKEN -+ default 2 if LRNG_RCT_BROKEN -+ - # Default taken from SP800-90B sec 4.4.2 - significance level 2^-30 --# config LRNG_APT_CUTOFF --# int --# default 325 if !LRNG_APT_BROKEN --# default 32 if LRNG_APT_BROKEN --# -+config LRNG_APT_CUTOFF -+ int -+ default 325 if !LRNG_APT_BROKEN -+ default 32 if LRNG_APT_BROKEN -+ - # Default taken from SP800-90B sec 4.4.2 - significance level 2^-80 --# config LRNG_APT_CUTOFF_PERMANENT --# int --# default 371 if !LRNG_APT_BROKEN --# default 33 if LRNG_APT_BROKEN -+config LRNG_APT_CUTOFF_PERMANENT -+ int -+ default 371 if !LRNG_APT_BROKEN -+ default 33 if LRNG_APT_BROKEN - - comment "Interrupt Entropy Source" - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -21,3 +21,5 @@ obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_ - obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o - obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o - obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o -+ -+obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_health.c -@@ -0,0 +1,447 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * Entropy Source and DRNG Manager (LRNG) Health Testing -+ * -+ * Copyright (C) 2022 - 2023, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+ -+#include "lrng_definitions.h" -+#include "lrng_es_mgr.h" -+#include "lrng_health.h" -+ -+/* Stuck Test */ -+struct lrng_stuck_test { -+ u32 last_time; /* Stuck test: time of previous IRQ */ -+ u32 last_delta; /* Stuck test: delta of previous IRQ */ -+ u32 last_delta2; /* Stuck test: 2. time derivation of prev IRQ */ -+}; -+ -+/* Repetition Count Test */ -+struct lrng_rct { -+ atomic_t rct_count; /* Number of stuck values */ -+}; -+ -+/* Adaptive Proportion Test */ -+struct lrng_apt { -+ /* Data window size */ -+#define LRNG_APT_WINDOW_SIZE 512 -+ /* LSB of time stamp to process */ -+#define LRNG_APT_LSB 16 -+#define LRNG_APT_WORD_MASK (LRNG_APT_LSB - 1) -+ atomic_t apt_count; /* APT counter */ -+ atomic_t apt_base; /* APT base reference */ -+ -+ atomic_t apt_trigger; -+ bool apt_base_set; /* Is APT base set? */ -+}; -+ -+/* Health data collected for one entropy source */ -+struct lrng_health_es_state { -+ struct lrng_rct rct; -+ struct lrng_apt apt; -+ -+ /* SP800-90B startup health tests */ -+#define LRNG_SP80090B_STARTUP_SAMPLES 1024 -+#define LRNG_SP80090B_STARTUP_BLOCKS ((LRNG_SP80090B_STARTUP_SAMPLES + \ -+ LRNG_APT_WINDOW_SIZE - 1) / \ -+ LRNG_APT_WINDOW_SIZE) -+ bool sp80090b_startup_done; -+ atomic_t sp80090b_startup_blocks; -+}; -+ -+#define LRNG_HEALTH_ES_INIT(x) \ -+ x.rct.rct_count = ATOMIC_INIT(0), \ -+ x.apt.apt_count = ATOMIC_INIT(0), \ -+ x.apt.apt_base = ATOMIC_INIT(-1), \ -+ x.apt.apt_trigger = ATOMIC_INIT(LRNG_APT_WINDOW_SIZE), \ -+ x.apt.apt_base_set = false, \ -+ x.sp80090b_startup_blocks = ATOMIC_INIT(LRNG_SP80090B_STARTUP_BLOCKS), \ -+ x.sp80090b_startup_done = false, -+ -+/* The health test code must operate lock-less */ -+struct lrng_health { -+ bool health_test_enabled; -+ struct lrng_health_es_state es_state[lrng_int_es_last]; -+}; -+ -+static struct lrng_health lrng_health = { -+ .health_test_enabled = true, -+ -+#ifdef CONFIG_LRNG_IRQ -+ LRNG_HEALTH_ES_INIT(.es_state[lrng_int_es_irq]) -+#endif -+#ifdef CONFIG_LRNG_SCHED -+ LRNG_HEALTH_ES_INIT(.es_state[lrng_int_es_sched]) -+#endif -+}; -+ -+static DEFINE_PER_CPU(struct lrng_stuck_test[lrng_int_es_last], -+ lrng_stuck_test_array); -+ -+static bool lrng_sp80090b_health_requested(void) -+{ -+ /* Health tests are only requested in FIPS mode */ -+ return fips_enabled; -+} -+ -+static bool lrng_sp80090b_health_enabled(void) -+{ -+ struct lrng_health *health = &lrng_health; -+ -+ return lrng_sp80090b_health_requested() && health->health_test_enabled; -+} -+ -+/*************************************************************************** -+ * SP800-90B Compliance -+ * -+ * If the Linux-RNG is booted into FIPS mode, the following interfaces -+ * provide an SP800-90B compliant noise source: -+ * -+ * * /dev/random -+ * * getrandom(2) -+ * * get_random_bytes_full -+ * -+ * All other interfaces, including /dev/urandom or get_random_bytes without -+ * the add_random_ready_callback cannot claim to use an SP800-90B compliant -+ * noise source. -+ ***************************************************************************/ -+ -+/* -+ * Perform SP800-90B startup testing -+ */ -+static void lrng_sp80090b_startup(struct lrng_health *health, -+ enum lrng_internal_es es) -+{ -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ -+ if (!es_state->sp80090b_startup_done && -+ atomic_dec_and_test(&es_state->sp80090b_startup_blocks)) { -+ es_state->sp80090b_startup_done = true; -+ pr_info("SP800-90B startup health tests for internal entropy source %u completed\n", -+ es); -+ lrng_drng_force_reseed(); -+ -+ /* -+ * We cannot call lrng_es_add_entropy() as this may cause a -+ * schedule operation while in scheduler context for the -+ * scheduler ES. -+ */ -+ } -+} -+ -+/* -+ * Handle failure of SP800-90B startup testing -+ */ -+static void lrng_sp80090b_startup_failure(struct lrng_health *health, -+ enum lrng_internal_es es) -+{ -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ -+ -+ /* Reset of LRNG and its entropy - NOTE: we are in atomic context */ -+ lrng_reset(); -+ -+ /* -+ * Reset the SP800-90B startup test. -+ * -+ * NOTE SP800-90B section 4.3 bullet 4 does not specify what -+ * exactly is to be done in case of failure! Thus, we do what -+ * makes sense, i.e. restarting the health test and thus gating -+ * the output function of /dev/random and getrandom(2). -+ */ -+ atomic_set(&es_state->sp80090b_startup_blocks, -+ LRNG_SP80090B_STARTUP_BLOCKS); -+} -+ -+/* -+ * Handle failure of SP800-90B runtime testing -+ */ -+static void lrng_sp80090b_runtime_failure(struct lrng_health *health, -+ enum lrng_internal_es es) -+{ -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ -+ lrng_sp80090b_startup_failure(health, es); -+ es_state->sp80090b_startup_done = false; -+} -+ -+static void lrng_rct_reset(struct lrng_rct *rct); -+static void lrng_apt_reset(struct lrng_apt *apt, unsigned int time_masked); -+static void lrng_apt_restart(struct lrng_apt *apt); -+static void lrng_sp80090b_permanent_failure(struct lrng_health *health, -+ enum lrng_internal_es es) -+{ -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ struct lrng_apt *apt = &es_state->apt; -+ struct lrng_rct *rct = &es_state->rct; -+ -+ if (lrng_enforce_panic_on_permanent_health_failure()) { -+ panic("SP800-90B permanent health test failure for internal entropy source %u\n", -+ es); -+ } -+ -+ pr_err("SP800-90B permanent health test failure for internal entropy source %u - invalidating all existing entropy and initiate SP800-90B startup\n", -+ es); -+ lrng_sp80090b_runtime_failure(health, es); -+ -+ lrng_rct_reset(rct); -+ lrng_apt_reset(apt, 0); -+ lrng_apt_restart(apt); -+} -+ -+static void lrng_sp80090b_failure(struct lrng_health *health, -+ enum lrng_internal_es es) -+{ -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ -+ if (es_state->sp80090b_startup_done) { -+ pr_warn("SP800-90B runtime health test failure for internal entropy source %u - invalidating all existing entropy and initiate SP800-90B startup\n", es); -+ lrng_sp80090b_runtime_failure(health, es); -+ } else { -+ pr_warn("SP800-90B startup test failure for internal entropy source %u - resetting\n", es); -+ lrng_sp80090b_startup_failure(health, es); -+ } -+} -+ -+bool lrng_sp80090b_startup_complete_es(enum lrng_internal_es es) -+{ -+ struct lrng_health *health = &lrng_health; -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ -+ if (!lrng_sp80090b_health_enabled()) -+ return true; -+ -+ return es_state->sp80090b_startup_done; -+} -+ -+bool lrng_sp80090b_compliant(enum lrng_internal_es es) -+{ -+ struct lrng_health *health = &lrng_health; -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ -+ return lrng_sp80090b_health_enabled() && -+ es_state->sp80090b_startup_done; -+} -+ -+/*************************************************************************** -+ * Adaptive Proportion Test -+ * -+ * This test complies with SP800-90B section 4.4.2. -+ ***************************************************************************/ -+ -+/* -+ * Reset the APT counter -+ * -+ * @health [in] Reference to health state -+ */ -+static void lrng_apt_reset(struct lrng_apt *apt, unsigned int time_masked) -+{ -+ /* Reset APT */ -+ atomic_set(&apt->apt_count, 0); -+ atomic_set(&apt->apt_base, time_masked); -+} -+ -+static void lrng_apt_restart(struct lrng_apt *apt) -+{ -+ atomic_set(&apt->apt_trigger, LRNG_APT_WINDOW_SIZE); -+} -+ -+/* -+ * Insert a new entropy event into APT -+ * -+ * This function does is void as it does not decide about the fate of a time -+ * stamp. An APT failure can only happen at the same time of a stuck test -+ * failure. Thus, the stuck failure will already decide how the time stamp -+ * is handled. -+ * -+ * @health [in] Reference to health state -+ * @now_time [in] Time stamp to process -+ */ -+static void lrng_apt_insert(struct lrng_health *health, -+ unsigned int now_time, enum lrng_internal_es es) -+{ -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ struct lrng_apt *apt = &es_state->apt; -+ -+ if (!lrng_sp80090b_health_requested()) -+ return; -+ -+ now_time &= LRNG_APT_WORD_MASK; -+ -+ /* Initialization of APT */ -+ if (!apt->apt_base_set) { -+ atomic_set(&apt->apt_base, now_time); -+ apt->apt_base_set = true; -+ return; -+ } -+ -+ if (now_time == (unsigned int)atomic_read(&apt->apt_base)) { -+ u32 apt_val = (u32)atomic_inc_return_relaxed(&apt->apt_count); -+ -+ if (apt_val >= CONFIG_LRNG_APT_CUTOFF_PERMANENT) -+ lrng_sp80090b_permanent_failure(health, es); -+ else if (apt_val >= CONFIG_LRNG_APT_CUTOFF) -+ lrng_sp80090b_failure(health, es); -+ } -+ -+ if (atomic_dec_and_test(&apt->apt_trigger)) { -+ lrng_apt_restart(apt); -+ lrng_apt_reset(apt, now_time); -+ lrng_sp80090b_startup(health, es); -+ } -+} -+ -+/*************************************************************************** -+ * Repetition Count Test -+ * -+ * The LRNG uses an enhanced version of the Repetition Count Test -+ * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical -+ * back-to-back values, the input to the RCT is the counting of the stuck -+ * values while filling the entropy pool. -+ * -+ * The RCT is applied with an alpha of 2^-30 compliant to FIPS 140-2 IG 9.8. -+ * -+ * During the counting operation, the LRNG always calculates the RCT -+ * cut-off value of C. If that value exceeds the allowed cut-off value, -+ * the LRNG will invalidate all entropy for the entropy pool which implies -+ * that no data can be extracted from the entropy pool unless new entropy -+ * is received. -+ ***************************************************************************/ -+ -+static void lrng_rct_reset(struct lrng_rct *rct) -+{ -+ /* Reset RCT */ -+ atomic_set(&rct->rct_count, 0); -+} -+ -+/* -+ * Hot code path - Insert data for Repetition Count Test -+ * -+ * @health: Reference to health information -+ * @stuck: Decision of stuck test -+ */ -+static void lrng_rct(struct lrng_health *health, enum lrng_internal_es es, -+ int stuck) -+{ -+ struct lrng_health_es_state *es_state = &health->es_state[es]; -+ struct lrng_rct *rct = &es_state->rct; -+ -+ if (!lrng_sp80090b_health_requested()) -+ return; -+ -+ if (stuck) { -+ u32 rct_count = atomic_add_return_relaxed(1, &rct->rct_count); -+ -+ /* -+ * The cutoff value is based on the following consideration: -+ * alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8. -+ * In addition, we imply an entropy value H of 1 bit as this -+ * is the minimum entropy required to provide full entropy. -+ * -+ * Note, rct_count (which equals to value B in the -+ * pseudo code of SP800-90B section 4.4.1) starts with zero. -+ * Hence we need to subtract one from the cutoff value as -+ * calculated following SP800-90B. -+ */ -+ if (rct_count >= CONFIG_LRNG_RCT_CUTOFF_PERMANENT) -+ lrng_sp80090b_permanent_failure(health, es); -+ else if (rct_count >= CONFIG_LRNG_RCT_CUTOFF) -+ lrng_sp80090b_failure(health, es); -+ } else { -+ lrng_rct_reset(rct); -+ } -+} -+ -+/*************************************************************************** -+ * Stuck Test -+ * -+ * Checking the: -+ * 1st derivative of the event occurrence (time delta) -+ * 2nd derivative of the event occurrence (delta of time deltas) -+ * 3rd derivative of the event occurrence (delta of delta of time deltas) -+ * -+ * All values must always be non-zero. The stuck test is only valid disabled if -+ * high-resolution time stamps are identified after initialization. -+ ***************************************************************************/ -+ -+static u32 lrng_delta(u32 prev, u32 next) -+{ -+ /* -+ * Note that this (unsigned) subtraction does yield the correct value -+ * in the wraparound-case, i.e. when next < prev. -+ */ -+ return (next - prev); -+} -+ -+/* -+ * Hot code path -+ * -+ * @health: Reference to health information -+ * @now: Event time -+ * @return: 0 event occurrence not stuck (good time stamp) -+ * != 0 event occurrence stuck (reject time stamp) -+ */ -+static int lrng_irq_stuck(enum lrng_internal_es es, u32 now_time) -+{ -+ struct lrng_stuck_test *stuck = this_cpu_ptr(lrng_stuck_test_array); -+ u32 delta = lrng_delta(stuck[es].last_time, now_time); -+ u32 delta2 = lrng_delta(stuck[es].last_delta, delta); -+ u32 delta3 = lrng_delta(stuck[es].last_delta2, delta2); -+ -+ stuck[es].last_time = now_time; -+ stuck[es].last_delta = delta; -+ stuck[es].last_delta2 = delta2; -+ -+ if (!delta || !delta2 || !delta3) -+ return 1; -+ -+ return 0; -+} -+ -+/*************************************************************************** -+ * Health test interfaces -+ ***************************************************************************/ -+ -+/* -+ * Disable all health tests -+ */ -+void lrng_health_disable(void) -+{ -+ struct lrng_health *health = &lrng_health; -+ -+ health->health_test_enabled = false; -+ -+ if (lrng_sp80090b_health_requested()) -+ pr_warn("SP800-90B compliance requested but the Linux RNG is NOT SP800-90B compliant\n"); -+} -+ -+/* -+ * Hot code path - Perform health test on time stamp received from an event -+ * -+ * @now_time Time stamp -+ */ -+enum lrng_health_res lrng_health_test(u32 now_time, enum lrng_internal_es es) -+{ -+ struct lrng_health *health = &lrng_health; -+ int stuck; -+ -+ if (!health->health_test_enabled) -+ return lrng_health_pass; -+ -+ lrng_apt_insert(health, now_time, es); -+ -+ stuck = lrng_irq_stuck(es, now_time); -+ lrng_rct(health, es, stuck); -+ if (stuck) { -+ /* SP800-90B disallows using a failing health test time stamp */ -+ return lrng_sp80090b_health_requested() ? -+ lrng_health_fail_drop : lrng_health_fail_use; -+ } -+ -+ return lrng_health_pass; -+} diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch deleted file mode 100644 index 2bd89fab0..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch +++ /dev/null @@ -1,207 +0,0 @@ -From 660ed995cea5080ea33d0721592100ffd31bf2e4 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Mon, 20 Feb 2023 22:07:27 +0100 -Subject: [PATCH 15/25] LRNG - add random.c entropy source support - -The random.c implementation can be used as an entropy source by the -LRNG. This support can be enabled at compile time. - -The entropy rate can be set at compile time which is only applied: - -- once the random.c considers itself fully seeded, and - -- the kernel does not operate in FIPS mode (i.e. fips=1 is not set at - the kernel command line) - -If one of these properties is not set, the ES will obtain data, but will -credit it with zero bits of entropy. For the first bullet, it is clear -why it will have zero bits of entropy. But for the second property, this -is set because the random.c is not operating SP800-90B compliant and -thus must be treated to not deliver any entropy in FIPS mode. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 56 ++++++++--------- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_es_krng.c | 100 +++++++++++++++++++++++++++++++ - 3 files changed, 129 insertions(+), 28 deletions(-) - create mode 100644 drivers/char/lrng/lrng_es_krng.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -586,34 +586,34 @@ config LRNG_SCHED_ENTROPY_RATE - scheduler entropy source will still deliver data but without - being credited with entropy. - --# comment "Kernel RNG Entropy Source" --# --# config LRNG_KERNEL_RNG --# bool "Enable Kernel RNG as LRNG Seed Source" --# depends on RANDOM_DEFAULT_IMPL --# help --# The LRNG may use the kernel RNG (random.c) as entropy --# source. --# --# config LRNG_KERNEL_RNG_ENTROPY_RATE --# int "Kernel RNG Entropy Source Entropy Rate" --# depends on LRNG_KERNEL_RNG --# range 0 256 --# default 256 --# help --# The option defines the amount of entropy the LRNG applies to 256 --# bits of data obtained from the kernel RNG entropy source. The --# LRNG enforces the limit that this value must be in the range --# between 0 and 256. --# --# When configuring this value to 0, the kernel RNG entropy source --# will provide 256 bits of data without being credited to contain --# entropy. --# --# Note: This value is set to 0 automatically when booting the --# kernel in FIPS mode (with fips=1 kernel command line option). --# This is due to the fact that random.c is not SP800-90B --# compliant. -+comment "Kernel RNG Entropy Source" -+ -+config LRNG_KERNEL_RNG -+ bool "Enable Kernel RNG as LRNG Seed Source" -+ depends on RANDOM_DEFAULT_IMPL -+ help -+ The LRNG may use the kernel RNG (random.c) as entropy -+ source. -+ -+config LRNG_KERNEL_RNG_ENTROPY_RATE -+ int "Kernel RNG Entropy Source Entropy Rate" -+ depends on LRNG_KERNEL_RNG -+ range 0 256 -+ default 256 -+ help -+ The option defines the amount of entropy the LRNG applies to 256 -+ bits of data obtained from the kernel RNG entropy source. The -+ LRNG enforces the limit that this value must be in the range -+ between 0 and 256. -+ -+ When configuring this value to 0, the kernel RNG entropy source -+ will provide 256 bits of data without being credited to contain -+ entropy. -+ -+ Note: This value is set to 0 automatically when booting the -+ kernel in FIPS mode (with fips=1 kernel command line option). -+ This is due to the fact that random.c is not SP800-90B -+ compliant. - - endmenu # "Entropy Source Configuration" - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -20,6 +20,7 @@ obj-$(CONFIG_LRNG_DRNG_ATOMIC) += lrng_ - - obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng_es_timer_common.o - obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o -+obj-$(CONFIG_LRNG_KERNEL_RNG) += lrng_es_krng.o - obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o - - obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_krng.c -@@ -0,0 +1,100 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Fast Entropy Source: Linux kernel RNG (random.c) -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+ -+#include "lrng_es_aux.h" -+#include "lrng_es_krng.h" -+ -+static u32 krng_entropy = CONFIG_LRNG_KERNEL_RNG_ENTROPY_RATE; -+#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG -+module_param(krng_entropy, uint, 0644); -+MODULE_PARM_DESC(krng_entropy, "Entropy in bits of 256 data bits from the kernel RNG noise source"); -+#endif -+ -+static atomic_t lrng_krng_initial_rate = ATOMIC_INIT(0); -+ -+static u32 lrng_krng_fips_entropylevel(u32 entropylevel) -+{ -+ return fips_enabled ? 0 : entropylevel; -+} -+ -+static int lrng_krng_adjust_entropy(void) -+{ -+ u32 entropylevel; -+ -+ krng_entropy = atomic_read_u32(&lrng_krng_initial_rate); -+ -+ entropylevel = lrng_krng_fips_entropylevel(krng_entropy); -+ pr_debug("Kernel RNG is fully seeded, setting entropy rate to %u bits of entropy\n", -+ entropylevel); -+ lrng_drng_force_reseed(); -+ if (entropylevel) -+ lrng_es_add_entropy(); -+ return 0; -+} -+ -+static u32 lrng_krng_entropylevel(u32 requested_bits) -+{ -+ static bool init = false; -+ -+ if (unlikely(!init) && rng_is_initialized()) { -+ init = true; -+ lrng_krng_adjust_entropy(); -+ } -+ -+ return lrng_fast_noise_entropylevel( -+ lrng_krng_fips_entropylevel(krng_entropy), requested_bits); -+} -+ -+static u32 lrng_krng_poolsize(void) -+{ -+ return lrng_krng_entropylevel(lrng_security_strength()); -+} -+ -+/* -+ * lrng_krng_get() - Get kernel RNG entropy -+ * -+ * @eb: entropy buffer to store entropy -+ * @requested_bits: requested entropy in bits -+ */ -+static void lrng_krng_get(struct entropy_buf *eb, u32 requested_bits, -+ bool __unused) -+{ -+ u32 ent_bits = lrng_krng_entropylevel(requested_bits); -+ -+ get_random_bytes(eb->e[lrng_ext_es_krng], requested_bits >> 3); -+ -+ pr_debug("obtained %u bits of entropy from kernel RNG noise source\n", -+ ent_bits); -+ -+ eb->e_bits[lrng_ext_es_krng] = ent_bits; -+} -+ -+static void lrng_krng_es_state(unsigned char *buf, size_t buflen) -+{ -+ snprintf(buf, buflen, -+ " Available entropy: %u\n" -+ " Entropy Rate per 256 data bits: %u\n", -+ lrng_krng_poolsize(), -+ lrng_krng_entropylevel(256)); -+} -+ -+struct lrng_es_cb lrng_es_krng = { -+ .name = "KernelRNG", -+ .get_ent = lrng_krng_get, -+ .curr_entropy = lrng_krng_entropylevel, -+ .max_entropy = lrng_krng_poolsize, -+ .state = lrng_krng_es_state, -+ .reset = NULL, -+ .switch_hash = NULL, -+}; diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch deleted file mode 100644 index f666edeb2..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch +++ /dev/null @@ -1,401 +0,0 @@ -From b0559761b34dcd706c96ea42d546c53a99b3d028 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Mon, 20 Feb 2023 22:08:23 +0100 -Subject: [PATCH 16/25] LRNG - CPU entropy source - -Certain CPUs provide instructions giving access to an entropy source -(e.g. RDSEED on Intel/AMD, DARN on POWER, etc.). The LRNG can utilize -the entropy source to seed its DRNG from. - -Some CPU entropy sources (e.g. POWER DARN, RISC-V) are defined to -deliver data that does not contain full entropy. In this case, the CPU -is sampled for as much data as needed to obtain the required amount of -entropy. In this case, a compression operation using the set message -digest is applied. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 76 ++++----- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_es_cpu.c | 281 ++++++++++++++++++++++++++++++++ - 3 files changed, 320 insertions(+), 38 deletions(-) - create mode 100644 drivers/char/lrng/lrng_es_cpu.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -496,44 +496,44 @@ config LRNG_IRQ_ENTROPY_RATE - # will provide 256 bits of data without being credited to contain - # entropy. - # --# comment "CPU Entropy Source" --# --# config LRNG_CPU --# bool "Enable CPU Entropy Source as LRNG Seed Source" --# default y --# help --# Current CPUs commonly contain entropy sources which can be --# used to seed the LRNG. For example, the Intel RDSEED --# instruction, or the POWER DARN instruction will be sourced --# to seed the LRNG if this option is enabled. --# --# Note, if this option is enabled and the underlying CPU --# does not offer such entropy source, the LRNG will automatically --# detect this and ignore the hardware. --# --# config LRNG_CPU_FULL_ENT_MULTIPLIER --# int --# default 1 if !LRNG_TEST_CPU_ES_COMPRESSION --# default 123 if LRNG_TEST_CPU_ES_COMPRESSION --# --# config LRNG_CPU_ENTROPY_RATE --# int "CPU Entropy Source Entropy Rate" --# depends on LRNG_CPU --# range 0 256 --# default 8 --# help --# The option defines the amount of entropy the LRNG applies to 256 --# bits of data obtained from the CPU entropy source. The LRNG --# enforces the limit that this value must be in the range between --# 0 and 256. --# --# When configuring this value to 0, the CPU entropy source will --# provide 256 bits of data without being credited to contain --# entropy. --# --# Note, this option is overwritten when the option --# CONFIG_RANDOM_TRUST_CPU is set. --# -+comment "CPU Entropy Source" -+ -+config LRNG_CPU -+ bool "Enable CPU Entropy Source as LRNG Seed Source" -+ default y -+ help -+ Current CPUs commonly contain entropy sources which can be -+ used to seed the LRNG. For example, the Intel RDSEED -+ instruction, or the POWER DARN instruction will be sourced -+ to seed the LRNG if this option is enabled. -+ -+ Note, if this option is enabled and the underlying CPU -+ does not offer such entropy source, the LRNG will automatically -+ detect this and ignore the hardware. -+ -+config LRNG_CPU_FULL_ENT_MULTIPLIER -+ int -+ default 1 if !LRNG_TEST_CPU_ES_COMPRESSION -+ default 123 if LRNG_TEST_CPU_ES_COMPRESSION -+ -+config LRNG_CPU_ENTROPY_RATE -+ int "CPU Entropy Source Entropy Rate" -+ depends on LRNG_CPU -+ range 0 256 -+ default 8 -+ help -+ The option defines the amount of entropy the LRNG applies to 256 -+ bits of data obtained from the CPU entropy source. The LRNG -+ enforces the limit that this value must be in the range between -+ 0 and 256. -+ -+ When configuring this value to 0, the CPU entropy source will -+ provide 256 bits of data without being credited to contain -+ entropy. -+ -+ Note, this option is overwritten when the option -+ CONFIG_RANDOM_TRUST_CPU is set. -+ - comment "Scheduler Entropy Source" - - config LRNG_SCHED ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -22,5 +22,6 @@ obj-$(CONFIG_LRNG_TIMER_COMMON) += lrng - obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq.o - obj-$(CONFIG_LRNG_KERNEL_RNG) += lrng_es_krng.o - obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o -+obj-$(CONFIG_LRNG_CPU) += lrng_es_cpu.o - - obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_cpu.c -@@ -0,0 +1,281 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Fast Entropy Source: CPU-based entropy source -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_definitions.h" -+#include "lrng_es_aux.h" -+#include "lrng_es_cpu.h" -+ -+/* -+ * Estimated entropy of data is a 32th of LRNG_DRNG_SECURITY_STRENGTH_BITS. -+ * As we have no ability to review the implementation of those noise sources, -+ * it is prudent to have a conservative estimate here. -+ */ -+#define LRNG_ARCHRANDOM_DEFAULT_STRENGTH CONFIG_LRNG_CPU_ENTROPY_RATE -+#define LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH LRNG_DRNG_SECURITY_STRENGTH_BITS -+#ifdef CONFIG_RANDOM_TRUST_CPU -+static u32 cpu_entropy = LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH; -+#else -+static u32 cpu_entropy = LRNG_ARCHRANDOM_DEFAULT_STRENGTH; -+#endif -+#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG -+module_param(cpu_entropy, uint, 0644); -+MODULE_PARM_DESC(cpu_entropy, "Entropy in bits of 256 data bits from CPU noise source (e.g. RDSEED)"); -+#endif -+ -+static int __init lrng_parse_trust_cpu(char *arg) -+{ -+ int ret; -+ bool trust_cpu = false; -+ -+ ret = kstrtobool(arg, &trust_cpu); -+ if (ret) -+ return ret; -+ -+ if (trust_cpu) -+ cpu_entropy = LRNG_ARCHRANDOM_TRUST_CPU_STRENGTH; -+ else -+ cpu_entropy = LRNG_ARCHRANDOM_DEFAULT_STRENGTH; -+ -+ lrng_force_fully_seeded(); -+ -+ return 0; -+} -+early_param("random.trust_cpu", lrng_parse_trust_cpu); -+ -+static u32 lrng_cpu_entropylevel(u32 requested_bits) -+{ -+ return lrng_fast_noise_entropylevel(cpu_entropy, requested_bits); -+} -+ -+static u32 lrng_cpu_poolsize(void) -+{ -+ return lrng_cpu_entropylevel(lrng_security_strength()); -+} -+ -+static u32 lrng_get_cpu_data(u8 *outbuf, u32 requested_bits) -+{ -+ size_t longs = 0; -+ u32 i, req = requested_bits >> 3; -+ -+ /* operate on full blocks */ -+ BUILD_BUG_ON(LRNG_DRNG_SECURITY_STRENGTH_BYTES % sizeof(unsigned long)); -+ BUILD_BUG_ON(LRNG_SEED_BUFFER_INIT_ADD_BITS % sizeof(unsigned long)); -+ /* ensure we have aligned buffers */ -+ BUILD_BUG_ON(LRNG_KCAPI_ALIGN % sizeof(unsigned long)); -+ -+ for (i = 0; i < req; i += longs) { -+ longs = arch_get_random_seed_longs( -+ (unsigned long *)(outbuf + i), req - i); -+ if (longs) -+ continue; -+ longs = arch_get_random_longs((unsigned long *)(outbuf + i), -+ req - i); -+ if (!longs) { -+ cpu_entropy = 0; -+ return 0; -+ } -+ } -+ -+ return requested_bits; -+} -+ -+static u32 lrng_get_cpu_data_compress(u8 *outbuf, u32 requested_bits, -+ u32 data_multiplier) -+{ -+ SHASH_DESC_ON_STACK(shash, NULL); -+ const struct lrng_hash_cb *hash_cb; -+ struct lrng_drng *drng = lrng_drng_node_instance(); -+ unsigned long flags; -+ u32 ent_bits = 0, i, partial_bits = 0, digestsize, digestsize_bits, -+ full_bits; -+ void *hash; -+ -+ read_lock_irqsave(&drng->hash_lock, flags); -+ hash_cb = drng->hash_cb; -+ hash = drng->hash; -+ -+ digestsize = hash_cb->hash_digestsize(hash); -+ digestsize_bits = digestsize << 3; -+ /* Cap to maximum entropy that can ever be generated with given hash */ -+ lrng_cap_requested(digestsize_bits, requested_bits); -+ full_bits = requested_bits * data_multiplier; -+ -+ /* Calculate oversampling for SP800-90C */ -+ if (lrng_sp80090c_compliant()) { -+ /* Complete amount of bits to be pulled */ -+ full_bits += LRNG_OVERSAMPLE_ES_BITS * data_multiplier; -+ /* Full blocks that will be pulled */ -+ data_multiplier = full_bits / requested_bits; -+ /* Partial block in bits to be pulled */ -+ partial_bits = full_bits - (data_multiplier * requested_bits); -+ } -+ -+ if (hash_cb->hash_init(shash, hash)) -+ goto out; -+ -+ /* Hash all data from the CPU entropy source */ -+ for (i = 0; i < data_multiplier; i++) { -+ ent_bits = lrng_get_cpu_data(outbuf, requested_bits); -+ if (!ent_bits) -+ goto out; -+ -+ if (hash_cb->hash_update(shash, outbuf, ent_bits >> 3)) -+ goto err; -+ } -+ -+ /* Hash partial block, if applicable */ -+ ent_bits = lrng_get_cpu_data(outbuf, partial_bits); -+ if (ent_bits && -+ hash_cb->hash_update(shash, outbuf, ent_bits >> 3)) -+ goto err; -+ -+ pr_debug("pulled %u bits from CPU RNG entropy source\n", full_bits); -+ ent_bits = requested_bits; -+ -+ /* Generate the compressed data to be returned to the caller */ -+ if (requested_bits < digestsize_bits) { -+ u8 digest[LRNG_MAX_DIGESTSIZE]; -+ -+ if (hash_cb->hash_final(shash, digest)) -+ goto err; -+ -+ /* Truncate output data to requested size */ -+ memcpy(outbuf, digest, requested_bits >> 3); -+ memzero_explicit(digest, digestsize); -+ } else { -+ if (hash_cb->hash_final(shash, outbuf)) -+ goto err; -+ } -+ -+out: -+ hash_cb->hash_desc_zero(shash); -+ read_unlock_irqrestore(&drng->hash_lock, flags); -+ return ent_bits; -+ -+err: -+ ent_bits = 0; -+ goto out; -+} -+ -+/* -+ * If CPU entropy source requires does not return full entropy, return the -+ * multiplier of how much data shall be sampled from it. -+ */ -+static u32 lrng_cpu_multiplier(void) -+{ -+ static u32 data_multiplier = 0; -+ unsigned long v; -+ -+ if (data_multiplier > 0) -+ return data_multiplier; -+ -+ if (IS_ENABLED(CONFIG_X86) && !arch_get_random_seed_longs(&v, 1)) { -+ /* -+ * Intel SPEC: pulling 512 blocks from RDRAND ensures -+ * one reseed making it logically equivalent to RDSEED. -+ */ -+ data_multiplier = 512; -+ } else if (IS_ENABLED(CONFIG_PPC)) { -+ /* -+ * PowerISA defines DARN to deliver at least 0.5 bits of -+ * entropy per data bit. -+ */ -+ data_multiplier = 2; -+ } else if (IS_ENABLED(CONFIG_RISCV)) { -+ /* -+ * riscv-crypto-spec-scalar-1.0.0-rc6.pdf section 4.2 defines -+ * this requirement. -+ */ -+ data_multiplier = 2; -+ } else { -+ /* CPU provides full entropy */ -+ data_multiplier = CONFIG_LRNG_CPU_FULL_ENT_MULTIPLIER; -+ } -+ return data_multiplier; -+} -+ -+static int -+lrng_cpu_switch_hash(struct lrng_drng *drng, int node, -+ const struct lrng_hash_cb *new_cb, void *new_hash, -+ const struct lrng_hash_cb *old_cb) -+{ -+ u32 digestsize, multiplier; -+ -+ if (!IS_ENABLED(CONFIG_LRNG_SWITCH)) -+ return -EOPNOTSUPP; -+ -+ digestsize = lrng_get_digestsize(); -+ multiplier = lrng_cpu_multiplier(); -+ -+ /* -+ * It would be security violation if the new digestsize is smaller than -+ * the set CPU entropy rate. -+ */ -+ WARN_ON(multiplier > 1 && digestsize < cpu_entropy); -+ cpu_entropy = min_t(u32, digestsize, cpu_entropy); -+ return 0; -+} -+ -+/* -+ * lrng_get_arch() - Get CPU entropy source entropy -+ * -+ * @eb: entropy buffer to store entropy -+ * @requested_bits: requested entropy in bits -+ */ -+static void lrng_cpu_get(struct entropy_buf *eb, u32 requested_bits, -+ bool __unused) -+{ -+ u32 ent_bits, data_multiplier = lrng_cpu_multiplier(); -+ -+ if (data_multiplier <= 1) { -+ ent_bits = lrng_get_cpu_data(eb->e[lrng_ext_es_cpu], -+ requested_bits); -+ } else { -+ ent_bits = lrng_get_cpu_data_compress(eb->e[lrng_ext_es_cpu], -+ requested_bits, -+ data_multiplier); -+ } -+ -+ ent_bits = lrng_cpu_entropylevel(ent_bits); -+ pr_debug("obtained %u bits of entropy from CPU RNG entropy source\n", -+ ent_bits); -+ eb->e_bits[lrng_ext_es_cpu] = ent_bits; -+} -+ -+static void lrng_cpu_es_state(unsigned char *buf, size_t buflen) -+{ -+ const struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); -+ u32 data_multiplier = lrng_cpu_multiplier(); -+ -+ /* Assume the lrng_drng_init lock is taken by caller */ -+ snprintf(buf, buflen, -+ " Hash for compressing data: %s\n" -+ " Available entropy: %u\n" -+ " Data multiplier: %u\n", -+ (data_multiplier <= 1) ? -+ "N/A" : lrng_drng_init->hash_cb->hash_name(), -+ lrng_cpu_poolsize(), -+ data_multiplier); -+} -+ -+struct lrng_es_cb lrng_es_cpu = { -+ .name = "CPU", -+ .get_ent = lrng_cpu_get, -+ .curr_entropy = lrng_cpu_entropylevel, -+ .max_entropy = lrng_cpu_poolsize, -+ .state = lrng_cpu_es_state, -+ .reset = NULL, -+ .switch_hash = lrng_cpu_switch_hash, -+}; diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch deleted file mode 100644 index e5f88a20b..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch +++ /dev/null @@ -1,571 +0,0 @@ -From 6f2210ea4a3b09563a0587b21ccca4d847c6bc95 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 27 Aug 2023 17:11:37 +0200 -Subject: [PATCH 17/25] LRNG - add Jitter RNG fast noise source - -The Jitter RNG fast noise source implemented as part of the kernel -crypto API is queried for 256 bits of entropy at the time the seed -buffer managed by the LRNG is about to be filled. - -The default entropy rate is set to 16 bits of entropy per 256 bits of -data. In FIPS mode, the ratio is set to 256 bits of entropy per 256 bits -of data considering that the Jitter RNG passed the NIST ENT validation -to claim full entropy. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 172 +++++++-------- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_es_jent.c | 356 +++++++++++++++++++++++++++++++ - 3 files changed, 443 insertions(+), 86 deletions(-) - create mode 100644 drivers/char/lrng/lrng_es_jent.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -410,92 +410,92 @@ config LRNG_IRQ_ENTROPY_RATE - interrupt entropy source will still deliver data but without - being credited with entropy. - --# comment "Jitter RNG Entropy Source" --# --# config LRNG_JENT --# bool "Enable Jitter RNG as LRNG Seed Source" --# depends on CRYPTO --# select CRYPTO_JITTERENTROPY --# help --# The LRNG may use the Jitter RNG as entropy source. Enabling --# this option enables the use of the Jitter RNG. Its default --# entropy level is 16 bits of entropy per 256 data bits delivered --# by the Jitter RNG. This entropy level can be changed at boot --# time or at runtime with the lrng_base.jitterrng configuration --# variable. --# --#choice --# prompt "Jitter RNG Async Block Number" --# default LRNG_JENT_ENTROPY_BLOCKS_NO_128 --# depends on LRNG_JENT --# help --# Select the number of Jitter RNG entropy blocks the asynchronous --# collection operation will fill. A caller for Jitter RNG entropy --# will be given data from the pre-filled blocks if available to --# prevent the Jitter RNG from utilizing the CPU too much in a --# possible hot code path. --# --# The number specifies the number of 256/384 bit blocks that will --# be held in memory and asynchronously filled with Jitter RNG data. --# --# The asynchronous entropy collection can also be disabled at --# kernel startup time when setting the command line option of --# lrng_es_jent.jent_async_enabled=0. Also, setting this option at --# runtime is allowed via the corresponding SysFS interface. This --# option is only available with the options SysFS and --# CONFIG_LRNG_RUNTIME_ES_CONFIG enabled. --# --# config LRNG_JENT_ENTROPY_BLOCKS_DISABLED --# bool "Async collection disabled" --# --# # Any block number is allowed, provided it is a power of 2 and --# # equal or larger than 4 (4 is due to the division in --# # lrng_jent_async_get when deciding to wake up the monitor). --# config LRNG_JENT_ENTROPY_BLOCKS_NO_32 --# bool "32 blocks" --# --# config LRNG_JENT_ENTROPY_BLOCKS_NO_64 --# bool "64 blocks" --# --# config LRNG_JENT_ENTROPY_BLOCKS_NO_128 --# bool "128 blocks (default)" --# --# config LRNG_JENT_ENTROPY_BLOCKS_NO_256 --# bool "256 blocks" --# --# config LRNG_JENT_ENTROPY_BLOCKS_NO_512 --# bool "512 blocks" --# --# config LRNG_JENT_ENTROPY_BLOCKS_NO_1024 --# bool "1024 blocks" --# --#endchoice --# --#config LRNG_JENT_ENTROPY_BLOCKS --# int --# default 0 if LRNG_JENT_ENTROPY_BLOCKS_DISABLED --# default 32 if LRNG_JENT_ENTROPY_BLOCKS_NO_32 --# default 64 if LRNG_JENT_ENTROPY_BLOCKS_NO_64 --# default 128 if LRNG_JENT_ENTROPY_BLOCKS_NO_128 --# default 256 if LRNG_JENT_ENTROPY_BLOCKS_NO_256 --# default 512 if LRNG_JENT_ENTROPY_BLOCKS_NO_512 --# default 1024 if LRNG_JENT_ENTROPY_BLOCKS_NO_1024 --# --# config LRNG_JENT_ENTROPY_RATE --# int "Jitter RNG Entropy Source Entropy Rate" --# depends on LRNG_JENT --# range 0 256 --# default 16 --# help --# The option defines the amount of entropy the LRNG applies to 256 --# bits of data obtained from the Jitter RNG entropy source. The --# LRNG enforces the limit that this value must be in the range --# between 0 and 256. --# --# When configuring this value to 0, the Jitter RNG entropy source --# will provide 256 bits of data without being credited to contain --# entropy. --# -+comment "Jitter RNG Entropy Source" -+ -+config LRNG_JENT -+ bool "Enable Jitter RNG as LRNG Seed Source" -+ depends on CRYPTO -+ select CRYPTO_JITTERENTROPY -+ help -+ The LRNG may use the Jitter RNG as entropy source. Enabling -+ this option enables the use of the Jitter RNG. Its default -+ entropy level is 16 bits of entropy per 256 data bits delivered -+ by the Jitter RNG. This entropy level can be changed at boot -+ time or at runtime with the lrng_base.jitterrng configuration -+ variable. -+ -+choice -+ prompt "Jitter RNG Async Block Number" -+ default LRNG_JENT_ENTROPY_BLOCKS_NO_128 -+ depends on LRNG_JENT -+ help -+ Select the number of Jitter RNG entropy blocks the asynchronous -+ collection operation will fill. A caller for Jitter RNG entropy -+ will be given data from the pre-filled blocks if available to -+ prevent the Jitter RNG from utilizing the CPU too much in a -+ possible hot code path. -+ -+ The number specifies the number of 256/384 bit blocks that will -+ be held in memory and asynchronously filled with Jitter RNG data. -+ -+ The asynchronous entropy collection can also be disabled at -+ kernel startup time when setting the command line option of -+ lrng_es_jent.jent_async_enabled=0. Also, setting this option at -+ runtime is allowed via the corresponding SysFS interface. This -+ option is only available with the options SysFS and -+ CONFIG_LRNG_RUNTIME_ES_CONFIG enabled. -+ -+ config LRNG_JENT_ENTROPY_BLOCKS_DISABLED -+ bool "Async collection disabled" -+ -+ # Any block number is allowed, provided it is a power of 2 and -+ # equal or larger than 4 (4 is due to the division in -+ # lrng_jent_async_get when deciding to wake up the monitor). -+ config LRNG_JENT_ENTROPY_BLOCKS_NO_32 -+ bool "32 blocks" -+ -+ config LRNG_JENT_ENTROPY_BLOCKS_NO_64 -+ bool "64 blocks" -+ -+ config LRNG_JENT_ENTROPY_BLOCKS_NO_128 -+ bool "128 blocks (default)" -+ -+ config LRNG_JENT_ENTROPY_BLOCKS_NO_256 -+ bool "256 blocks" -+ -+ config LRNG_JENT_ENTROPY_BLOCKS_NO_512 -+ bool "512 blocks" -+ -+ config LRNG_JENT_ENTROPY_BLOCKS_NO_1024 -+ bool "1024 blocks" -+ -+endchoice -+ -+config LRNG_JENT_ENTROPY_BLOCKS -+ int -+ default 0 if LRNG_JENT_ENTROPY_BLOCKS_DISABLED -+ default 32 if LRNG_JENT_ENTROPY_BLOCKS_NO_32 -+ default 64 if LRNG_JENT_ENTROPY_BLOCKS_NO_64 -+ default 128 if LRNG_JENT_ENTROPY_BLOCKS_NO_128 -+ default 256 if LRNG_JENT_ENTROPY_BLOCKS_NO_256 -+ default 512 if LRNG_JENT_ENTROPY_BLOCKS_NO_512 -+ default 1024 if LRNG_JENT_ENTROPY_BLOCKS_NO_1024 -+ -+config LRNG_JENT_ENTROPY_RATE -+ int "Jitter RNG Entropy Source Entropy Rate" -+ depends on LRNG_JENT -+ range 0 256 -+ default 16 -+ help -+ The option defines the amount of entropy the LRNG applies to 256 -+ bits of data obtained from the Jitter RNG entropy source. The -+ LRNG enforces the limit that this value must be in the range -+ between 0 and 256. -+ -+ When configuring this value to 0, the Jitter RNG entropy source -+ will provide 256 bits of data without being credited to contain -+ entropy. -+ - comment "CPU Entropy Source" - - config LRNG_CPU ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -23,5 +23,6 @@ obj-$(CONFIG_LRNG_IRQ) += lrng_es_irq. - obj-$(CONFIG_LRNG_KERNEL_RNG) += lrng_es_krng.o - obj-$(CONFIG_LRNG_SCHED) += lrng_es_sched.o - obj-$(CONFIG_LRNG_CPU) += lrng_es_cpu.o -+obj-$(CONFIG_LRNG_JENT) += lrng_es_jent.o - - obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_es_jent.c -@@ -0,0 +1,356 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Fast Entropy Source: Jitter RNG -+ * -+ * Copyright (C) 2022 - 2023, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_definitions.h" -+#include "lrng_es_aux.h" -+#include "lrng_es_jent.h" -+#include "lrng_es_mgr.h" -+ -+/* -+ * Estimated entropy of data is a 16th of LRNG_DRNG_SECURITY_STRENGTH_BITS. -+ * Albeit a full entropy assessment is provided for the noise source indicating -+ * that it provides high entropy rates and considering that it deactivates -+ * when it detects insufficient hardware, the chosen under estimation of -+ * entropy is considered to be acceptable to all reviewers. -+ */ -+static u32 jent_entropy = CONFIG_LRNG_JENT_ENTROPY_RATE; -+#ifdef CONFIG_LRNG_RUNTIME_ES_CONFIG -+module_param(jent_entropy, uint, 0644); -+MODULE_PARM_DESC(jent_entropy, -+ "Entropy in bits of 256 data bits from Jitter RNG noise source"); -+#endif -+ -+static bool lrng_jent_initialized = false; -+static struct crypto_rng *jent; -+ -+#if (CONFIG_LRNG_JENT_ENTROPY_BLOCKS != 0) -+ -+/* Entropy buffer filled by Jitter RNG thread - must be power of 2 */ -+#define LRNG_JENT_ENTROPY_BLOCKS_MASK (CONFIG_LRNG_JENT_ENTROPY_BLOCKS - 1) -+ -+struct jent_entropy_es { -+ uint8_t e[LRNG_DRNG_INIT_SEED_SIZE_BYTES]; -+ uint32_t e_bits; -+}; -+ -+/* Buffer that is filled with Jitter RNG data by a thread. */ -+static struct jent_entropy_es -+ lrng_jent_async[CONFIG_LRNG_JENT_ENTROPY_BLOCKS] __aligned(sizeof(u64)); -+ -+/* State of each Jitter RNG buffer entry to ensure atomic access. */ -+enum lrng_jent_async_state { -+ buffer_empty, -+ buffer_filling, -+ buffer_filled, -+ buffer_reading, -+}; -+static atomic_t lrng_jent_async_set[CONFIG_LRNG_JENT_ENTROPY_BLOCKS]; -+ -+/* Jitter RNG buffer work handler. */ -+static struct work_struct lrng_jent_async_work; -+ -+/* Is the asynchronous operation enabled? */ -+static bool lrng_es_jent_async_enabled = true; -+ -+#else /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ -+ -+/* The asynchronous operation is disabled by compile time option. */ -+static bool lrng_es_jent_async_enabled = false; -+ -+#endif /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ -+ -+static u32 lrng_jent_entropylevel(u32 requested_bits) -+{ -+ return lrng_fast_noise_entropylevel(lrng_jent_initialized ? -+ jent_entropy : 0, requested_bits); -+} -+ -+static u32 lrng_jent_poolsize(void) -+{ -+ return lrng_jent_entropylevel(lrng_security_strength()); -+} -+ -+static void __lrng_jent_get(u8 *e, u32 *e_bits, u32 requested_bits) -+{ -+ int ret; -+ u32 ent_bits = lrng_jent_entropylevel(requested_bits); -+ unsigned long flags; -+ static DEFINE_SPINLOCK(lrng_jent_lock); -+ -+ if (!lrng_jent_initialized) -+ goto err; -+ -+ spin_lock_irqsave(&lrng_jent_lock, flags); -+ ret = crypto_rng_get_bytes(jent, e, requested_bits >> 3); -+ spin_unlock_irqrestore(&lrng_jent_lock, flags); -+ -+ if (ret) { -+ pr_debug("Jitter RNG failed with %d\n", ret); -+ goto err; -+ } -+ -+ pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n", -+ ent_bits); -+ -+ *e_bits = ent_bits; -+ return; -+ -+err: -+ *e_bits = 0; -+} -+ -+/* -+ * lrng_get_jent() - Get Jitter RNG entropy -+ * -+ * @eb: entropy buffer to store entropy -+ * @requested_bits: requested entropy in bits -+ */ -+static void lrng_jent_get(struct entropy_buf *eb, u32 requested_bits, -+ bool __unused) -+{ -+ __lrng_jent_get(eb->e[lrng_ext_es_jitter], -+ &eb->e_bits[lrng_ext_es_jitter], requested_bits); -+} -+ -+#if (CONFIG_LRNG_JENT_ENTROPY_BLOCKS != 0) -+ -+/* Fill the Jitter RNG buffer with random data. */ -+static void lrng_jent_async_monitor(struct work_struct *__unused) -+{ -+ unsigned int i, requested_bits = lrng_get_seed_entropy_osr(true); -+ -+ pr_debug("Jitter RNG block filling started\n"); -+ -+ for (i = 0; i < CONFIG_LRNG_JENT_ENTROPY_BLOCKS; i++) { -+ /* Ensure atomic access to the Jitter RNG buffer slot. */ -+ if (atomic_cmpxchg(&lrng_jent_async_set[i], -+ buffer_empty, buffer_filling) != -+ buffer_empty) -+ continue; -+ -+ /* -+ * Always gather entropy data including -+ * potential oversampling factor. -+ */ -+ __lrng_jent_get(lrng_jent_async[i].e, -+ &lrng_jent_async[i].e_bits, requested_bits); -+ -+ atomic_set(&lrng_jent_async_set[i], buffer_filled); -+ -+ pr_debug("Jitter RNG ES monitor: filled slot %u with %u bits of entropy\n", -+ i, requested_bits); -+ } -+ -+ pr_debug("Jitter RNG block filling completed\n"); -+} -+ -+static void lrng_jent_async_monitor_schedule(void) -+{ -+ if (lrng_es_jent_async_enabled) -+ schedule_work(&lrng_jent_async_work); -+} -+ -+static void lrng_jent_async_fini(void) -+{ -+ /* Reset state */ -+ memzero_explicit(lrng_jent_async, sizeof(lrng_jent_async)); -+} -+ -+/* Get Jitter RNG data from the buffer */ -+static void lrng_jent_async_get(struct entropy_buf *eb, uint32_t requested_bits, -+ bool __unused) -+{ -+ static atomic_t idx = ATOMIC_INIT(-1); -+ unsigned int slot; -+ -+ (void)requested_bits; -+ -+ if (!lrng_jent_initialized) { -+ eb->e_bits[lrng_ext_es_jitter] = 0; -+ return; -+ } -+ -+ /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS must be a power of 2 */ -+ BUILD_BUG_ON((CONFIG_LRNG_JENT_ENTROPY_BLOCKS & -+ LRNG_JENT_ENTROPY_BLOCKS_MASK) != 0); -+ -+ slot = ((unsigned int)atomic_inc_return(&idx)) & -+ LRNG_JENT_ENTROPY_BLOCKS_MASK; -+ -+ /* Ensure atomic access to the Jitter RNG buffer slot. */ -+ if (atomic_cmpxchg(&lrng_jent_async_set[slot], -+ buffer_filled, buffer_reading) != buffer_filled) { -+ pr_debug("Jitter RNG ES monitor: buffer slot %u exhausted\n", -+ slot); -+ lrng_jent_get(eb, requested_bits, __unused); -+ lrng_jent_async_monitor_schedule(); -+ return; -+ } -+ -+ pr_debug("Jitter RNG ES monitor: used slot %u\n", slot); -+ memcpy(eb->e[lrng_ext_es_jitter], lrng_jent_async[slot].e, -+ LRNG_DRNG_INIT_SEED_SIZE_BYTES); -+ eb->e_bits[lrng_ext_es_jitter] = lrng_jent_async[slot].e_bits; -+ -+ pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n", -+ eb->e_bits[lrng_ext_es_jitter]); -+ -+ memzero_explicit(&lrng_jent_async[slot], -+ sizeof(struct jent_entropy_es)); -+ -+ atomic_set(&lrng_jent_async_set[slot], buffer_empty); -+ -+ /* Ensure division in the following check works */ -+ BUILD_BUG_ON(CONFIG_LRNG_JENT_ENTROPY_BLOCKS < 4); -+ if (!(slot % (CONFIG_LRNG_JENT_ENTROPY_BLOCKS / 4)) && slot) -+ lrng_jent_async_monitor_schedule(); -+} -+ -+static void lrng_jent_get_check(struct entropy_buf *eb, -+ uint32_t requested_bits, bool __unused) -+{ -+ if (lrng_es_jent_async_enabled && -+ (requested_bits == lrng_get_seed_entropy_osr(true))) { -+ lrng_jent_async_get(eb, requested_bits, __unused); -+ } else { -+ lrng_jent_get(eb, requested_bits, __unused); -+ } -+} -+ -+static void lrng_jent_async_init(void) -+{ -+ unsigned int i; -+ -+ if (!lrng_es_jent_async_enabled) -+ return; -+ -+ for (i = 0; i < CONFIG_LRNG_JENT_ENTROPY_BLOCKS; i++) -+ atomic_set(&lrng_jent_async_set[i], buffer_empty); -+} -+ -+static void lrng_jent_async_init_complete(void) -+{ -+ lrng_jent_async_init(); -+ INIT_WORK(&lrng_jent_async_work, lrng_jent_async_monitor); -+} -+ -+#if (defined(CONFIG_SYSFS) && defined(CONFIG_LRNG_RUNTIME_ES_CONFIG)) -+/* Initialize or deinitialize the Jitter RNG async collection */ -+static int lrng_jent_async_sysfs_set(const char *val, -+ const struct kernel_param *kp) -+{ -+ static const char val_dflt[] = "1"; -+ int ret; -+ bool setting; -+ -+ if (!val) -+ val = val_dflt; -+ -+ ret = kstrtobool(val, &setting); -+ if (ret) -+ return ret; -+ -+ if (setting) { -+ if (!lrng_es_jent_async_enabled) { -+ lrng_es_jent_async_enabled = 1; -+ lrng_jent_async_init(); -+ pr_devel("Jitter RNG async data collection enabled\n"); -+ lrng_jent_async_monitor_schedule(); -+ } -+ } else { -+ if (lrng_es_jent_async_enabled) { -+ lrng_es_jent_async_enabled = 0; -+ lrng_jent_async_fini(); -+ pr_devel("Jitter RNG async data collection disabled\n"); -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct kernel_param_ops lrng_jent_async_sysfs = { -+ .set = lrng_jent_async_sysfs_set, -+ .get = param_get_bool, -+}; -+module_param_cb(jent_async_enabled, &lrng_jent_async_sysfs, -+ &lrng_es_jent_async_enabled, 0644); -+MODULE_PARM_DESC(lrng_es_jent_async_enabled, -+ "Enable Jitter RNG entropy buffer asynchronous collection"); -+#endif /* CONFIG_SYSFS && CONFIG_LRNG_RUNTIME_ES_CONFIG */ -+ -+#else /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ -+ -+static void lrng_jent_get_check(struct entropy_buf *eb, -+ uint32_t requested_bits, bool __unused) -+{ -+ lrng_jent_get(eb, requested_bits, __unused); -+} -+ -+static inline void __init lrng_jent_async_init_complete(void) { } -+ -+#endif /* CONFIG_LRNG_JENT_ENTROPY_BLOCKS */ -+ -+static void lrng_jent_es_state(unsigned char *buf, size_t buflen) -+{ -+ snprintf(buf, buflen, -+ " Available entropy: %u\n" -+ " Enabled: %s\n" -+ " Jitter RNG async collection %s\n", -+ lrng_jent_poolsize(), -+ lrng_jent_initialized ? "true" : "false", -+ lrng_es_jent_async_enabled ? "true" : "false"); -+} -+ -+static int __init lrng_jent_initialize(void) -+{ -+ jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); -+ if (IS_ERR(jent)) { -+ pr_err("Cannot allocate Jitter RNG\n"); -+ return PTR_ERR(jent); -+ } -+ -+ lrng_jent_async_init_complete(); -+ -+ lrng_jent_initialized = true; -+ pr_debug("Jitter RNG working on current system\n"); -+ -+ /* -+ * In FIPS mode, the Jitter RNG is defined to have full of entropy -+ * unless a different value has been specified at the command line -+ * (i.e. the user overrides the default), and the default value is -+ * larger than zero (if it is zero, it is assumed that an RBG2(P) or -+ * RBG2(NP) construction is attempted that intends to exclude the -+ * Jitter RNG). -+ */ -+ if (fips_enabled && CONFIG_LRNG_JENT_ENTROPY_RATE > 0 && -+ jent_entropy == CONFIG_LRNG_JENT_ENTROPY_RATE) -+ jent_entropy = LRNG_DRNG_SECURITY_STRENGTH_BITS; -+ -+ if (jent_entropy) -+ lrng_force_fully_seeded(); -+ -+ return 0; -+} -+device_initcall(lrng_jent_initialize); -+ -+struct lrng_es_cb lrng_es_jent = { -+ .name = "JitterRNG", -+ .get_ent = lrng_jent_get_check, -+ .curr_entropy = lrng_jent_entropylevel, -+ .max_entropy = lrng_jent_poolsize, -+ .state = lrng_jent_es_state, -+ .reset = NULL, -+ .switch_hash = NULL, -+}; diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch deleted file mode 100644 index 21c37ef93..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch +++ /dev/null @@ -1,60 +0,0 @@ -From f9f338bb3283bc54cd9084ccdabb7ad3f50a0eb8 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 17:56:56 +0200 -Subject: [PATCH 18/25] LRNG - add option to enable runtime entropy rate - configuration - -The entropy rate for the different entropy sources is configured at -compile time. Enabling the option CONFIG_LRNG_RUNTIME_ES_CONFIG allows -the entropy sources' entropy rate to be adjusted at runtime or boot -time. The different options are: - -- IRQ ES: lrng_es_irq.irq_entropy - -- Scheduler ES: lrng_es_sched.sched_entropy - -- CPU ES: lrng_es_cpu.cpu_entropy - -- Kernel ES: lrng_es_krng.krng_entropy - -- Jitter RNG ES: lrng_es_jent.jent_entropy - -The values to be specified there must apply the rationale given for the -different CONFIG_LRNG_*_ENTROPY_RATE kernel configuration options. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 22 +++++++++++----------- - 1 file changed, 11 insertions(+), 11 deletions(-) - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -124,17 +124,17 @@ endmenu # "Specific DRNG seeding strateg - - menu "Entropy Source Configuration" - --# config LRNG_RUNTIME_ES_CONFIG --# bool "Enable runtime configuration of entropy sources" --# help --# When enabling this option, the LRNG provides the mechanism --# allowing to alter the entropy rate of each entropy source --# during boot time and runtime. --# --# Each entropy source allows its entropy rate changed with --# a kernel command line option. When not providing any --# option, the default specified during kernel compilation --# is applied. -+config LRNG_RUNTIME_ES_CONFIG -+ bool "Enable runtime configuration of entropy sources" -+ help -+ When enabling this option, the LRNG provides the mechanism -+ allowing to alter the entropy rate of each entropy source -+ during boot time and runtime. -+ -+ Each entropy source allows its entropy rate changed with -+ a kernel command line option. When not providing any -+ option, the default specified during kernel compilation -+ is applied. - - comment "Common Timer-based Entropy Source Configuration" - diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch deleted file mode 100644 index d7c2fad08..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch +++ /dev/null @@ -1,1533 +0,0 @@ -From 787d2d2ebdc98784ac7b63192d0e2508d28a1023 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 18 Dec 2022 21:22:36 +0100 -Subject: [PATCH 19/25] LRNG - add interface for gathering of raw entropy - -The test interface allows a privileged process to capture the raw -unconditioned noise that is collected by the LRNG for statistical -analysis. Such testing allows the analysis how much entropy -the interrupt noise source provides on a given platform. -Extracted noise data is not used to seed the LRNG. This -is a test interface and not appropriate for production systems. -Yet, the interface is considered to be sufficiently secured for -production systems. - -The raw entropy collection is provided for the internal entropy sources -under full control of the LRNG: the IRQ ES and the scheduler-based ES. -The test interfaces are only enabled for the given ES if the ES is -enabled itself. - -Access to the data is given through the lrng_raw debugfs file. The -data buffer should be multiples of sizeof(u32) to fill the entire -buffer. Using the option lrng_testing.boot_test=1 the raw noise of -the first 1000 entropy events since boot can be sampled. - -This test interface allows generating the data required for -analysis whether the LRNG is in compliance with SP800-90B -sections 3.1.3 and 3.1.4. - -In addition, the test interface allows gathering of the concatenated raw -entropy data to verify that the concatenation works appropriately. -This includes sampling of the following raw IRQ data: - -* high-resolution time stamp obtained for an IRQ event - -* Jiffies - -* IRQ number - -* return instruction pointer - -* interrupt register state - -* array logic batching the high-resolution time stamp - -* a performance monitor of the IRQ ES - -The sampling of the following scheduler-based ES data is possible: - -* high-resolution time stamp obtained for a context switch event - -* the PID of the process scheduled to - -* the process' start time value - -* the process' context switch numbers value - -* a performance monitor of the scheduler-based ES - -Also, a testing interface to support ACVT of the hash implementation -is provided. The reason why only hash testing is supported (as -opposed to also provide testing for the DRNG) is the fact that the -LRNG software hash implementation contains glue code that may -warrant testing in addition to the testing of the software ciphers -via the kernel crypto API. Also, for testing the CTR-DRBG, the -underlying AES implementation would need to be tested. However, -such AES test interface cannot be provided by the LRNG as it has no -means to access the AES operation. - -If a test interface is not compiled, its code is a noop which has no -impact on the performance. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 534 +++++++++--------- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_testing.c | 901 +++++++++++++++++++++++++++++++ - 3 files changed, 1169 insertions(+), 267 deletions(-) - create mode 100644 drivers/char/lrng/lrng_testing.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -718,273 +718,273 @@ choice - select LRNG_DRNG_KCAPI - endchoice - --# menuconfig LRNG_TESTING_MENU --# bool "LRNG testing interfaces" --# depends on DEBUG_FS --# help --# Enable one or more of the following test interfaces. --# --# If unsure, say N. --# --# if LRNG_TESTING_MENU --# --# config LRNG_TESTING --# bool --# --# config LRNG_TESTING_RECORDING --# bool --# --# comment "Interrupt Entropy Source Test Interfaces" --# --# config LRNG_RAW_HIRES_ENTROPY --# bool "Interface to obtain raw unprocessed IRQ noise source data" --# default y --# depends on LRNG_IRQ --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned high resolution time stamp noise that --# is collected by the LRNG for statistical analysis. Extracted --# noise data is not used to seed the LRNG. --# --# The raw noise data can be obtained using the lrng_raw_hires --# debugfs file. Using the option lrng_testing.boot_raw_hires_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_RAW_JIFFIES_ENTROPY --# bool "Entropy test interface to Jiffies of IRQ noise source" --# depends on LRNG_IRQ --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned Jiffies that is collected by --# the LRNG for statistical analysis. This data is used for --# seeding the LRNG if a high-resolution time stamp is not --# available. If a high-resolution time stamp is detected, --# the Jiffies value is not collected by the LRNG and no --# data is provided via the test interface. Extracted noise --# data is not used to seed the random number generator. --# --# The raw noise data can be obtained using the lrng_raw_jiffies --# debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_RAW_IRQ_ENTROPY --# bool "Entropy test interface to IRQ number noise source" --# depends on LRNG_IRQ --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned interrupt number that is collected by --# the LRNG for statistical analysis. Extracted noise data is --# not used to seed the random number generator. --# --# The raw noise data can be obtained using the lrng_raw_irq --# debugfs file. Using the option lrng_testing.boot_raw_irq_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_RAW_RETIP_ENTROPY --# bool "Entropy test interface to RETIP value of IRQ noise source" --# depends on LRNG_IRQ --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned return instruction pointer value --# that is collected by the LRNG for statistical analysis. --# Extracted noise data is not used to seed the random number --# generator. --# --# The raw noise data can be obtained using the lrng_raw_retip --# debugfs file. Using the option lrng_testing.boot_raw_retip_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_RAW_REGS_ENTROPY --# bool "Entropy test interface to IRQ register value noise source" --# depends on LRNG_IRQ --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned interrupt register value that is --# collected by the LRNG for statistical analysis. Extracted noise --# data is not used to seed the random number generator. --# --# The raw noise data can be obtained using the lrng_raw_regs --# debugfs file. Using the option lrng_testing.boot_raw_regs_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_RAW_ARRAY --# bool "Test interface to LRNG raw entropy IRQ storage array" --# depends on LRNG_IRQ --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw noise data that is collected by the LRNG --# in the per-CPU array for statistical analysis. The purpose --# of this interface is to verify that the array handling code --# truly only concatenates data and provides the same entropy --# rate as the raw unconditioned noise source when assessing --# the collected data byte-wise. --# --# The data can be obtained using the lrng_raw_array debugfs --# file. Using the option lrng_testing.boot_raw_array=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_IRQ_PERF --# bool "LRNG interrupt entropy source performance monitor" --# depends on LRNG_IRQ --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# With this option, the performance monitor of the LRNG --# interrupt handling code is enabled. The file provides --# the execution time of the interrupt handler in --# cycles. --# --# The interrupt performance data can be obtained using --# the lrng_irq_perf debugfs file. Using the option --# lrng_testing.boot_irq_perf=1 the performance data of --# the first 1000 entropy events since boot can be sampled. --# --# comment "Scheduler Entropy Source Test Interfaces" --# --# config LRNG_RAW_SCHED_HIRES_ENTROPY --# bool "Interface to obtain raw unprocessed scheduler noise source data" --# depends on LRNG_SCHED --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned high resolution time stamp noise that --# is collected by the LRNG for the Scheduler-based noise source --# for statistical analysis. Extracted noise data is not used to --# seed the LRNG. --# --# The raw noise data can be obtained using the lrng_raw_sched_hires --# debugfs file. Using the option --# lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the --# first 1000 entropy events since boot can be sampled. --# --# config LRNG_RAW_SCHED_PID_ENTROPY --# bool "Entropy test interface to PID value" --# depends on LRNG_SCHED --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned PID value that is collected by the --# LRNG for statistical analysis. Extracted noise --# data is not used to seed the random number generator. --# --# The raw noise data can be obtained using the --# lrng_raw_sched_pid debugfs file. Using the option --# lrng_testing.boot_raw_sched_pid_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_RAW_SCHED_START_TIME_ENTROPY --# bool "Entropy test interface to task start time value" --# depends on LRNG_SCHED --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned task start time value that is collected --# by the LRNG for statistical analysis. Extracted noise --# data is not used to seed the random number generator. --# --# The raw noise data can be obtained using the --# lrng_raw_sched_starttime debugfs file. Using the option --# lrng_testing.boot_raw_sched_starttime_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# --# config LRNG_RAW_SCHED_NVCSW_ENTROPY --# bool "Entropy test interface to task context switch numbers" --# depends on LRNG_SCHED --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# The test interface allows a privileged process to capture --# the raw unconditioned task numbers of context switches that --# are collected by the LRNG for statistical analysis. Extracted --# noise data is not used to seed the random number generator. --# --# The raw noise data can be obtained using the --# lrng_raw_sched_nvcsw debugfs file. Using the option --# lrng_testing.boot_raw_sched_nvcsw_test=1 --# the raw noise of the first 1000 entropy events since boot --# can be sampled. --# --# config LRNG_SCHED_PERF --# bool "LRNG scheduler entropy source performance monitor" --# depends on LRNG_SCHED --# select LRNG_TESTING --# select LRNG_TESTING_RECORDING --# help --# With this option, the performance monitor of the LRNG --# scheduler event handling code is enabled. The file provides --# the execution time of the interrupt handler in cycles. --# --# The scheduler performance data can be obtained using --# the lrng_sched_perf debugfs file. Using the option --# lrng_testing.boot_sched_perf=1 the performance data of --# the first 1000 entropy events since boot can be sampled. --# --# comment "Auxiliary Test Interfaces" --# --# config LRNG_ACVT_HASH --# bool "Enable LRNG ACVT Hash interface" --# select LRNG_TESTING --# help --# With this option, the LRNG built-in hash function used for --# auxiliary pool management and prior to switching the --# cryptographic backends is made available for ACVT. The --# interface allows writing of the data to be hashed --# into the interface. The read operation triggers the hash --# operation to generate message digest. --# --# The ACVT interface is available with the lrng_acvt_hash --# debugfs file. --# --# config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG --# bool "Enable runtime configuration of max reseed threshold" --# help --# When enabling this option, the LRNG provides an interface --# allowing the setting of the maximum number of DRNG generate --# operations without a reseed that has full entropy. The --# interface is lrng_drng.max_wo_reseed. --# --#config LRNG_RUNTIME_FORCE_SEEDING_DISABLE --# bool "Enable runtime configuration of force seeding" --# help --# When enabling this option, the LRNG provides an interface --# allowing the disabling of the force seeding when the DRNG --# is not fully seeded but entropy is available. --# --# config LRNG_TEST_CPU_ES_COMPRESSION --# bool "Force CPU ES compression operation" --# help --# When enabling this option, the CPU ES compression operation --# is forced by setting an arbitrary value > 1 for the data --# multiplier even when the CPU ES would deliver full entropy. --# This allows testing of the compression operation. It --# therefore forces to pull more data from the CPU ES --# than what may be required. --# --# endif #LRNG_TESTING_MENU -+menuconfig LRNG_TESTING_MENU -+ bool "LRNG testing interfaces" -+ depends on DEBUG_FS -+ help -+ Enable one or more of the following test interfaces. -+ -+ If unsure, say N. -+ -+if LRNG_TESTING_MENU -+ -+config LRNG_TESTING -+ bool -+ -+config LRNG_TESTING_RECORDING -+ bool -+ -+comment "Interrupt Entropy Source Test Interfaces" -+ -+config LRNG_RAW_HIRES_ENTROPY -+ bool "Interface to obtain raw unprocessed IRQ noise source data" -+ default y -+ depends on LRNG_IRQ -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned high resolution time stamp noise that -+ is collected by the LRNG for statistical analysis. Extracted -+ noise data is not used to seed the LRNG. -+ -+ The raw noise data can be obtained using the lrng_raw_hires -+ debugfs file. Using the option lrng_testing.boot_raw_hires_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_RAW_JIFFIES_ENTROPY -+ bool "Entropy test interface to Jiffies of IRQ noise source" -+ depends on LRNG_IRQ -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned Jiffies that is collected by -+ the LRNG for statistical analysis. This data is used for -+ seeding the LRNG if a high-resolution time stamp is not -+ available. If a high-resolution time stamp is detected, -+ the Jiffies value is not collected by the LRNG and no -+ data is provided via the test interface. Extracted noise -+ data is not used to seed the random number generator. -+ -+ The raw noise data can be obtained using the lrng_raw_jiffies -+ debugfs file. Using the option lrng_testing.boot_raw_jiffies_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_RAW_IRQ_ENTROPY -+ bool "Entropy test interface to IRQ number noise source" -+ depends on LRNG_IRQ -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned interrupt number that is collected by -+ the LRNG for statistical analysis. Extracted noise data is -+ not used to seed the random number generator. -+ -+ The raw noise data can be obtained using the lrng_raw_irq -+ debugfs file. Using the option lrng_testing.boot_raw_irq_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_RAW_RETIP_ENTROPY -+ bool "Entropy test interface to RETIP value of IRQ noise source" -+ depends on LRNG_IRQ -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned return instruction pointer value -+ that is collected by the LRNG for statistical analysis. -+ Extracted noise data is not used to seed the random number -+ generator. -+ -+ The raw noise data can be obtained using the lrng_raw_retip -+ debugfs file. Using the option lrng_testing.boot_raw_retip_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_RAW_REGS_ENTROPY -+ bool "Entropy test interface to IRQ register value noise source" -+ depends on LRNG_IRQ -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned interrupt register value that is -+ collected by the LRNG for statistical analysis. Extracted noise -+ data is not used to seed the random number generator. -+ -+ The raw noise data can be obtained using the lrng_raw_regs -+ debugfs file. Using the option lrng_testing.boot_raw_regs_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_RAW_ARRAY -+ bool "Test interface to LRNG raw entropy IRQ storage array" -+ depends on LRNG_IRQ -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw noise data that is collected by the LRNG -+ in the per-CPU array for statistical analysis. The purpose -+ of this interface is to verify that the array handling code -+ truly only concatenates data and provides the same entropy -+ rate as the raw unconditioned noise source when assessing -+ the collected data byte-wise. -+ -+ The data can be obtained using the lrng_raw_array debugfs -+ file. Using the option lrng_testing.boot_raw_array=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_IRQ_PERF -+ bool "LRNG interrupt entropy source performance monitor" -+ depends on LRNG_IRQ -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ With this option, the performance monitor of the LRNG -+ interrupt handling code is enabled. The file provides -+ the execution time of the interrupt handler in -+ cycles. -+ -+ The interrupt performance data can be obtained using -+ the lrng_irq_perf debugfs file. Using the option -+ lrng_testing.boot_irq_perf=1 the performance data of -+ the first 1000 entropy events since boot can be sampled. -+ -+comment "Scheduler Entropy Source Test Interfaces" -+ -+config LRNG_RAW_SCHED_HIRES_ENTROPY -+ bool "Interface to obtain raw unprocessed scheduler noise source data" -+ depends on LRNG_SCHED -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned high resolution time stamp noise that -+ is collected by the LRNG for the Scheduler-based noise source -+ for statistical analysis. Extracted noise data is not used to -+ seed the LRNG. -+ -+ The raw noise data can be obtained using the lrng_raw_sched_hires -+ debugfs file. Using the option -+ lrng_testing.boot_raw_sched_hires_test=1 the raw noise of the -+ first 1000 entropy events since boot can be sampled. -+ -+config LRNG_RAW_SCHED_PID_ENTROPY -+ bool "Entropy test interface to PID value" -+ depends on LRNG_SCHED -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned PID value that is collected by the -+ LRNG for statistical analysis. Extracted noise -+ data is not used to seed the random number generator. -+ -+ The raw noise data can be obtained using the -+ lrng_raw_sched_pid debugfs file. Using the option -+ lrng_testing.boot_raw_sched_pid_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_RAW_SCHED_START_TIME_ENTROPY -+ bool "Entropy test interface to task start time value" -+ depends on LRNG_SCHED -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned task start time value that is collected -+ by the LRNG for statistical analysis. Extracted noise -+ data is not used to seed the random number generator. -+ -+ The raw noise data can be obtained using the -+ lrng_raw_sched_starttime debugfs file. Using the option -+ lrng_testing.boot_raw_sched_starttime_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+ -+config LRNG_RAW_SCHED_NVCSW_ENTROPY -+ bool "Entropy test interface to task context switch numbers" -+ depends on LRNG_SCHED -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ The test interface allows a privileged process to capture -+ the raw unconditioned task numbers of context switches that -+ are collected by the LRNG for statistical analysis. Extracted -+ noise data is not used to seed the random number generator. -+ -+ The raw noise data can be obtained using the -+ lrng_raw_sched_nvcsw debugfs file. Using the option -+ lrng_testing.boot_raw_sched_nvcsw_test=1 -+ the raw noise of the first 1000 entropy events since boot -+ can be sampled. -+ -+config LRNG_SCHED_PERF -+ bool "LRNG scheduler entropy source performance monitor" -+ depends on LRNG_SCHED -+ select LRNG_TESTING -+ select LRNG_TESTING_RECORDING -+ help -+ With this option, the performance monitor of the LRNG -+ scheduler event handling code is enabled. The file provides -+ the execution time of the interrupt handler in cycles. -+ -+ The scheduler performance data can be obtained using -+ the lrng_sched_perf debugfs file. Using the option -+ lrng_testing.boot_sched_perf=1 the performance data of -+ the first 1000 entropy events since boot can be sampled. -+ -+comment "Auxiliary Test Interfaces" -+ -+config LRNG_ACVT_HASH -+ bool "Enable LRNG ACVT Hash interface" -+ select LRNG_TESTING -+ help -+ With this option, the LRNG built-in hash function used for -+ auxiliary pool management and prior to switching the -+ cryptographic backends is made available for ACVT. The -+ interface allows writing of the data to be hashed -+ into the interface. The read operation triggers the hash -+ operation to generate message digest. -+ -+ The ACVT interface is available with the lrng_acvt_hash -+ debugfs file. -+ -+config LRNG_RUNTIME_MAX_WO_RESEED_CONFIG -+ bool "Enable runtime configuration of max reseed threshold" -+ help -+ When enabling this option, the LRNG provides an interface -+ allowing the setting of the maximum number of DRNG generate -+ operations without a reseed that has full entropy. The -+ interface is lrng_drng.max_wo_reseed. -+ -+config LRNG_RUNTIME_FORCE_SEEDING_DISABLE -+ bool "Enable runtime configuration of force seeding" -+ help -+ When enabling this option, the LRNG provides an interface -+ allowing the disabling of the force seeding when the DRNG -+ is not fully seeded but entropy is available. -+ -+config LRNG_TEST_CPU_ES_COMPRESSION -+ bool "Force CPU ES compression operation" -+ help -+ When enabling this option, the CPU ES compression operation -+ is forced by setting an arbitrary value > 1 for the data -+ multiplier even when the CPU ES would deliver full entropy. -+ This allows testing of the compression operation. It -+ therefore forces to pull more data from the CPU ES -+ than what may be required. -+ -+endif #LRNG_TESTING_MENU - # - # config LRNG_SELFTEST - # bool "Enable power-on and on-demand self-tests" ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -26,3 +26,4 @@ obj-$(CONFIG_LRNG_CPU) += lrng_es_cpu. - obj-$(CONFIG_LRNG_JENT) += lrng_es_jent.o - - obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o -+obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_testing.c -@@ -0,0 +1,901 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG testing interfaces to obtain raw entropy -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_definitions.h" -+#include "lrng_drng_chacha20.h" -+#include "lrng_sha.h" -+#include "lrng_testing.h" -+ -+#if defined(CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY) || \ -+ defined(CONFIG_LRNG_RAW_SCHED_PID_ENTROPY) || \ -+ defined(CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY) || \ -+ defined(CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY) || \ -+ defined(CONFIG_LRNG_SCHED_PERF) -+#define LRNG_TESTING_USE_BUSYLOOP -+#endif -+ -+#ifdef CONFIG_LRNG_TESTING_RECORDING -+ -+#define LRNG_TESTING_RINGBUFFER_SIZE 1024 -+#define LRNG_TESTING_RINGBUFFER_MASK (LRNG_TESTING_RINGBUFFER_SIZE - 1) -+ -+struct lrng_testing { -+ u32 lrng_testing_rb[LRNG_TESTING_RINGBUFFER_SIZE]; -+ u32 rb_reader; -+ atomic_t rb_writer; -+ atomic_t lrng_testing_enabled; -+ spinlock_t lock; -+ wait_queue_head_t read_wait; -+}; -+ -+/*************************** Generic Data Handling ****************************/ -+ -+/* -+ * boot variable: -+ * 0 ==> No boot test, gathering of runtime data allowed -+ * 1 ==> Boot test enabled and ready for collecting data, gathering runtime -+ * data is disabled -+ * 2 ==> Boot test completed and disabled, gathering of runtime data is -+ * disabled -+ */ -+ -+static void lrng_testing_reset(struct lrng_testing *data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&data->lock, flags); -+ data->rb_reader = 0; -+ atomic_set(&data->rb_writer, 0); -+ spin_unlock_irqrestore(&data->lock, flags); -+} -+ -+static void lrng_testing_init(struct lrng_testing *data, u32 boot) -+{ -+ /* -+ * The boot time testing implies we have a running test. If the -+ * caller wants to clear it, he has to unset the boot_test flag -+ * at runtime via sysfs to enable regular runtime testing -+ */ -+ if (boot) -+ return; -+ -+ lrng_testing_reset(data); -+ atomic_set(&data->lrng_testing_enabled, 1); -+ pr_warn("Enabling data collection\n"); -+} -+ -+static void lrng_testing_fini(struct lrng_testing *data, u32 boot) -+{ -+ /* If we have boot data, we do not reset yet to allow data to be read */ -+ if (boot) -+ return; -+ -+ atomic_set(&data->lrng_testing_enabled, 0); -+ lrng_testing_reset(data); -+ pr_warn("Disabling data collection\n"); -+} -+ -+static bool lrng_testing_store(struct lrng_testing *data, u32 value, -+ u32 *boot) -+{ -+ unsigned long flags; -+ -+ if (!atomic_read(&data->lrng_testing_enabled) && (*boot != 1)) -+ return false; -+ -+ spin_lock_irqsave(&data->lock, flags); -+ -+ /* -+ * Disable entropy testing for boot time testing after ring buffer -+ * is filled. -+ */ -+ if (*boot) { -+ if (((u32)atomic_read(&data->rb_writer)) > -+ LRNG_TESTING_RINGBUFFER_SIZE) { -+ *boot = 2; -+ pr_warn_once("One time data collection test disabled\n"); -+ spin_unlock_irqrestore(&data->lock, flags); -+ return false; -+ } -+ -+ if (atomic_read(&data->rb_writer) == 1) -+ pr_warn("One time data collection test enabled\n"); -+ } -+ -+ data->lrng_testing_rb[((u32)atomic_read(&data->rb_writer)) & -+ LRNG_TESTING_RINGBUFFER_MASK] = value; -+ atomic_inc(&data->rb_writer); -+ -+ spin_unlock_irqrestore(&data->lock, flags); -+ -+#ifndef LRNG_TESTING_USE_BUSYLOOP -+ if (wq_has_sleeper(&data->read_wait)) -+ wake_up_interruptible(&data->read_wait); -+#endif -+ -+ return true; -+} -+ -+static bool lrng_testing_have_data(struct lrng_testing *data) -+{ -+ return ((((u32)atomic_read(&data->rb_writer)) & -+ LRNG_TESTING_RINGBUFFER_MASK) != -+ (data->rb_reader & LRNG_TESTING_RINGBUFFER_MASK)); -+} -+ -+static int lrng_testing_reader(struct lrng_testing *data, u32 *boot, -+ u8 *outbuf, u32 outbuflen) -+{ -+ unsigned long flags; -+ int collected_data = 0; -+ -+ lrng_testing_init(data, *boot); -+ -+ while (outbuflen) { -+ u32 writer = (u32)atomic_read(&data->rb_writer); -+ -+ spin_lock_irqsave(&data->lock, flags); -+ -+ /* We have no data or reached the writer. */ -+ if (!writer || (writer == data->rb_reader)) { -+ -+ spin_unlock_irqrestore(&data->lock, flags); -+ -+ /* -+ * Now we gathered all boot data, enable regular data -+ * collection. -+ */ -+ if (*boot) { -+ *boot = 0; -+ goto out; -+ } -+ -+#ifdef LRNG_TESTING_USE_BUSYLOOP -+ while (!lrng_testing_have_data(data)) -+ ; -+#else -+ wait_event_interruptible(data->read_wait, -+ lrng_testing_have_data(data)); -+#endif -+ if (signal_pending(current)) { -+ collected_data = -ERESTARTSYS; -+ goto out; -+ } -+ -+ continue; -+ } -+ -+ /* We copy out word-wise */ -+ if (outbuflen < sizeof(u32)) { -+ spin_unlock_irqrestore(&data->lock, flags); -+ goto out; -+ } -+ -+ memcpy(outbuf, &data->lrng_testing_rb[data->rb_reader], -+ sizeof(u32)); -+ data->rb_reader++; -+ -+ spin_unlock_irqrestore(&data->lock, flags); -+ -+ outbuf += sizeof(u32); -+ outbuflen -= sizeof(u32); -+ collected_data += sizeof(u32); -+ } -+ -+out: -+ lrng_testing_fini(data, *boot); -+ return collected_data; -+} -+ -+static int lrng_testing_extract_user(struct file *file, char __user *buf, -+ size_t nbytes, loff_t *ppos, -+ int (*reader)(u8 *outbuf, u32 outbuflen)) -+{ -+ u8 *tmp, *tmp_aligned; -+ int ret = 0, large_request = (nbytes > 256); -+ -+ if (!nbytes) -+ return 0; -+ -+ /* -+ * The intention of this interface is for collecting at least -+ * 1000 samples due to the SP800-90B requirements. So, we make no -+ * effort in avoiding allocating more memory that actually needed -+ * by the user. Hence, we allocate sufficient memory to always hold -+ * that amount of data. -+ */ -+ tmp = kmalloc(LRNG_TESTING_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL); -+ if (!tmp) -+ return -ENOMEM; -+ -+ tmp_aligned = PTR_ALIGN(tmp, sizeof(u32)); -+ -+ while (nbytes) { -+ int i; -+ -+ if (large_request && need_resched()) { -+ if (signal_pending(current)) { -+ if (ret == 0) -+ ret = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ } -+ -+ i = min_t(int, nbytes, LRNG_TESTING_RINGBUFFER_SIZE); -+ i = reader(tmp_aligned, i); -+ if (i <= 0) { -+ if (i < 0) -+ ret = i; -+ break; -+ } -+ if (copy_to_user(buf, tmp_aligned, i)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ nbytes -= i; -+ buf += i; -+ ret += i; -+ } -+ -+ kfree_sensitive(tmp); -+ -+ if (ret > 0) -+ *ppos += ret; -+ -+ return ret; -+} -+ -+#endif /* CONFIG_LRNG_TESTING_RECORDING */ -+ -+/************* Raw High-Resolution IRQ Timer Entropy Data Handling ************/ -+ -+#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY -+ -+static u32 boot_raw_hires_test = 0; -+module_param(boot_raw_hires_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_hires_test, "Enable gathering boot time high resolution timer entropy of the first IRQ entropy events"); -+ -+static struct lrng_testing lrng_raw_hires = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_hires.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_hires.read_wait) -+}; -+ -+bool lrng_raw_hires_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_hires, value, &boot_raw_hires_test); -+} -+ -+static int lrng_raw_hires_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_hires, &boot_raw_hires_test, -+ outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_hires_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_hires_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_hires_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_hires_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */ -+ -+/********************* Raw Jiffies Entropy Data Handling **********************/ -+ -+#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY -+ -+static u32 boot_raw_jiffies_test = 0; -+module_param(boot_raw_jiffies_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_jiffies_test, "Enable gathering boot time high resolution timer entropy of the first entropy events"); -+ -+static struct lrng_testing lrng_raw_jiffies = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_jiffies.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_jiffies.read_wait) -+}; -+ -+bool lrng_raw_jiffies_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_jiffies, value, -+ &boot_raw_jiffies_test); -+} -+ -+static int lrng_raw_jiffies_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_jiffies, &boot_raw_jiffies_test, -+ outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_jiffies_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_jiffies_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_jiffies_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_jiffies_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */ -+ -+/************************** Raw IRQ Data Handling ****************************/ -+ -+#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY -+ -+static u32 boot_raw_irq_test = 0; -+module_param(boot_raw_irq_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_irq_test, "Enable gathering boot time entropy of the first IRQ entropy events"); -+ -+static struct lrng_testing lrng_raw_irq = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_irq.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_irq.read_wait) -+}; -+ -+bool lrng_raw_irq_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_irq, value, &boot_raw_irq_test); -+} -+ -+static int lrng_raw_irq_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_irq, &boot_raw_irq_test, outbuf, -+ outbuflen); -+} -+ -+static ssize_t lrng_raw_irq_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_irq_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_irq_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_irq_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */ -+ -+/************************ Raw _RET_IP_ Data Handling **************************/ -+ -+#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY -+ -+static u32 boot_raw_retip_test = 0; -+module_param(boot_raw_retip_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_retip_test, "Enable gathering boot time entropy of the first return instruction pointer entropy events"); -+ -+static struct lrng_testing lrng_raw_retip = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_retip.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_retip.read_wait) -+}; -+ -+bool lrng_raw_retip_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_retip, value, &boot_raw_retip_test); -+} -+ -+static int lrng_raw_retip_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_retip, &boot_raw_retip_test, -+ outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_retip_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_retip_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_retip_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_retip_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */ -+ -+/********************** Raw IRQ register Data Handling ************************/ -+ -+#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY -+ -+static u32 boot_raw_regs_test = 0; -+module_param(boot_raw_regs_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_regs_test, "Enable gathering boot time entropy of the first interrupt register entropy events"); -+ -+static struct lrng_testing lrng_raw_regs = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_regs.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_regs.read_wait) -+}; -+ -+bool lrng_raw_regs_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_regs, value, &boot_raw_regs_test); -+} -+ -+static int lrng_raw_regs_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_regs, &boot_raw_regs_test, -+ outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_regs_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_regs_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_regs_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_regs_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */ -+ -+/********************** Raw Entropy Array Data Handling ***********************/ -+ -+#ifdef CONFIG_LRNG_RAW_ARRAY -+ -+static u32 boot_raw_array = 0; -+module_param(boot_raw_array, uint, 0644); -+MODULE_PARM_DESC(boot_raw_array, "Enable gathering boot time raw noise array data of the first entropy events"); -+ -+static struct lrng_testing lrng_raw_array = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_array.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_array.read_wait) -+}; -+ -+bool lrng_raw_array_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_array, value, &boot_raw_array); -+} -+ -+static int lrng_raw_array_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_array, &boot_raw_array, outbuf, -+ outbuflen); -+} -+ -+static ssize_t lrng_raw_array_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_array_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_array_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_array_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_ARRAY */ -+ -+/******************** Interrupt Performance Data Handling *********************/ -+ -+#ifdef CONFIG_LRNG_IRQ_PERF -+ -+static u32 boot_irq_perf = 0; -+module_param(boot_irq_perf, uint, 0644); -+MODULE_PARM_DESC(boot_irq_perf, "Enable gathering interrupt entropy source performance data"); -+ -+static struct lrng_testing lrng_irq_perf = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_irq_perf.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_irq_perf.read_wait) -+}; -+ -+bool lrng_perf_time(u32 start) -+{ -+ return lrng_testing_store(&lrng_irq_perf, random_get_entropy() - start, -+ &boot_irq_perf); -+} -+ -+static int lrng_irq_perf_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_irq_perf, &boot_irq_perf, outbuf, -+ outbuflen); -+} -+ -+static ssize_t lrng_irq_perf_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_irq_perf_reader); -+} -+ -+static const struct file_operations lrng_irq_perf_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_irq_perf_read, -+}; -+ -+#endif /* CONFIG_LRNG_IRQ_PERF */ -+ -+/****** Raw High-Resolution Scheduler-based Timer Entropy Data Handling *******/ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY -+ -+static u32 boot_raw_sched_hires_test = 0; -+module_param(boot_raw_sched_hires_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_sched_hires_test, "Enable gathering boot time high resolution timer entropy of the first Scheduler-based entropy events"); -+ -+static struct lrng_testing lrng_raw_sched_hires = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_hires.lock), -+ .read_wait = -+ __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_hires.read_wait) -+}; -+ -+bool lrng_raw_sched_hires_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_sched_hires, value, -+ &boot_raw_sched_hires_test); -+} -+ -+static int lrng_raw_sched_hires_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_sched_hires, -+ &boot_raw_sched_hires_test, -+ outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_sched_hires_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_sched_hires_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_sched_hires_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_sched_hires_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY */ -+ -+/******************** Interrupt Performance Data Handling *********************/ -+ -+#ifdef CONFIG_LRNG_SCHED_PERF -+ -+static u32 boot_sched_perf = 0; -+module_param(boot_sched_perf, uint, 0644); -+MODULE_PARM_DESC(boot_sched_perf, "Enable gathering scheduler-based entropy source performance data"); -+ -+static struct lrng_testing lrng_sched_perf = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_sched_perf.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_sched_perf.read_wait) -+}; -+ -+bool lrng_sched_perf_time(u32 start) -+{ -+ return lrng_testing_store(&lrng_sched_perf, random_get_entropy() - start, -+ &boot_sched_perf); -+} -+ -+static int lrng_sched_perf_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_sched_perf, &boot_sched_perf, outbuf, -+ outbuflen); -+} -+ -+static ssize_t lrng_sched_perf_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_sched_perf_reader); -+} -+ -+static const struct file_operations lrng_sched_perf_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_sched_perf_read, -+}; -+ -+#endif /* CONFIG_LRNG_SCHED_PERF */ -+ -+/*************** Raw Scheduler task_struct->pid Data Handling *****************/ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY -+ -+static u32 boot_raw_sched_pid_test = 0; -+module_param(boot_raw_sched_pid_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_sched_pid_test, "Enable gathering boot time entropy of the first PIDs collected by the scheduler entropy source"); -+ -+static struct lrng_testing lrng_raw_sched_pid = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_pid.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_pid.read_wait) -+}; -+ -+bool lrng_raw_sched_pid_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_sched_pid, value, -+ &boot_raw_sched_pid_test); -+} -+ -+static int lrng_raw_sched_pid_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_sched_pid, -+ &boot_raw_sched_pid_test, outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_sched_pid_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_sched_pid_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_sched_pid_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_sched_pid_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_SCHED_PID_ENTROPY */ -+ -+ -+/*********** Raw Scheduler task_struct->start_time Data Handling **************/ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY -+ -+static u32 boot_raw_sched_starttime_test = 0; -+module_param(boot_raw_sched_starttime_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_sched_starttime_test, "Enable gathering boot time entropy of the first task start times collected by the scheduler entropy source"); -+ -+static struct lrng_testing lrng_raw_sched_starttime = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_starttime.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_starttime.read_wait) -+}; -+ -+bool lrng_raw_sched_starttime_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_sched_starttime, value, -+ &boot_raw_sched_starttime_test); -+} -+ -+static int lrng_raw_sched_starttime_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_sched_starttime, -+ &boot_raw_sched_starttime_test, outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_sched_starttime_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_sched_starttime_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_sched_starttime_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_sched_starttime_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY */ -+ -+/************** Raw Scheduler task_struct->nvcsw Data Handling ****************/ -+ -+#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY -+ -+static u32 boot_raw_sched_nvcsw_test = 0; -+module_param(boot_raw_sched_nvcsw_test, uint, 0644); -+MODULE_PARM_DESC(boot_raw_sched_nvcsw_test, "Enable gathering boot time entropy of the first task context switch numbers collected by the scheduler entropy source"); -+ -+static struct lrng_testing lrng_raw_sched_nvcsw = { -+ .rb_reader = 0, -+ .rb_writer = ATOMIC_INIT(0), -+ .lock = __SPIN_LOCK_UNLOCKED(lrng_raw_sched_nvcsw.lock), -+ .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lrng_raw_sched_nvcsw.read_wait) -+}; -+ -+bool lrng_raw_sched_nvcsw_entropy_store(u32 value) -+{ -+ return lrng_testing_store(&lrng_raw_sched_nvcsw, value, -+ &boot_raw_sched_nvcsw_test); -+} -+ -+static int lrng_raw_sched_nvcsw_entropy_reader(u8 *outbuf, u32 outbuflen) -+{ -+ return lrng_testing_reader(&lrng_raw_sched_nvcsw, -+ &boot_raw_sched_nvcsw_test, outbuf, outbuflen); -+} -+ -+static ssize_t lrng_raw_sched_nvcsw_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_testing_extract_user(file, to, count, ppos, -+ lrng_raw_sched_nvcsw_entropy_reader); -+} -+ -+static const struct file_operations lrng_raw_sched_nvcsw_fops = { -+ .owner = THIS_MODULE, -+ .read = lrng_raw_sched_nvcsw_read, -+}; -+ -+#endif /* CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY */ -+ -+/*********************************** ACVT ************************************/ -+ -+#ifdef CONFIG_LRNG_ACVT_HASH -+ -+/* maximum amount of data to be hashed as defined by ACVP */ -+#define LRNG_ACVT_MAX_SHA_MSG (65536 >> 3) -+ -+/* -+ * As we use static variables to store the data, it is clear that the -+ * test interface is only able to handle single threaded testing. This is -+ * considered to be sufficient for testing. If multi-threaded use of the -+ * ACVT test interface would be performed, the caller would get garbage -+ * but the kernel operation is unaffected by this. -+ */ -+static u8 lrng_acvt_hash_data[LRNG_ACVT_MAX_SHA_MSG] -+ __aligned(LRNG_KCAPI_ALIGN); -+static atomic_t lrng_acvt_hash_data_size = ATOMIC_INIT(0); -+static u8 lrng_acvt_hash_digest[LRNG_ATOMIC_DIGEST_SIZE]; -+ -+static ssize_t lrng_acvt_hash_write(struct file *file, const char __user *buf, -+ size_t nbytes, loff_t *ppos) -+{ -+ if (nbytes > LRNG_ACVT_MAX_SHA_MSG) -+ return -EINVAL; -+ -+ atomic_set(&lrng_acvt_hash_data_size, (int)nbytes); -+ -+ return simple_write_to_buffer(lrng_acvt_hash_data, -+ LRNG_ACVT_MAX_SHA_MSG, ppos, buf, nbytes); -+} -+ -+static ssize_t lrng_acvt_hash_read(struct file *file, char __user *to, -+ size_t count, loff_t *ppos) -+{ -+ SHASH_DESC_ON_STACK(shash, NULL); -+ const struct lrng_hash_cb *hash_cb = &lrng_sha_hash_cb; -+ ssize_t ret; -+ -+ if (count > LRNG_ATOMIC_DIGEST_SIZE) -+ return -EINVAL; -+ -+ ret = hash_cb->hash_init(shash, NULL) ?: -+ hash_cb->hash_update(shash, lrng_acvt_hash_data, -+ atomic_read_u32(&lrng_acvt_hash_data_size)) ?: -+ hash_cb->hash_final(shash, lrng_acvt_hash_digest); -+ if (ret) -+ return ret; -+ -+ return simple_read_from_buffer(to, count, ppos, lrng_acvt_hash_digest, -+ sizeof(lrng_acvt_hash_digest)); -+} -+ -+static const struct file_operations lrng_acvt_hash_fops = { -+ .owner = THIS_MODULE, -+ .open = simple_open, -+ .llseek = default_llseek, -+ .read = lrng_acvt_hash_read, -+ .write = lrng_acvt_hash_write, -+}; -+ -+#endif /* CONFIG_LRNG_ACVT_DRNG */ -+ -+/************************************************************************** -+ * Debugfs interface -+ **************************************************************************/ -+ -+static int __init lrng_raw_init(void) -+{ -+ struct dentry *lrng_raw_debugfs_root; -+ -+ lrng_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); -+ -+#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_hires", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_hires_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_jiffies", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_jiffies_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_irq", 0400, lrng_raw_debugfs_root, -+ NULL, &lrng_raw_irq_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_retip", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_retip_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_regs", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_regs_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_ARRAY -+ debugfs_create_file_unsafe("lrng_raw_array", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_array_fops); -+#endif -+#ifdef CONFIG_LRNG_IRQ_PERF -+ debugfs_create_file_unsafe("lrng_irq_perf", 0400, lrng_raw_debugfs_root, -+ NULL, &lrng_irq_perf_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_SCHED_HIRES_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_sched_hires", 0400, -+ lrng_raw_debugfs_root, -+ NULL, &lrng_raw_sched_hires_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_SCHED_PID_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_sched_pid", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_sched_pid_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_SCHED_START_TIME_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_sched_starttime", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_sched_starttime_fops); -+#endif -+#ifdef CONFIG_LRNG_RAW_SCHED_NVCSW_ENTROPY -+ debugfs_create_file_unsafe("lrng_raw_sched_nvcsw", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_raw_sched_nvcsw_fops); -+#endif -+#ifdef CONFIG_LRNG_SCHED_PERF -+ debugfs_create_file_unsafe("lrng_sched_perf", 0400, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_sched_perf_fops); -+#endif -+#ifdef CONFIG_LRNG_ACVT_HASH -+ debugfs_create_file_unsafe("lrng_acvt_hash", 0600, -+ lrng_raw_debugfs_root, NULL, -+ &lrng_acvt_hash_fops); -+#endif -+ -+ return 0; -+} -+ -+module_init(lrng_raw_init); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch deleted file mode 100644 index 2922c975b..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch +++ /dev/null @@ -1,523 +0,0 @@ -From c64dbfe3aeaaebd8dd16e21e5a2c5755e164b003 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 18:13:56 +0200 -Subject: [PATCH 20/25] LRNG - add power-on and runtime self-tests - -Parts of the LRNG are already covered by self-tests, including: - -* Self-test of SP800-90A DRBG provided by the Linux kernel crypto API. - -* Self-test of the PRNG provided by the Linux kernel crypto API. - -* Raw noise source data testing including SP800-90B compliant - tests when enabling CONFIG_LRNG_HEALTH_TESTS - -This patch adds the self-tests for the remaining critical functions of -the LRNG that are essential to maintain entropy and provide -cryptographic strong random numbers. The following self-tests are -implemented: - -* Self-test of the time array maintenance. This test verifies whether -the time stamp array management to store multiple values in one integer -implements a concatenation of the data. - -* Self-test of the software hash implementation ensures that this -function operates compliant to the FIPS 180-4 specification. The -self-test performs a hash operation of a zeroized per-CPU data array. - -* Self-test of the ChaCha20 DRNG is based on the self-tests that are -already present and implemented with the stand-alone user space -ChaCha20 DRNG implementation available at [1]. The self-tests cover -different use cases of the DRNG seeded with known seed data. - -The status of the LRNG self-tests is provided with the selftest_status -SysFS file. If the file contains a zero, the self-tests passed. The -value 0xffffffff means that the self-tests were not executed. Any other -value indicates a self-test failure. - -The self-test may be compiled to panic the system if the self-test -fails. - -All self-tests operate on private state data structures. This implies -that none of the self-tests have any impact on the regular LRNG -operations. This allows the self-tests to be repeated at runtime by -writing anything into the selftest_status SysFS file. - -[1] https://www.chronox.de/chacha20.html - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 52 ++-- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_selftest.c | 397 ++++++++++++++++++++++++++++++ - 3 files changed, 424 insertions(+), 26 deletions(-) - create mode 100644 drivers/char/lrng/lrng_selftest.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -985,32 +985,32 @@ config LRNG_TEST_CPU_ES_COMPRESSION - than what may be required. - - endif #LRNG_TESTING_MENU --# --# config LRNG_SELFTEST --# bool "Enable power-on and on-demand self-tests" --# help --# The power-on self-tests are executed during boot time --# covering the ChaCha20 DRNG, the hash operation used for --# processing the entropy pools and the auxiliary pool, and --# the time stamp management of the LRNG. --# --# The on-demand self-tests are triggered by writing any --# value into the SysFS file selftest_status. At the same --# time, when reading this file, the test status is --# returned. A zero indicates that all tests were executed --# successfully. --# --# If unsure, say Y. --# --# if LRNG_SELFTEST --# --# config LRNG_SELFTEST_PANIC --# bool "Panic the kernel upon self-test failure" --# help --# If the option is enabled, the kernel is terminated if an --# LRNG power-on self-test failure is detected. --# --# endif # LRNG_SELFTEST -+ -+config LRNG_SELFTEST -+ bool "Enable power-on and on-demand self-tests" -+ help -+ The power-on self-tests are executed during boot time -+ covering the ChaCha20 DRNG, the hash operation used for -+ processing the entropy pools and the auxiliary pool, and -+ the time stamp management of the LRNG. -+ -+ The on-demand self-tests are triggered by writing any -+ value into the SysFS file selftest_status. At the same -+ time, when reading this file, the test status is -+ returned. A zero indicates that all tests were executed -+ successfully. -+ -+ If unsure, say Y. -+ -+if LRNG_SELFTEST -+ -+config LRNG_SELFTEST_PANIC -+ bool "Panic the kernel upon self-test failure" -+ help -+ If the option is enabled, the kernel is terminated if an -+ LRNG power-on self-test failure is detected. -+ -+endif # LRNG_SELFTEST - - endif # LRNG - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -27,3 +27,4 @@ obj-$(CONFIG_LRNG_JENT) += lrng_es_jen - - obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o - obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o -+obj-$(CONFIG_LRNG_SELFTEST) += lrng_selftest.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_selftest.c -@@ -0,0 +1,397 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG power-on and on-demand self-test -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+/* -+ * In addition to the self-tests below, the following LRNG components -+ * are covered with self-tests during regular operation: -+ * -+ * * power-on self-test: SP800-90A DRBG provided by the Linux kernel crypto API -+ * * power-on self-test: PRNG provided by the Linux kernel crypto API -+ * * runtime test: Raw noise source data testing including SP800-90B compliant -+ * tests when enabling CONFIG_LRNG_HEALTH_TESTS -+ * -+ * Additional developer tests present with LRNG code: -+ * * SP800-90B APT and RCT test enforcement validation when enabling -+ * CONFIG_LRNG_APT_BROKEN or CONFIG_LRNG_RCT_BROKEN. -+ * * Collection of raw entropy from the interrupt noise source when enabling -+ * CONFIG_LRNG_TESTING and pulling the data from the kernel with the provided -+ * interface. -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+ -+#include "lrng_drng_chacha20.h" -+#include "lrng_sha.h" -+ -+#define LRNG_SELFTEST_PASSED 0 -+#define LRNG_SEFLTEST_ERROR_TIME (1 << 0) -+#define LRNG_SEFLTEST_ERROR_CHACHA20 (1 << 1) -+#define LRNG_SEFLTEST_ERROR_HASH (1 << 2) -+#define LRNG_SEFLTEST_ERROR_GCD (1 << 3) -+#define LRNG_SELFTEST_NOT_EXECUTED 0xffffffff -+ -+#ifdef CONFIG_LRNG_TIMER_COMMON -+ -+#include "lrng_es_timer_common.h" -+ -+static u32 lrng_data_selftest_ptr = 0; -+static u32 lrng_data_selftest[LRNG_DATA_ARRAY_SIZE]; -+ -+static void lrng_data_process_selftest_insert(u32 time) -+{ -+ u32 ptr = lrng_data_selftest_ptr++ & LRNG_DATA_WORD_MASK; -+ unsigned int array = lrng_data_idx2array(ptr); -+ unsigned int slot = lrng_data_idx2slot(ptr); -+ -+ /* zeroization of slot to ensure the following OR adds the data */ -+ lrng_data_selftest[array] &= -+ ~(lrng_data_slot_val(0xffffffff & LRNG_DATA_SLOTSIZE_MASK, -+ slot)); -+ lrng_data_selftest[array] |= -+ lrng_data_slot_val(time & LRNG_DATA_SLOTSIZE_MASK, slot); -+} -+ -+static void lrng_data_process_selftest_u32(u32 data) -+{ -+ u32 pre_ptr, ptr, mask; -+ unsigned int pre_array; -+ -+ /* Increment pointer by number of slots taken for input value */ -+ lrng_data_selftest_ptr += LRNG_DATA_SLOTS_PER_UINT; -+ -+ /* ptr to current unit */ -+ ptr = lrng_data_selftest_ptr; -+ -+ lrng_data_split_u32(&ptr, &pre_ptr, &mask); -+ -+ /* MSB of data go into previous unit */ -+ pre_array = lrng_data_idx2array(pre_ptr); -+ /* zeroization of slot to ensure the following OR adds the data */ -+ lrng_data_selftest[pre_array] &= ~(0xffffffff & ~mask); -+ lrng_data_selftest[pre_array] |= data & ~mask; -+ -+ /* LSB of data go into current unit */ -+ lrng_data_selftest[lrng_data_idx2array(ptr)] = data & mask; -+} -+ -+static unsigned int lrng_data_process_selftest(void) -+{ -+ u32 time; -+ u32 idx_zero_compare = (0 << 0) | (1 << 8) | (2 << 16) | (3 << 24); -+ u32 idx_one_compare = (4 << 0) | (5 << 8) | (6 << 16) | (7 << 24); -+ u32 idx_last_compare = -+ (((LRNG_DATA_NUM_VALUES - 4) & LRNG_DATA_SLOTSIZE_MASK) << 0) | -+ (((LRNG_DATA_NUM_VALUES - 3) & LRNG_DATA_SLOTSIZE_MASK) << 8) | -+ (((LRNG_DATA_NUM_VALUES - 2) & LRNG_DATA_SLOTSIZE_MASK) << 16) | -+ (((LRNG_DATA_NUM_VALUES - 1) & LRNG_DATA_SLOTSIZE_MASK) << 24); -+ -+ (void)idx_one_compare; -+ -+ /* "poison" the array to verify the operation of the zeroization */ -+ lrng_data_selftest[0] = 0xffffffff; -+ lrng_data_selftest[1] = 0xffffffff; -+ -+ lrng_data_process_selftest_insert(0); -+ /* -+ * Note, when using lrng_data_process_u32() on unaligned ptr, -+ * the first slots will go into next word, and the last slots go -+ * into the previous word. -+ */ -+ lrng_data_process_selftest_u32((4 << 0) | (1 << 8) | (2 << 16) | -+ (3 << 24)); -+ lrng_data_process_selftest_insert(5); -+ lrng_data_process_selftest_insert(6); -+ lrng_data_process_selftest_insert(7); -+ -+ if ((lrng_data_selftest[0] != idx_zero_compare) || -+ (lrng_data_selftest[1] != idx_one_compare)) -+ goto err; -+ -+ /* Reset for next test */ -+ lrng_data_selftest[0] = 0; -+ lrng_data_selftest[1] = 0; -+ lrng_data_selftest_ptr = 0; -+ -+ for (time = 0; time < LRNG_DATA_NUM_VALUES; time++) -+ lrng_data_process_selftest_insert(time); -+ -+ if ((lrng_data_selftest[0] != idx_zero_compare) || -+ (lrng_data_selftest[1] != idx_one_compare) || -+ (lrng_data_selftest[LRNG_DATA_ARRAY_SIZE - 1] != idx_last_compare)) -+ goto err; -+ -+ return LRNG_SELFTEST_PASSED; -+ -+err: -+ pr_err("LRNG data array self-test FAILED\n"); -+ return LRNG_SEFLTEST_ERROR_TIME; -+} -+ -+static unsigned int lrng_gcd_selftest(void) -+{ -+ u32 history[10]; -+ unsigned int i; -+ -+#define LRNG_GCD_SELFTEST 3 -+ for (i = 0; i < ARRAY_SIZE(history); i++) -+ history[i] = i * LRNG_GCD_SELFTEST; -+ -+ if (lrng_gcd_analyze(history, ARRAY_SIZE(history)) == LRNG_GCD_SELFTEST) -+ return LRNG_SELFTEST_PASSED; -+ -+ pr_err("LRNG GCD self-test FAILED\n"); -+ return LRNG_SEFLTEST_ERROR_GCD; -+} -+ -+#else /* CONFIG_LRNG_TIMER_COMMON */ -+ -+static unsigned int lrng_data_process_selftest(void) -+{ -+ return LRNG_SELFTEST_PASSED; -+} -+ -+static unsigned int lrng_gcd_selftest(void) -+{ -+ return LRNG_SELFTEST_PASSED; -+} -+ -+#endif /* CONFIG_LRNG_TIMER_COMMON */ -+ -+/* The test vectors are taken from crypto/testmgr.h */ -+static unsigned int lrng_hash_selftest(void) -+{ -+ SHASH_DESC_ON_STACK(shash, NULL); -+ const struct lrng_hash_cb *hash_cb = &lrng_sha_hash_cb; -+ static const u8 lrng_hash_selftest_result[] = -+#ifdef CONFIG_CRYPTO_LIB_SHA256 -+ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, -+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, -+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, -+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }; -+#else /* CONFIG_CRYPTO_LIB_SHA256 */ -+ { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, -+ 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d }; -+#endif /* CONFIG_CRYPTO_LIB_SHA256 */ -+ static const u8 hash_input[] = { 0x61, 0x62, 0x63 }; /* "abc" */ -+ u8 digest[sizeof(lrng_hash_selftest_result)] __aligned(sizeof(u32)); -+ -+ if (sizeof(digest) != hash_cb->hash_digestsize(NULL)) -+ return LRNG_SEFLTEST_ERROR_HASH; -+ -+ if (!hash_cb->hash_init(shash, NULL) && -+ !hash_cb->hash_update(shash, hash_input, -+ sizeof(hash_input)) && -+ !hash_cb->hash_final(shash, digest) && -+ !memcmp(digest, lrng_hash_selftest_result, sizeof(digest))) -+ return 0; -+ -+ pr_err("LRNG %s Hash self-test FAILED\n", hash_cb->hash_name()); -+ return LRNG_SEFLTEST_ERROR_HASH; -+} -+ -+#ifdef CONFIG_LRNG_DRNG_CHACHA20 -+ -+static void lrng_selftest_bswap32(u32 *ptr, u32 words) -+{ -+ u32 i; -+ -+ /* Byte-swap data which is an LE representation */ -+ for (i = 0; i < words; i++) { -+ __le32 *p = (__le32 *)ptr; -+ -+ *p = cpu_to_le32(*ptr); -+ ptr++; -+ } -+} -+ -+/* -+ * The test vectors were generated using the ChaCha20 DRNG from -+ * https://www.chronox.de/chacha20.html -+ */ -+static unsigned int lrng_chacha20_drng_selftest(void) -+{ -+ const struct lrng_drng_cb *drng_cb = &lrng_cc20_drng_cb; -+ u8 seed[CHACHA_KEY_SIZE * 2] = { -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, -+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, -+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, -+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, -+ }; -+ struct chacha20_block chacha20; -+ int ret; -+ u8 outbuf[CHACHA_KEY_SIZE * 2] __aligned(sizeof(u32)); -+ -+ /* -+ * Expected result when ChaCha20 DRNG state is zero: -+ * * constants are set to "expand 32-byte k" -+ * * remaining state is 0 -+ * and pulling one half ChaCha20 DRNG block. -+ */ -+ static const u8 expected_halfblock[CHACHA_KEY_SIZE] = { -+ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, -+ 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, -+ 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, -+ 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7 }; -+ -+ /* -+ * Expected result when ChaCha20 DRNG state is zero: -+ * * constants are set to "expand 32-byte k" -+ * * remaining state is 0 -+ * followed by a reseed with two keyblocks -+ * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -+ * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, -+ * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -+ * 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, -+ * 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, -+ * 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -+ * 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f -+ * and pulling one ChaCha20 DRNG block. -+ */ -+ static const u8 expected_oneblock[CHACHA_KEY_SIZE * 2] = { -+ 0xe3, 0xb0, 0x8a, 0xcc, 0x34, 0xc3, 0x17, 0x0e, -+ 0xc3, 0xd8, 0xc3, 0x40, 0xe7, 0x73, 0xe9, 0x0d, -+ 0xd1, 0x62, 0xa3, 0x5d, 0x7d, 0xf2, 0xf1, 0x4a, -+ 0x24, 0x42, 0xb7, 0x1e, 0xb0, 0x05, 0x17, 0x07, -+ 0xb9, 0x35, 0x10, 0x69, 0x8b, 0x46, 0xfb, 0x51, -+ 0xe9, 0x91, 0x3f, 0x46, 0xf2, 0x4d, 0xea, 0xd0, -+ 0x81, 0xc1, 0x1b, 0xa9, 0x5d, 0x52, 0x91, 0x5f, -+ 0xcd, 0xdc, 0xc6, 0xd6, 0xc3, 0x7c, 0x50, 0x23 }; -+ -+ /* -+ * Expected result when ChaCha20 DRNG state is zero: -+ * * constants are set to "expand 32-byte k" -+ * * remaining state is 0 -+ * followed by a reseed with one key block plus one byte -+ * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -+ * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, -+ * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -+ * 0x20 -+ * and pulling less than one ChaCha20 DRNG block. -+ */ -+ static const u8 expected_block_nonalinged[CHACHA_KEY_SIZE + 4] = { -+ 0x9c, 0xfc, 0x5e, 0x31, 0x21, 0x62, 0x11, 0x85, -+ 0xd3, 0x77, 0xd3, 0x69, 0x0f, 0xa8, 0x16, 0x55, -+ 0xb4, 0x4c, 0xf6, 0x52, 0xf3, 0xa8, 0x37, 0x99, -+ 0x38, 0x76, 0xa0, 0x66, 0xec, 0xbb, 0xce, 0xa9, -+ 0x9c, 0x95, 0xa1, 0xfd }; -+ -+ BUILD_BUG_ON(sizeof(seed) % sizeof(u32)); -+ -+ memset(&chacha20, 0, sizeof(chacha20)); -+ lrng_cc20_init_rfc7539(&chacha20); -+ lrng_selftest_bswap32((u32 *)seed, sizeof(seed) / sizeof(u32)); -+ -+ /* Generate with zero state */ -+ ret = drng_cb->drng_generate(&chacha20, outbuf, -+ sizeof(expected_halfblock)); -+ if (ret != sizeof(expected_halfblock)) -+ goto err; -+ if (memcmp(outbuf, expected_halfblock, sizeof(expected_halfblock))) -+ goto err; -+ -+ /* Clear state of DRNG */ -+ memset(&chacha20.key.u[0], 0, 48); -+ -+ /* Reseed with 2 key blocks */ -+ ret = drng_cb->drng_seed(&chacha20, seed, sizeof(expected_oneblock)); -+ if (ret < 0) -+ goto err; -+ ret = drng_cb->drng_generate(&chacha20, outbuf, -+ sizeof(expected_oneblock)); -+ if (ret != sizeof(expected_oneblock)) -+ goto err; -+ if (memcmp(outbuf, expected_oneblock, sizeof(expected_oneblock))) -+ goto err; -+ -+ /* Clear state of DRNG */ -+ memset(&chacha20.key.u[0], 0, 48); -+ -+ /* Reseed with 1 key block and one byte */ -+ ret = drng_cb->drng_seed(&chacha20, seed, -+ sizeof(expected_block_nonalinged)); -+ if (ret < 0) -+ goto err; -+ ret = drng_cb->drng_generate(&chacha20, outbuf, -+ sizeof(expected_block_nonalinged)); -+ if (ret != sizeof(expected_block_nonalinged)) -+ goto err; -+ if (memcmp(outbuf, expected_block_nonalinged, -+ sizeof(expected_block_nonalinged))) -+ goto err; -+ -+ return LRNG_SELFTEST_PASSED; -+ -+err: -+ pr_err("LRNG ChaCha20 DRNG self-test FAILED\n"); -+ return LRNG_SEFLTEST_ERROR_CHACHA20; -+} -+ -+#else /* CONFIG_LRNG_DRNG_CHACHA20 */ -+ -+static unsigned int lrng_chacha20_drng_selftest(void) -+{ -+ return LRNG_SELFTEST_PASSED; -+} -+ -+#endif /* CONFIG_LRNG_DRNG_CHACHA20 */ -+ -+static unsigned int lrng_selftest_status = LRNG_SELFTEST_NOT_EXECUTED; -+ -+static int lrng_selftest(void) -+{ -+ unsigned int ret = lrng_data_process_selftest(); -+ -+ ret |= lrng_chacha20_drng_selftest(); -+ ret |= lrng_hash_selftest(); -+ ret |= lrng_gcd_selftest(); -+ -+ if (ret) { -+ if (IS_ENABLED(CONFIG_LRNG_SELFTEST_PANIC)) -+ panic("LRNG self-tests failed: %u\n", ret); -+ } else { -+ pr_info("LRNG self-tests passed\n"); -+ } -+ -+ lrng_selftest_status = ret; -+ -+ if (lrng_selftest_status) -+ return -EFAULT; -+ return 0; -+} -+ -+#ifdef CONFIG_SYSFS -+/* Re-perform self-test when any value is written to the sysfs file. */ -+static int lrng_selftest_sysfs_set(const char *val, -+ const struct kernel_param *kp) -+{ -+ return lrng_selftest(); -+} -+ -+static const struct kernel_param_ops lrng_selftest_sysfs = { -+ .set = lrng_selftest_sysfs_set, -+ .get = param_get_uint, -+}; -+module_param_cb(selftest_status, &lrng_selftest_sysfs, &lrng_selftest_status, -+ 0644); -+#endif /* CONFIG_SYSFS */ -+ -+static int __init lrng_selftest_init(void) -+{ -+ return lrng_selftest(); -+} -+ -+module_init(lrng_selftest_init); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch deleted file mode 100644 index 6959c81f8..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 4b870ec78ee021d4134ffdbb007e0a9299d76126 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 31 Jul 2022 22:34:51 +0200 -Subject: [PATCH 21/25] LRNG - sysctls and /proc interface - -The LRNG sysctl interface provides the same controls as the existing -/dev/random implementation. These sysctls behave identically and are -implemented identically. The goal is to allow a possible merge of the -existing /dev/random implementation with this implementation which -implies that this patch tries have a very close similarity. Yet, all -sysctls are documented at [1]. - -The sysctl implementation is only enabled if the existing random.c file -is not compiled. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_sysctl.c | 139 ++++++++++++++++++++++++++++++++ - 2 files changed, 140 insertions(+) - create mode 100644 drivers/char/lrng/lrng_sysctl.c - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -9,6 +9,7 @@ obj-$(CONFIG_LRNG_SHA256) += lrng_sha25 - obj-$(CONFIG_LRNG_SHA1) += lrng_sha1.o - - obj-$(CONFIG_SYSCTL) += lrng_proc.o -+obj-$(CONFIG_LRNG_SYSCTL) += lrng_sysctl.o - obj-$(CONFIG_NUMA) += lrng_numa.o - - obj-$(CONFIG_LRNG_SWITCH) += lrng_switch.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_sysctl.c -@@ -0,0 +1,139 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG sysctl interfaces -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "lrng_drng_mgr.h" -+#include "lrng_es_mgr.h" -+#include "lrng_sysctl.h" -+ -+/* -+ * This function is used to return both the bootid UUID, and random -+ * UUID. The difference is in whether table->data is NULL; if it is, -+ * then a new UUID is generated and returned to the user. -+ * -+ * If the user accesses this via the proc interface, the UUID will be -+ * returned as an ASCII string in the standard UUID format; if via the -+ * sysctl system call, as 16 bytes of binary data. -+ */ -+static int lrng_sysctl_do_uuid(struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos) -+{ -+ struct ctl_table fake_table; -+ unsigned char buf[64], tmp_uuid[16], *uuid; -+ -+ uuid = table->data; -+ if (!uuid) { -+ uuid = tmp_uuid; -+ generate_random_uuid(uuid); -+ } else { -+ static DEFINE_SPINLOCK(bootid_spinlock); -+ -+ spin_lock(&bootid_spinlock); -+ if (!uuid[8]) -+ generate_random_uuid(uuid); -+ spin_unlock(&bootid_spinlock); -+ } -+ -+ sprintf(buf, "%pU", uuid); -+ -+ fake_table.data = buf; -+ fake_table.maxlen = sizeof(buf); -+ -+ return proc_dostring(&fake_table, write, buffer, lenp, ppos); -+} -+ -+static int lrng_sysctl_do_entropy(struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos) -+{ -+ struct ctl_table fake_table; -+ int entropy_count = lrng_avail_entropy_aux(); -+ -+ fake_table.data = &entropy_count; -+ fake_table.maxlen = sizeof(entropy_count); -+ -+ return proc_dointvec(&fake_table, write, buffer, lenp, ppos); -+} -+ -+static int lrng_sysctl_do_poolsize(struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos) -+{ -+ struct ctl_table fake_table; -+ u32 entropy_count = lrng_es[lrng_ext_es_aux]->max_entropy(); -+ -+ fake_table.data = &entropy_count; -+ fake_table.maxlen = sizeof(entropy_count); -+ -+ return proc_dointvec(&fake_table, write, buffer, lenp, ppos); -+} -+ -+static int lrng_min_write_thresh; -+static int lrng_max_write_thresh = (LRNG_WRITE_WAKEUP_ENTROPY << 3); -+static char lrng_sysctl_bootid[16]; -+static int lrng_drng_reseed_max_min; -+ -+void lrng_sysctl_update_max_write_thresh(u32 new_digestsize) -+{ -+ lrng_max_write_thresh = (int)new_digestsize; -+ /* Ensure that changes to the global variable are visible */ -+ mb(); -+} -+ -+static struct ctl_table random_table[] = { -+ { -+ .procname = "poolsize", -+ .maxlen = sizeof(int), -+ .mode = 0444, -+ .proc_handler = lrng_sysctl_do_poolsize, -+ }, -+ { -+ .procname = "entropy_avail", -+ .maxlen = sizeof(int), -+ .mode = 0444, -+ .proc_handler = lrng_sysctl_do_entropy, -+ }, -+ { -+ .procname = "write_wakeup_threshold", -+ .data = &lrng_write_wakeup_bits, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax, -+ .extra1 = &lrng_min_write_thresh, -+ .extra2 = &lrng_max_write_thresh, -+ }, -+ { -+ .procname = "boot_id", -+ .data = &lrng_sysctl_bootid, -+ .maxlen = 16, -+ .mode = 0444, -+ .proc_handler = lrng_sysctl_do_uuid, -+ }, -+ { -+ .procname = "uuid", -+ .maxlen = 16, -+ .mode = 0444, -+ .proc_handler = lrng_sysctl_do_uuid, -+ }, -+ { -+ .procname = "urandom_min_reseed_secs", -+ .data = &lrng_drng_reseed_max_time, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec, -+ .extra1 = &lrng_drng_reseed_max_min, -+ }, -+}; -+ -+static int __init random_sysctls_init(void) -+{ -+ register_sysctl_init("kernel/random", random_table); -+ return 0; -+} -+device_initcall(random_sysctls_init); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch deleted file mode 100644 index a61070740..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch +++ /dev/null @@ -1,938 +0,0 @@ -From d527a9b879562f0d7e83fbda53269c39cd9801de Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Mon, 20 Feb 2023 22:12:04 +0100 -Subject: [PATCH 22/25] LRMG - add drop-in replacement random(4) API - -The LRNG is intended to be a full replacement of the existing random.c. -This also includes the providing of a full API and ABI compliant drop-in -replacement of all APIs offered by random.c. - -These LRNG interfaces are compiled when the random.c is not compiled -any more. - -Signed-off-by: Stephan Mueller ---- - drivers/char/Makefile | 3 +- - drivers/char/lrng/Makefile | 5 + - drivers/char/lrng/lrng_interface_aux.c | 210 ++++++++++++ - drivers/char/lrng/lrng_interface_dev_common.c | 315 ++++++++++++++++++ - .../char/lrng/lrng_interface_random_kernel.c | 248 ++++++++++++++ - .../char/lrng/lrng_interface_random_user.c | 104 ++++++ - 6 files changed, 884 insertions(+), 1 deletion(-) - create mode 100644 drivers/char/lrng/lrng_interface_aux.c - create mode 100644 drivers/char/lrng/lrng_interface_dev_common.c - create mode 100644 drivers/char/lrng/lrng_interface_random_kernel.c - create mode 100644 drivers/char/lrng/lrng_interface_random_user.c - ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -3,7 +3,8 @@ - # Makefile for the kernel character device drivers. - # - --obj-y += mem.o random.o -+obj-y += mem.o -+obj-$(CONFIG_RANDOM_DEFAULT_IMPL) += random.o - obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o - obj-y += misc.o - obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -29,3 +29,8 @@ obj-$(CONFIG_LRNG_JENT) += lrng_es_jen - obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o - obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o - obj-$(CONFIG_LRNG_SELFTEST) += lrng_selftest.o -+ -+obj-$(CONFIG_LRNG_COMMON_DEV_IF) += lrng_interface_dev_common.o -+obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_interface_random_user.o \ -+ lrng_interface_random_kernel.o \ -+ lrng_interface_aux.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_aux.c -@@ -0,0 +1,210 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG auxiliary interfaces -+ * -+ * Copyright (C) 2022 Stephan Mueller -+ * Copyright (C) 2017 Jason A. Donenfeld . All -+ * Rights Reserved. -+ * Copyright (C) 2016 Jason Cooper -+ */ -+ -+#include -+#include -+#include -+ -+#include "lrng_es_mgr.h" -+#include "lrng_interface_random_kernel.h" -+ -+/* -+ * Fill a buffer with random numbers and tokenize it to provide random numbers -+ * to callers in fixed chunks. This approach is provided to be consistent with -+ * the Linux kernel interface requirements. Yet, this approach violate the -+ * backtracking resistance of the random number generator. Thus, the provided -+ * random numbers are not considered to be as strong as those requested directly -+ * from the LRNG. -+ */ -+struct batched_entropy { -+ union { -+ u64 entropy_u64[LRNG_DRNG_BLOCKSIZE / sizeof(u64)]; -+ u32 entropy_u32[LRNG_DRNG_BLOCKSIZE / sizeof(u32)]; -+ u16 entropy_u16[LRNG_DRNG_BLOCKSIZE / sizeof(u16)]; -+ u8 entropy_u8[LRNG_DRNG_BLOCKSIZE / sizeof(u8)]; -+ }; -+ unsigned int position; -+ spinlock_t batch_lock; -+}; -+ -+/* -+ * Get a random word for internal kernel use only. The quality of the random -+ * number is as good as /dev/urandom, but there is no backtrack protection, -+ * with the goal of being quite fast and not depleting entropy. -+ */ -+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = { -+ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u64.lock), -+}; -+ -+u64 get_random_u64(void) -+{ -+ u64 ret; -+ unsigned long flags; -+ struct batched_entropy *batch; -+ -+ lrng_debug_report_seedlevel("get_random_u64"); -+ -+ batch = raw_cpu_ptr(&batched_entropy_u64); -+ spin_lock_irqsave(&batch->batch_lock, flags); -+ if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) { -+ lrng_get_random_bytes(batch->entropy_u64, LRNG_DRNG_BLOCKSIZE); -+ batch->position = 0; -+ } -+ ret = batch->entropy_u64[batch->position++]; -+ spin_unlock_irqrestore(&batch->batch_lock, flags); -+ return ret; -+} -+EXPORT_SYMBOL(get_random_u64); -+ -+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32) = { -+ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u32.lock), -+}; -+ -+u32 get_random_u32(void) -+{ -+ u32 ret; -+ unsigned long flags; -+ struct batched_entropy *batch; -+ -+ lrng_debug_report_seedlevel("get_random_u32"); -+ -+ batch = raw_cpu_ptr(&batched_entropy_u32); -+ spin_lock_irqsave(&batch->batch_lock, flags); -+ if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) { -+ lrng_get_random_bytes(batch->entropy_u32, LRNG_DRNG_BLOCKSIZE); -+ batch->position = 0; -+ } -+ ret = batch->entropy_u32[batch->position++]; -+ spin_unlock_irqrestore(&batch->batch_lock, flags); -+ return ret; -+} -+EXPORT_SYMBOL(get_random_u32); -+ -+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u16) = { -+ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u16.lock), -+}; -+ -+u16 get_random_u16(void) -+{ -+ u16 ret; -+ unsigned long flags; -+ struct batched_entropy *batch; -+ -+ lrng_debug_report_seedlevel("get_random_u16"); -+ -+ batch = raw_cpu_ptr(&batched_entropy_u16); -+ spin_lock_irqsave(&batch->batch_lock, flags); -+ if (batch->position % ARRAY_SIZE(batch->entropy_u16) == 0) { -+ lrng_get_random_bytes(batch->entropy_u16, LRNG_DRNG_BLOCKSIZE); -+ batch->position = 0; -+ } -+ ret = batch->entropy_u16[batch->position++]; -+ spin_unlock_irqrestore(&batch->batch_lock, flags); -+ return ret; -+} -+EXPORT_SYMBOL(get_random_u16); -+ -+static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u8) = { -+ .batch_lock = __SPIN_LOCK_UNLOCKED(batched_entropy_u8.lock), -+}; -+ -+u8 get_random_u8(void) -+{ -+ u8 ret; -+ unsigned long flags; -+ struct batched_entropy *batch; -+ -+ lrng_debug_report_seedlevel("get_random_u8"); -+ -+ batch = raw_cpu_ptr(&batched_entropy_u8); -+ spin_lock_irqsave(&batch->batch_lock, flags); -+ if (batch->position % ARRAY_SIZE(batch->entropy_u8) == 0) { -+ lrng_get_random_bytes(batch->entropy_u8, LRNG_DRNG_BLOCKSIZE); -+ batch->position = 0; -+ } -+ ret = batch->entropy_u8[batch->position++]; -+ spin_unlock_irqrestore(&batch->batch_lock, flags); -+ return ret; -+} -+EXPORT_SYMBOL(get_random_u8); -+ -+/* Taken directly from random.c */ -+u32 __get_random_u32_below(u32 ceil) -+{ -+ u64 mult = (u64)ceil * get_random_u32(); -+ -+ if (unlikely((u32)mult < ceil)) { -+ u32 bound = -ceil % ceil; -+ while (unlikely((u32)mult < bound)) -+ mult = (u64)ceil * get_random_u32(); -+ } -+ return mult >> 32; -+} -+EXPORT_SYMBOL(__get_random_u32_below); -+ -+#ifdef CONFIG_SMP -+/* -+ * This function is called when the CPU is coming up, with entry -+ * CPUHP_RANDOM_PREPARE, which comes before CPUHP_WORKQUEUE_PREP. -+ */ -+int random_prepare_cpu(unsigned int cpu) -+{ -+ /* -+ * When the cpu comes back online, immediately invalidate all batches, -+ * so that we serve fresh randomness. -+ */ -+ per_cpu_ptr(&batched_entropy_u8, cpu)->position = 0; -+ per_cpu_ptr(&batched_entropy_u16, cpu)->position = 0; -+ per_cpu_ptr(&batched_entropy_u32, cpu)->position = 0; -+ per_cpu_ptr(&batched_entropy_u64, cpu)->position = 0; -+ return 0; -+} -+ -+int random_online_cpu(unsigned int cpu) -+{ -+ return 0; -+} -+#endif -+ -+/* -+ * It's important to invalidate all potential batched entropy that might -+ * be stored before the crng is initialized, which we can do lazily by -+ * simply resetting the counter to zero so that it's re-extracted on the -+ * next usage. -+ */ -+void invalidate_batched_entropy(void) -+{ -+ int cpu; -+ unsigned long flags; -+ -+ for_each_possible_cpu(cpu) { -+ struct batched_entropy *batched_entropy; -+ -+ batched_entropy = per_cpu_ptr(&batched_entropy_u8, cpu); -+ spin_lock_irqsave(&batched_entropy->batch_lock, flags); -+ batched_entropy->position = 0; -+ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); -+ -+ batched_entropy = per_cpu_ptr(&batched_entropy_u16, cpu); -+ spin_lock_irqsave(&batched_entropy->batch_lock, flags); -+ batched_entropy->position = 0; -+ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); -+ -+ batched_entropy = per_cpu_ptr(&batched_entropy_u32, cpu); -+ spin_lock_irqsave(&batched_entropy->batch_lock, flags); -+ batched_entropy->position = 0; -+ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); -+ -+ batched_entropy = per_cpu_ptr(&batched_entropy_u64, cpu); -+ spin_lock(&batched_entropy->batch_lock); -+ batched_entropy->position = 0; -+ spin_unlock_irqrestore(&batched_entropy->batch_lock, flags); -+ } -+} ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_dev_common.c -@@ -0,0 +1,315 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG User and kernel space interfaces -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+ -+#include "lrng_drng_mgr.h" -+#include "lrng_es_aux.h" -+#include "lrng_es_mgr.h" -+#include "lrng_interface_dev_common.h" -+ -+DECLARE_WAIT_QUEUE_HEAD(lrng_write_wait); -+static struct fasync_struct *fasync; -+ -+static bool lrng_seed_hw = true; /* Allow HW to provide seed */ -+static bool lrng_seed_user = true; /* Allow user space to provide seed */ -+ -+/********************************** Helper ***********************************/ -+ -+static u32 lrng_get_aux_ent(void) -+{ -+ return lrng_es[lrng_ext_es_aux]->curr_entropy(0); -+} -+ -+/* Is the DRNG seed level too low? */ -+bool lrng_need_entropy(void) -+{ -+ return (lrng_get_aux_ent() < lrng_write_wakeup_bits); -+} -+ -+void lrng_writer_wakeup(void) -+{ -+ if (lrng_need_entropy() && wq_has_sleeper(&lrng_write_wait)) { -+ wake_up_interruptible(&lrng_write_wait); -+ kill_fasync(&fasync, SIGIO, POLL_OUT); -+ } -+} -+ -+void lrng_init_wakeup_dev(void) -+{ -+ kill_fasync(&fasync, SIGIO, POLL_IN); -+} -+ -+/* External entropy provider is allowed to provide seed data */ -+bool lrng_state_exseed_allow(enum lrng_external_noise_source source) -+{ -+ if (source == lrng_noise_source_hw) -+ return lrng_seed_hw; -+ return lrng_seed_user; -+} -+ -+/* Enable / disable external entropy provider to furnish seed */ -+void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type) -+{ -+ /* -+ * If the LRNG is not yet operational, allow all entropy sources -+ * to deliver data unconditionally to get fully seeded asap. -+ */ -+ if (!lrng_state_operational()) -+ return; -+ -+ if (source == lrng_noise_source_hw) -+ lrng_seed_hw = type; -+ else -+ lrng_seed_user = type; -+} -+ -+void lrng_state_exseed_allow_all(void) -+{ -+ lrng_state_exseed_set(lrng_noise_source_hw, true); -+ lrng_state_exseed_set(lrng_noise_source_user, true); -+} -+ -+/************************ LRNG user output interfaces *************************/ -+ -+ssize_t lrng_read_seed(char __user *buf, size_t nbytes, unsigned int flags) -+{ -+ ssize_t ret = 0; -+ u64 t[(sizeof(struct entropy_buf) + 3 * sizeof(u64) - 1) / sizeof(u64)]; -+ -+ memset(t, 0, sizeof(t)); -+ ret = lrng_get_seed(t, min_t(size_t, nbytes, sizeof(t)), flags); -+ if (ret == -EMSGSIZE && copy_to_user(buf, t, sizeof(u64))) -+ ret = -EFAULT; -+ else if (ret > 0 && copy_to_user(buf, t, ret)) -+ ret = -EFAULT; -+ -+ memzero_explicit(t, sizeof(t)); -+ -+ return ret; -+} -+ -+ssize_t lrng_read_common(char __user *buf, size_t nbytes, bool pr) -+{ -+ ssize_t ret = 0; -+ u8 tmpbuf[LRNG_DRNG_BLOCKSIZE] __aligned(LRNG_KCAPI_ALIGN); -+ u8 *tmp_large = NULL, *tmp = tmpbuf; -+ u32 tmplen = sizeof(tmpbuf); -+ -+ if (nbytes == 0) -+ return 0; -+ -+ /* -+ * Satisfy large read requests -- as the common case are smaller -+ * request sizes, such as 16 or 32 bytes, avoid a kmalloc overhead for -+ * those by using the stack variable of tmpbuf. -+ */ -+ if (!CONFIG_BASE_SMALL && (nbytes > sizeof(tmpbuf))) { -+ tmplen = min_t(u32, nbytes, LRNG_DRNG_MAX_REQSIZE); -+ tmp_large = kmalloc(tmplen + LRNG_KCAPI_ALIGN, GFP_KERNEL); -+ if (!tmp_large) -+ tmplen = sizeof(tmpbuf); -+ else -+ tmp = PTR_ALIGN(tmp_large, LRNG_KCAPI_ALIGN); -+ } -+ -+ while (nbytes) { -+ u32 todo = min_t(u32, nbytes, tmplen); -+ int rc = 0; -+ -+ /* Reschedule if we received a large request. */ -+ if ((tmp_large) && need_resched()) { -+ if (signal_pending(current)) { -+ if (ret == 0) -+ ret = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ } -+ -+ rc = lrng_drng_get_sleep(tmp, todo, pr); -+ if (rc <= 0) { -+ if (rc < 0) -+ ret = rc; -+ break; -+ } -+ if (copy_to_user(buf, tmp, rc)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ nbytes -= rc; -+ buf += rc; -+ ret += rc; -+ } -+ -+ /* Wipe data just returned from memory */ -+ if (tmp_large) -+ kfree_sensitive(tmp_large); -+ else -+ memzero_explicit(tmpbuf, sizeof(tmpbuf)); -+ -+ return ret; -+} -+ -+ssize_t lrng_read_common_block(int nonblock, int pr, -+ char __user *buf, size_t nbytes) -+{ -+ int ret; -+ -+ if (nbytes == 0) -+ return 0; -+ -+ ret = lrng_drng_sleep_while_nonoperational(nonblock); -+ if (ret) -+ return ret; -+ -+ return lrng_read_common(buf, nbytes, !!pr); -+} -+ -+ssize_t lrng_drng_read_block(struct file *file, char __user *buf, size_t nbytes, -+ loff_t *ppos) -+{ -+ return lrng_read_common_block(file->f_flags & O_NONBLOCK, -+ file->f_flags & O_SYNC, buf, nbytes); -+} -+ -+__poll_t lrng_random_poll(struct file *file, poll_table *wait) -+{ -+ __poll_t mask; -+ -+ poll_wait(file, &lrng_init_wait, wait); -+ poll_wait(file, &lrng_write_wait, wait); -+ mask = 0; -+ if (lrng_state_operational()) -+ mask |= EPOLLIN | EPOLLRDNORM; -+ if (lrng_need_entropy() || -+ lrng_state_exseed_allow(lrng_noise_source_user)) { -+ lrng_state_exseed_set(lrng_noise_source_user, false); -+ mask |= EPOLLOUT | EPOLLWRNORM; -+ } -+ return mask; -+} -+ -+ssize_t lrng_drng_write_common(const char __user *buffer, size_t count, -+ u32 entropy_bits) -+{ -+ ssize_t ret = 0; -+ u8 buf[64] __aligned(LRNG_KCAPI_ALIGN); -+ const char __user *p = buffer; -+ u32 orig_entropy_bits = entropy_bits; -+ -+ if (!lrng_get_available()) { -+ ret = lrng_drng_initalize(); -+ if (!ret) -+ return ret; -+ } -+ -+ count = min_t(size_t, count, INT_MAX); -+ while (count > 0) { -+ size_t bytes = min_t(size_t, count, sizeof(buf)); -+ u32 ent = min_t(u32, bytes<<3, entropy_bits); -+ -+ if (copy_from_user(&buf, p, bytes)) -+ return -EFAULT; -+ /* Inject data into entropy pool */ -+ lrng_pool_insert_aux(buf, bytes, ent); -+ -+ count -= bytes; -+ p += bytes; -+ ret += bytes; -+ entropy_bits -= ent; -+ -+ cond_resched(); -+ } -+ -+ /* Force reseed of DRNG during next data request. */ -+ if (!orig_entropy_bits) -+ lrng_drng_force_reseed(); -+ -+ return ret; -+} -+ -+ssize_t lrng_drng_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ return lrng_drng_write_common(buffer, count, 0); -+} -+ -+long lrng_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -+{ -+ u32 digestsize_bits; -+ int size, ent_count_bits, ret; -+ int __user *p = (int __user *)arg; -+ -+ switch (cmd) { -+ case RNDGETENTCNT: -+ ent_count_bits = lrng_avail_entropy_aux(); -+ if (put_user(ent_count_bits, p)) -+ return -EFAULT; -+ return 0; -+ case RNDADDTOENTCNT: -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ if (get_user(ent_count_bits, p)) -+ return -EFAULT; -+ ent_count_bits = (int)lrng_get_aux_ent() + ent_count_bits; -+ if (ent_count_bits < 0) -+ ent_count_bits = 0; -+ digestsize_bits = lrng_get_digestsize(); -+ if (ent_count_bits > digestsize_bits) -+ ent_count_bits = digestsize_bits; -+ lrng_pool_set_entropy(ent_count_bits); -+ return 0; -+ case RNDADDENTROPY: -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ if (get_user(ent_count_bits, p++)) -+ return -EFAULT; -+ if (ent_count_bits < 0) -+ return -EINVAL; -+ if (get_user(size, p++)) -+ return -EFAULT; -+ if (size < 0) -+ return -EINVAL; -+ /* there cannot be more entropy than data */ -+ ent_count_bits = min(ent_count_bits, size<<3); -+ ret = lrng_drng_write_common((const char __user *)p, size, -+ ent_count_bits); -+ return (ret < 0) ? ret : 0; -+ case RNDZAPENTCNT: -+ case RNDCLEARPOOL: -+ /* Clear the entropy pool counter. */ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ lrng_pool_set_entropy(0); -+ return 0; -+ case RNDRESEEDCRNG: -+ /* -+ * We leave the capability check here since it is present -+ * in the upstream's RNG implementation. Yet, user space -+ * can trigger a reseed as easy as writing into /dev/random -+ * or /dev/urandom where no privilege is needed. -+ */ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ /* Force a reseed of all DRNGs */ -+ lrng_drng_force_reseed(); -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+EXPORT_SYMBOL(lrng_ioctl); -+ -+int lrng_fasync(int fd, struct file *filp, int on) -+{ -+ return fasync_helper(fd, filp, on, &fasync); -+} ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_random_kernel.c -@@ -0,0 +1,248 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Kernel space interfaces API/ABI compliant to linux/random.h -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "lrng_es_aux.h" -+#include "lrng_es_irq.h" -+#include "lrng_es_mgr.h" -+#include "lrng_interface_dev_common.h" -+#include "lrng_interface_random_kernel.h" -+ -+static ATOMIC_NOTIFIER_HEAD(random_ready_notifier); -+ -+/********************************** Helper ***********************************/ -+ -+static bool lrng_trust_bootloader __initdata = -+ IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER); -+ -+static int __init lrng_parse_trust_bootloader(char *arg) -+{ -+ return kstrtobool(arg, &lrng_trust_bootloader); -+} -+early_param("random.trust_bootloader", lrng_parse_trust_bootloader); -+ -+void __init random_init_early(const char *command_line) -+{ -+ lrng_rand_initialize_early(); -+ lrng_pool_insert_aux(command_line, strlen(command_line), 0); -+} -+ -+void __init random_init(void) -+{ -+ lrng_rand_initialize(); -+} -+ -+/* -+ * Add a callback function that will be invoked when the LRNG is initialised, -+ * or immediately if it already has been. Only use this is you are absolutely -+ * sure it is required. Most users should instead be able to test -+ * `rng_is_initialized()` on demand, or make use of `get_random_bytes_wait()`. -+ */ -+int __cold execute_with_initialized_rng(struct notifier_block *nb) -+{ -+ unsigned long flags; -+ int ret = 0; -+ -+ spin_lock_irqsave(&random_ready_notifier.lock, flags); -+ if (rng_is_initialized()) -+ nb->notifier_call(nb, 0, NULL); -+ else -+ ret = raw_notifier_chain_register( -+ (struct raw_notifier_head *)&random_ready_notifier.head, -+ nb); -+ spin_unlock_irqrestore(&random_ready_notifier.lock, flags); -+ return ret; -+} -+ -+void lrng_kick_random_ready(void) -+{ -+ atomic_notifier_call_chain(&random_ready_notifier, 0, NULL); -+} -+ -+/************************ LRNG kernel input interfaces ************************/ -+ -+/* -+ * add_hwgenerator_randomness() - Interface for in-kernel drivers of true -+ * hardware RNGs. -+ * -+ * Those devices may produce endless random bits and will be throttled -+ * when our pool is full. -+ * -+ * @buffer: buffer holding the entropic data from HW noise sources to be used to -+ * insert into entropy pool. -+ * @count: length of buffer -+ * @entropy_bits: amount of entropy in buffer (value is in bits) -+ */ -+void add_hwgenerator_randomness(const void *buffer, size_t count, -+ size_t entropy_bits, bool sleep_after) -+{ -+ /* -+ * Suspend writing if we are fully loaded with entropy or if caller -+ * did not provide any entropy. We'll be woken up again once below -+ * lrng_write_wakeup_thresh, or when the calling thread is about to -+ * terminate. -+ */ -+ wait_event_interruptible(lrng_write_wait, -+ (lrng_need_entropy() && entropy_bits) || -+ lrng_state_exseed_allow(lrng_noise_source_hw) || -+ !sleep_after || -+ kthread_should_stop()); -+ lrng_state_exseed_set(lrng_noise_source_hw, false); -+ lrng_pool_insert_aux(buffer, count, entropy_bits); -+} -+EXPORT_SYMBOL_GPL(add_hwgenerator_randomness); -+ -+/* -+ * add_bootloader_randomness() - Handle random seed passed by bootloader. -+ * -+ * If the seed is trustworthy, it would be regarded as hardware RNGs. Otherwise -+ * it would be regarded as device data. -+ * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER. -+ * -+ * @buf: buffer holding the entropic data from HW noise sources to be used to -+ * insert into entropy pool. -+ * @size: length of buffer -+ */ -+void __init add_bootloader_randomness(const void *buf, size_t size) -+{ -+ lrng_pool_insert_aux(buf, size, lrng_trust_bootloader ? size * 8 : 0); -+} -+ -+/* -+ * Callback for HID layer -- use the HID event values to stir the entropy pool -+ */ -+void add_input_randomness(unsigned int type, unsigned int code, -+ unsigned int value) -+{ -+ static unsigned char last_value; -+ -+ /* ignore autorepeat and the like */ -+ if (value == last_value) -+ return; -+ -+ last_value = value; -+ -+ lrng_irq_array_add_u32((type << 4) ^ code ^ (code >> 4) ^ value); -+} -+EXPORT_SYMBOL_GPL(add_input_randomness); -+ -+/* -+ * add_device_randomness() - Add device- or boot-specific data to the entropy -+ * pool to help initialize it. -+ * -+ * None of this adds any entropy; it is meant to avoid the problem of -+ * the entropy pool having similar initial state across largely -+ * identical devices. -+ * -+ * @buf: buffer holding the entropic data from HW noise sources to be used to -+ * insert into entropy pool. -+ * @size: length of buffer -+ */ -+void add_device_randomness(const void *buf, size_t size) -+{ -+ lrng_pool_insert_aux((u8 *)buf, size, 0); -+} -+EXPORT_SYMBOL(add_device_randomness); -+ -+#ifdef CONFIG_BLOCK -+void rand_initialize_disk(struct gendisk *disk) { } -+void add_disk_randomness(struct gendisk *disk) { } -+EXPORT_SYMBOL(add_disk_randomness); -+#endif -+ -+#ifndef CONFIG_LRNG_IRQ -+void add_interrupt_randomness(int irq) { } -+EXPORT_SYMBOL(add_interrupt_randomness); -+#endif -+ -+#if IS_ENABLED(CONFIG_VMGENID) -+static BLOCKING_NOTIFIER_HEAD(lrng_vmfork_chain); -+ -+/* -+ * Handle a new unique VM ID, which is unique, not secret, so we -+ * don't credit it, but we do immediately force a reseed after so -+ * that it's used by the crng posthaste. -+ */ -+void add_vmfork_randomness(const void *unique_vm_id, size_t size) -+{ -+ add_device_randomness(unique_vm_id, size); -+ if (lrng_state_operational()) -+ lrng_drng_force_reseed(); -+ blocking_notifier_call_chain(&lrng_vmfork_chain, 0, NULL); -+} -+#if IS_MODULE(CONFIG_VMGENID) -+EXPORT_SYMBOL_GPL(add_vmfork_randomness); -+#endif -+ -+int register_random_vmfork_notifier(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_register(&lrng_vmfork_chain, nb); -+} -+EXPORT_SYMBOL_GPL(register_random_vmfork_notifier); -+ -+int unregister_random_vmfork_notifier(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_unregister(&lrng_vmfork_chain, nb); -+} -+EXPORT_SYMBOL_GPL(unregister_random_vmfork_notifier); -+#endif -+ -+/*********************** LRNG kernel output interfaces ************************/ -+ -+/* -+ * get_random_bytes() - Provider of cryptographic strong random numbers for -+ * kernel-internal usage. -+ * -+ * This function is appropriate for all in-kernel use cases. However, -+ * it will always use the ChaCha20 DRNG. -+ * -+ * @buf: buffer to store the random bytes -+ * @nbytes: size of the buffer -+ */ -+void get_random_bytes(void *buf, size_t nbytes) -+{ -+ lrng_get_random_bytes(buf, nbytes); -+} -+EXPORT_SYMBOL(get_random_bytes); -+ -+/* -+ * wait_for_random_bytes() - Wait for the LRNG to be seeded and thus -+ * guaranteed to supply cryptographically secure random numbers. -+ * -+ * This applies to: the /dev/urandom device, the get_random_bytes function, -+ * and the get_random_{u32,u64,int,long} family of functions. Using any of -+ * these functions without first calling this function forfeits the guarantee -+ * of security. -+ * -+ * Return: -+ * * 0 if the LRNG has been seeded. -+ * * -ERESTARTSYS if the function was interrupted by a signal. -+ */ -+int wait_for_random_bytes(void) -+{ -+ return lrng_drng_sleep_while_non_min_seeded(); -+} -+EXPORT_SYMBOL(wait_for_random_bytes); -+ -+/* -+ * Returns whether or not the LRNG has been seeded. -+ * -+ * Returns: true if the urandom pool has been seeded. -+ * false if the urandom pool has not been seeded. -+ */ -+bool rng_is_initialized(void) -+{ -+ return lrng_state_operational(); -+} -+EXPORT_SYMBOL(rng_is_initialized); ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_random_user.c -@@ -0,0 +1,104 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG Common user space interfaces compliant to random(4), random(7) and -+ * getrandom(2) man pages. -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+ -+#include "lrng_es_mgr.h" -+#include "lrng_interface_dev_common.h" -+ -+static ssize_t lrng_drng_read(struct file *file, char __user *buf, -+ size_t nbytes, loff_t *ppos) -+{ -+ if (!lrng_state_min_seeded()) -+ pr_notice_ratelimited("%s - use of insufficiently seeded DRNG (%zu bytes read)\n", -+ current->comm, nbytes); -+ else if (!lrng_state_operational()) -+ pr_debug_ratelimited("%s - use of not fully seeded DRNG (%zu bytes read)\n", -+ current->comm, nbytes); -+ -+ return lrng_read_common(buf, nbytes, false); -+} -+ -+const struct file_operations random_fops = { -+ .read = lrng_drng_read_block, -+ .write = lrng_drng_write, -+ .poll = lrng_random_poll, -+ .unlocked_ioctl = lrng_ioctl, -+ .compat_ioctl = compat_ptr_ioctl, -+ .fasync = lrng_fasync, -+ .llseek = noop_llseek, -+}; -+ -+const struct file_operations urandom_fops = { -+ .read = lrng_drng_read, -+ .write = lrng_drng_write, -+ .unlocked_ioctl = lrng_ioctl, -+ .compat_ioctl = compat_ptr_ioctl, -+ .fasync = lrng_fasync, -+ .llseek = noop_llseek, -+}; -+ -+/* -+ * GRND_SEED -+ * -+ * This flag requests to provide the data directly from the entropy sources. -+ * -+ * The behavior of the call is exactly as outlined for the function -+ * lrng_get_seed in lrng.h. -+ */ -+#define GRND_SEED 0x0010 -+ -+/* -+ * GRND_FULLY_SEEDED -+ * -+ * This flag indicates whether the caller wants to reseed a DRNG that is already -+ * fully seeded. See esdm_get_seed in lrng.h for details. -+ */ -+#define GRND_FULLY_SEEDED 0x0020 -+ -+SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, -+ unsigned int, flags) -+{ -+ if (flags & ~(GRND_NONBLOCK|GRND_RANDOM|GRND_INSECURE| -+ GRND_SEED|GRND_FULLY_SEEDED)) -+ return -EINVAL; -+ -+ /* -+ * Requesting insecure and blocking randomness at the same time makes -+ * no sense. -+ */ -+ if ((flags & -+ (GRND_INSECURE|GRND_RANDOM)) == (GRND_INSECURE|GRND_RANDOM)) -+ return -EINVAL; -+ if ((flags & -+ (GRND_INSECURE|GRND_SEED)) == (GRND_INSECURE|GRND_SEED)) -+ return -EINVAL; -+ if ((flags & -+ (GRND_RANDOM|GRND_SEED)) == (GRND_RANDOM|GRND_SEED)) -+ return -EINVAL; -+ -+ if (count > INT_MAX) -+ count = INT_MAX; -+ -+ if (flags & GRND_INSECURE) { -+ return lrng_drng_read(NULL, buf, count, NULL); -+ } else if (flags & GRND_SEED) { -+ unsigned int seed_flags = (flags & GRND_NONBLOCK) ? -+ LRNG_GET_SEED_NONBLOCK : 0; -+ -+ seed_flags |= (flags & GRND_FULLY_SEEDED) ? -+ LRNG_GET_SEED_FULLY_SEEDED : 0; -+ return lrng_read_seed(buf, count, seed_flags); -+ } -+ -+ return lrng_read_common_block(flags & GRND_NONBLOCK, -+ flags & GRND_RANDOM, buf, count); -+} diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch deleted file mode 100644 index b57607e0c..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch +++ /dev/null @@ -1,199 +0,0 @@ -From e326fcaf1ca28e9c777efcb04f61595eda3a5f96 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 9 Oct 2022 10:22:39 +0200 -Subject: [PATCH 23/25] LRNG - add kernel crypto API interface - -The LRNG can be registered with the kernel crypto API's random number -generator framework. This offers a random number generator with the name -"lrng" and a priority that is intended to be higher than the existing -RNG implementations. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 26 ++--- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_interface_kcapi.c | 129 +++++++++++++++++++++++ - 3 files changed, 143 insertions(+), 13 deletions(-) - create mode 100644 drivers/char/lrng/lrng_interface_kcapi.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -89,18 +89,18 @@ config LRNG_AIS2031_NTG1_SEEDING_STRATEG - - endmenu # "Specific DRNG seeding strategies" - --# menu "LRNG Interfaces" --# --# config LRNG_KCAPI_IF --# tristate "Interface with Kernel Crypto API" --# depends on CRYPTO_RNG --# help --# The LRNG can be registered with the kernel crypto API's --# random number generator framework. This offers a random --# number generator with the name "lrng" and a priority that --# is intended to be higher than the existing RNG --# implementations. --# -+menu "LRNG Interfaces" -+ -+config LRNG_KCAPI_IF -+ tristate "Interface with Kernel Crypto API" -+ depends on CRYPTO_RNG -+ help -+ The LRNG can be registered with the kernel crypto API's -+ random number generator framework. This offers a random -+ number generator with the name "lrng" and a priority that -+ is intended to be higher than the existing RNG -+ implementations. -+ - # config LRNG_HWRAND_IF - # tristate "Interface with Hardware Random Number Generator Framework" - # depends on HW_RANDOM -@@ -120,7 +120,7 @@ endmenu # "Specific DRNG seeding strateg - # identically to /dev/random including IOCTL, read and write - # operations. - # --# endmenu # "LRNG Interfaces" -+endmenu # "LRNG Interfaces" - - menu "Entropy Source Configuration" - ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -34,3 +34,4 @@ obj-$(CONFIG_LRNG_COMMON_DEV_IF) += lrng - obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_interface_random_user.o \ - lrng_interface_random_kernel.o \ - lrng_interface_aux.o -+obj-$(CONFIG_LRNG_KCAPI_IF) += lrng_interface_kcapi.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_kcapi.c -@@ -0,0 +1,129 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG interface with the RNG framework of the kernel crypto API -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#include -+#include -+#include -+ -+#include "lrng_drng_mgr.h" -+#include "lrng_es_aux.h" -+ -+static int lrng_kcapi_if_init(struct crypto_tfm *tfm) -+{ -+ return 0; -+} -+ -+static void lrng_kcapi_if_cleanup(struct crypto_tfm *tfm) { } -+ -+static int lrng_kcapi_if_reseed(const u8 *src, unsigned int slen) -+{ -+ int ret; -+ -+ if (!slen) -+ return 0; -+ -+ /* Insert caller-provided data without crediting entropy */ -+ ret = lrng_pool_insert_aux((u8 *)src, slen, 0); -+ if (ret) -+ return ret; -+ -+ /* Make sure the new data is immediately available to DRNG */ -+ lrng_drng_force_reseed(); -+ -+ return 0; -+} -+ -+static int lrng_kcapi_if_random(struct crypto_rng *tfm, -+ const u8 *src, unsigned int slen, -+ u8 *rdata, unsigned int dlen) -+{ -+ int ret = lrng_kcapi_if_reseed(src, slen); -+ -+ if (!ret) -+ lrng_get_random_bytes_full(rdata, dlen); -+ -+ return ret; -+} -+ -+static int lrng_kcapi_if_reset(struct crypto_rng *tfm, -+ const u8 *seed, unsigned int slen) -+{ -+ return lrng_kcapi_if_reseed(seed, slen); -+} -+ -+static struct rng_alg lrng_alg = { -+ .generate = lrng_kcapi_if_random, -+ .seed = lrng_kcapi_if_reset, -+ .seedsize = 0, -+ .base = { -+ .cra_name = "stdrng", -+ .cra_driver_name = "lrng", -+ .cra_priority = 500, -+ .cra_ctxsize = 0, -+ .cra_module = THIS_MODULE, -+ .cra_init = lrng_kcapi_if_init, -+ .cra_exit = lrng_kcapi_if_cleanup, -+ -+ } -+}; -+ -+#ifdef CONFIG_LRNG_DRNG_ATOMIC -+static int lrng_kcapi_if_random_atomic(struct crypto_rng *tfm, -+ const u8 *src, unsigned int slen, -+ u8 *rdata, unsigned int dlen) -+{ -+ int ret = lrng_kcapi_if_reseed(src, slen); -+ -+ if (!ret) -+ lrng_get_random_bytes(rdata, dlen); -+ -+ return ret; -+} -+ -+static struct rng_alg lrng_alg_atomic = { -+ .generate = lrng_kcapi_if_random_atomic, -+ .seed = lrng_kcapi_if_reset, -+ .seedsize = 0, -+ .base = { -+ .cra_name = "lrng_atomic", -+ .cra_driver_name = "lrng_atomic", -+ .cra_priority = 100, -+ .cra_ctxsize = 0, -+ .cra_module = THIS_MODULE, -+ .cra_init = lrng_kcapi_if_init, -+ .cra_exit = lrng_kcapi_if_cleanup, -+ -+ } -+}; -+#endif /* CONFIG_LRNG_DRNG_ATOMIC */ -+ -+static int __init lrng_kcapi_if_mod_init(void) -+{ -+ return -+#ifdef CONFIG_LRNG_DRNG_ATOMIC -+ crypto_register_rng(&lrng_alg_atomic) ?: -+#endif -+ crypto_register_rng(&lrng_alg); -+} -+ -+static void __exit lrng_kcapi_if_mod_exit(void) -+{ -+ crypto_unregister_rng(&lrng_alg); -+#ifdef CONFIG_LRNG_DRNG_ATOMIC -+ crypto_unregister_rng(&lrng_alg_atomic); -+#endif -+} -+ -+module_init(lrng_kcapi_if_mod_init); -+module_exit(lrng_kcapi_if_mod_exit); -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Stephan Mueller "); -+MODULE_DESCRIPTION("Entropy Source and DRNG Manager kernel crypto API RNG framework interface"); -+MODULE_ALIAS_CRYPTO("lrng"); -+MODULE_ALIAS_CRYPTO("lrng_atomic"); -+MODULE_ALIAS_CRYPTO("stdrng"); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch deleted file mode 100644 index 7e5a14f78..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch +++ /dev/null @@ -1,88 +0,0 @@ -From f56927ba73ece44bf5eafb73e7325af1b555e149 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 18:39:30 +0200 -Subject: [PATCH 24/25] LRNG - add /dev/lrng device file support - -The LRNG can create a character device file that operates identically -to /dev/random including IOCTL, read and write operations. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 18 ++++++------- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_interface_dev.c | 35 ++++++++++++++++++++++++++ - 3 files changed, 45 insertions(+), 9 deletions(-) - create mode 100644 drivers/char/lrng/lrng_interface_dev.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -111,15 +111,15 @@ config LRNG_KCAPI_IF - # with the name "lrng" that is accessible via the framework. - # For example it allows pulling data from the LRNG via the - # /dev/hwrng file. --# --# config LRNG_DEV_IF --# bool "Character device file interface" --# select LRNG_COMMON_DEV_IF --# help --# The LRNG can create a character device file that operates --# identically to /dev/random including IOCTL, read and write --# operations. --# -+ -+config LRNG_DEV_IF -+ bool "Character device file interface" -+ select LRNG_COMMON_DEV_IF -+ help -+ The LRNG can create a character device file that operates -+ identically to /dev/random including IOCTL, read and write -+ operations. -+ - endmenu # "LRNG Interfaces" - - menu "Entropy Source Configuration" ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -35,3 +35,4 @@ obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_in - lrng_interface_random_kernel.o \ - lrng_interface_aux.o - obj-$(CONFIG_LRNG_KCAPI_IF) += lrng_interface_kcapi.o -+obj-$(CONFIG_LRNG_DEV_IF) += lrng_interface_dev.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_dev.c -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG user space device file interface -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#include -+#include -+ -+#include "lrng_interface_dev_common.h" -+ -+static const struct file_operations lrng_fops = { -+ .read = lrng_drng_read_block, -+ .write = lrng_drng_write, -+ .poll = lrng_random_poll, -+ .unlocked_ioctl = lrng_ioctl, -+ .compat_ioctl = compat_ptr_ioctl, -+ .fasync = lrng_fasync, -+ .llseek = noop_llseek, -+}; -+ -+static struct miscdevice lrng_miscdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "lrng", -+ .nodename = "lrng", -+ .fops = &lrng_fops, -+ .mode = 0666 -+}; -+ -+static int __init lrng_dev_if_mod_init(void) -+{ -+ return misc_register(&lrng_miscdev); -+} -+device_initcall(lrng_dev_if_mod_init); diff --git a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch b/openwrt/patch/kernel-6.6/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch deleted file mode 100644 index b0f89eafe..000000000 --- a/openwrt/patch/kernel-6.6/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch +++ /dev/null @@ -1,125 +0,0 @@ -From d64121ae8e90283c8bdd3525a5e7613a635c8b98 Mon Sep 17 00:00:00 2001 -From: Stephan Mueller -Date: Sun, 15 May 2022 18:43:30 +0200 -Subject: [PATCH 25/25] LRNG - add hwrand framework interface - -The LRNG can be registered with the hardware random number generator -framework. This offers a random number generator with the name "lrng" -that is accessible via the framework. For example it allows pulling -data from the LRNG via the /dev/hwrng file. - -Signed-off-by: Stephan Mueller ---- - drivers/char/lrng/Kconfig | 20 +++---- - drivers/char/lrng/Makefile | 1 + - drivers/char/lrng/lrng_interface_hwrand.c | 68 +++++++++++++++++++++++ - 3 files changed, 79 insertions(+), 10 deletions(-) - create mode 100644 drivers/char/lrng/lrng_interface_hwrand.c - ---- a/drivers/char/lrng/Kconfig -+++ b/drivers/char/lrng/Kconfig -@@ -101,16 +101,16 @@ config LRNG_KCAPI_IF - is intended to be higher than the existing RNG - implementations. - --# config LRNG_HWRAND_IF --# tristate "Interface with Hardware Random Number Generator Framework" --# depends on HW_RANDOM --# select LRNG_DRNG_ATOMIC --# help --# The LRNG can be registered with the hardware random number --# generator framework. This offers a random number generator --# with the name "lrng" that is accessible via the framework. --# For example it allows pulling data from the LRNG via the --# /dev/hwrng file. -+config LRNG_HWRAND_IF -+ tristate "Interface with Hardware Random Number Generator Framework" -+ depends on HW_RANDOM -+ select LRNG_DRNG_ATOMIC -+ help -+ The LRNG can be registered with the hardware random number -+ generator framework. This offers a random number generator -+ with the name "lrng" that is accessible via the framework. -+ For example it allows pulling data from the LRNG via the -+ /dev/hwrng file. - - config LRNG_DEV_IF - bool "Character device file interface" ---- a/drivers/char/lrng/Makefile -+++ b/drivers/char/lrng/Makefile -@@ -36,3 +36,4 @@ obj-$(CONFIG_LRNG_RANDOM_IF) += lrng_in - lrng_interface_aux.o - obj-$(CONFIG_LRNG_KCAPI_IF) += lrng_interface_kcapi.o - obj-$(CONFIG_LRNG_DEV_IF) += lrng_interface_dev.o -+obj-$(CONFIG_LRNG_HWRAND_IF) += lrng_interface_hwrand.o ---- /dev/null -+++ b/drivers/char/lrng/lrng_interface_hwrand.c -@@ -0,0 +1,68 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+/* -+ * LRNG interface with the HW-Random framework -+ * -+ * Copyright (C) 2022, Stephan Mueller -+ */ -+ -+#include -+#include -+#include -+ -+static int lrng_hwrand_if_random(struct hwrng *rng, void *buf, size_t max, -+ bool wait) -+{ -+ /* -+ * lrng_get_random_bytes_full not called as we cannot block. -+ * -+ * Note: We should either adjust .quality below depending on -+ * rng_is_initialized() or block here, but neither is not supported by -+ * the hw_rand framework. -+ */ -+ lrng_get_random_bytes(buf, max); -+ return (int)max; -+} -+ -+static struct hwrng lrng_hwrand = { -+ .name = "lrng", -+ .init = NULL, -+ .cleanup = NULL, -+ .read = lrng_hwrand_if_random, -+ -+ /* -+ * We set .quality only in case the LRNG does not provide the common -+ * interfaces or does not use the legacy RNG as entropy source. This -+ * shall avoid that the LRNG automatically spawns the hw_rand -+ * framework's hwrng kernel thread to feed data into -+ * add_hwgenerator_randomness. When the LRNG implements the common -+ * interfaces, this function feeds the data directly into the LRNG. -+ * If the LRNG uses the legacy RNG as entropy source, -+ * add_hwgenerator_randomness is implemented by the legacy RNG, but -+ * still eventually feeds the data into the LRNG. We should avoid such -+ * circular loops. -+ * -+ * We can specify full entropy here, because the LRNG is designed -+ * to provide full entropy. -+ */ -+#if !defined(CONFIG_LRNG_RANDOM_IF) && \ -+ !defined(CONFIG_LRNG_KERNEL_RNG) -+ .quality = 1024, -+#endif -+}; -+ -+static int __init lrng_hwrand_if_mod_init(void) -+{ -+ return hwrng_register(&lrng_hwrand); -+} -+ -+static void __exit lrng_hwrand_if_mod_exit(void) -+{ -+ hwrng_unregister(&lrng_hwrand); -+} -+ -+module_init(lrng_hwrand_if_mod_init); -+module_exit(lrng_hwrand_if_mod_exit); -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Stephan Mueller "); -+MODULE_DESCRIPTION("Entropy Source and DRNG Manager HW-Random Interface"); diff --git a/openwrt/patch/kernel-6.6/net/601-netfilter-export-udp_get_timeouts-function.patch b/openwrt/patch/kernel-6.6/net/601-netfilter-export-udp_get_timeouts-function.patch deleted file mode 100644 index d741cb7c3..000000000 --- a/openwrt/patch/kernel-6.6/net/601-netfilter-export-udp_get_timeouts-function.patch +++ /dev/null @@ -1,38 +0,0 @@ -From e38488fd0a8a11b4bae4ccad9a7a8cfcf9eb5ab7 Mon Sep 17 00:00:00 2001 -From: Murat Sezgin -Date: Mon, 6 Apr 2020 11:08:09 -0700 -Subject: [PATCH] netfilter: export udp_get_timeouts function - -This function is required for acceleration support. - -Signed-off-by: Murat Sezgin -Change-Id: Ibca4f402735764e7e6fb3ce2678e670753c6ef9c ---- - include/net/netfilter/nf_conntrack_timeout.h | 1 + - net/netfilter/nf_conntrack_proto_udp.c | 3 ++- - 2 files changed, 3 insertions(+), 1 deletion(-) - ---- a/include/net/netfilter/nf_conntrack_timeout.h -+++ b/include/net/netfilter/nf_conntrack_timeout.h -@@ -107,5 +107,6 @@ struct nf_ct_timeout_hooks { - - extern const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook; - #endif -+extern unsigned int *udp_get_timeouts(struct net *net); - - #endif /* _NF_CONNTRACK_TIMEOUT_H */ ---- a/net/netfilter/nf_conntrack_proto_udp.c -+++ b/net/netfilter/nf_conntrack_proto_udp.c -@@ -29,10 +29,11 @@ static const unsigned int udp_timeouts[U - [UDP_CT_REPLIED] = 120*HZ, - }; - --static unsigned int *udp_get_timeouts(struct net *net) -+unsigned int *udp_get_timeouts(struct net *net) - { - return nf_udp_pernet(net)->timeouts; - } -+EXPORT_SYMBOL(udp_get_timeouts); - - static void udp_error_log(const struct sk_buff *skb, - const struct nf_hook_state *state, diff --git a/openwrt/patch/kernel-6.6/net/952-net-conntrack-events-support-multiple-registrant.patch b/openwrt/patch/kernel-6.6/net/952-net-conntrack-events-support-multiple-registrant.patch deleted file mode 100644 index 848102bd1..000000000 --- a/openwrt/patch/kernel-6.6/net/952-net-conntrack-events-support-multiple-registrant.patch +++ /dev/null @@ -1,352 +0,0 @@ -From 986b513b5cc049e9a5f10c35b76f037dde8b8c3e Mon Sep 17 00:00:00 2001 -From: Zhi Chen -Date: Tue, 13 Jan 2015 14:28:18 -0800 -Subject: [PATCH 1/2] net: conntrack events, support multiple registrant - -Merging this patch from kernel 3.4: -This was supported by old (.28) kernel versions but removed -because of it's overhead. -But we need this feature for NA connection manager. Both ipv4 -and ipv6 modules needs to register themselves to ct events. - -Change-Id: Iebfb254590fb594f5baf232f849d1b7ae45ef757 -Signed-off-by: Zhi Chen ---- - include/net/netfilter/nf_conntrack_ecache.h | 33 +++++-- - include/net/netns/conntrack.h | 3 + - net/netfilter/Kconfig | 8 ++ - net/netfilter/nf_conntrack_core.c | 4 + - net/netfilter/nf_conntrack_ecache.c | 103 +++++++++++++++++++- - net/netfilter/nf_conntrack_netlink.c | 17 ++++ - 6 files changed, 160 insertions(+), 8 deletions(-) - ---- a/include/net/netfilter/nf_conntrack_ecache.h -+++ b/include/net/netfilter/nf_conntrack_ecache.h -@@ -65,9 +65,14 @@ struct nf_ct_event_notifier { - int (*exp_event)(unsigned int events, const struct nf_exp_event *item); - }; - --void nf_conntrack_register_notifier(struct net *net, -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+extern int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb); -+extern int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb); -+#else -+int nf_conntrack_register_notifier(struct net *net, - const struct nf_ct_event_notifier *nb); - void nf_conntrack_unregister_notifier(struct net *net); -+#endif - - void nf_ct_deliver_cached_events(struct nf_conn *ct); - int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, -@@ -98,11 +103,13 @@ static inline void - nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) - { - #ifdef CONFIG_NF_CONNTRACK_EVENTS -- struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *e; -+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ struct net *net = nf_ct_net(ct); - - if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) - return; -+#endif - - e = nf_ct_ecache_find(ct); - if (e == NULL) -@@ -117,20 +124,34 @@ nf_conntrack_event_report(enum ip_conntr - u32 portid, int report) - { - #ifdef CONFIG_NF_CONNTRACK_EVENTS -- if (nf_ct_ecache_exist(ct)) -- return nf_conntrack_eventmask_report(1 << event, ct, portid, report); -+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ const struct net *net = nf_ct_net(ct); -+ -+ if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) -+ return 0; - #endif -+ -+ return nf_conntrack_eventmask_report(1 << event, ct, portid, report); -+#else - return 0; -+#endif - } - - static inline int - nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) - { - #ifdef CONFIG_NF_CONNTRACK_EVENTS -- if (nf_ct_ecache_exist(ct)) -- return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); -+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ const struct net *net = nf_ct_net(ct); -+ -+ if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) -+ return 0; - #endif -+ -+ return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); -+#else - return 0; -+#endif - } - - #ifdef CONFIG_NF_CONNTRACK_EVENTS ---- a/include/net/netns/conntrack.h -+++ b/include/net/netns/conntrack.h -@@ -104,6 +104,9 @@ struct netns_ct { - u8 sysctl_checksum; - - struct ip_conntrack_stat __percpu *stat; -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ struct atomic_notifier_head nf_conntrack_chain; -+#endif - struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb; - struct nf_ip_net nf_ct_proto; - #if defined(CONFIG_NF_CONNTRACK_LABELS) ---- a/net/netfilter/Kconfig -+++ b/net/netfilter/Kconfig -@@ -164,6 +164,14 @@ config NF_CONNTRACK_EVENTS - - If unsure, say `N'. - -+config NF_CONNTRACK_CHAIN_EVENTS -+ bool "Register multiple callbacks to ct events" -+ depends on NF_CONNTRACK_EVENTS -+ help -+ Support multiple registrations. -+ -+ If unsure, say `N'. -+ - config NF_CONNTRACK_TIMEOUT - bool 'Connection tracking timeout' - depends on NETFILTER_ADVANCED ---- a/net/netfilter/nf_conntrack_core.c -+++ b/net/netfilter/nf_conntrack_core.c -@@ -2801,6 +2801,10 @@ int nf_conntrack_init_net(struct net *ne - nf_conntrack_ecache_pernet_init(net); - nf_conntrack_proto_pernet_init(net); - -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ ATOMIC_INIT_NOTIFIER_HEAD(&net->ct.nf_conntrack_chain); -+#endif -+ - return 0; - - err_expect: ---- a/net/netfilter/nf_conntrack_ecache.c -+++ b/net/netfilter/nf_conntrack_ecache.c -@@ -17,6 +17,9 @@ - #include - #include - #include -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+#include -+#endif - #include - #include - #include -@@ -162,6 +165,35 @@ static int __nf_conntrack_eventmask_repo - return ret; - } - -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, -+ u32 portid, int report) -+{ -+ struct nf_conntrack_ecache *e; -+ struct net *net = nf_ct_net(ct); -+ -+ e = nf_ct_ecache_find(ct); -+ if (e == NULL) -+ return 0; -+ -+ if (nf_ct_is_confirmed(ct)) { -+ struct nf_ct_event item = { -+ .ct = ct, -+ .portid = e->portid ? e->portid : portid, -+ .report = report -+ }; -+ /* This is a resent of a destroy event? If so, skip missed */ -+ unsigned long missed = e->portid ? 0 : e->missed; -+ -+ if (!((eventmask | missed) & e->ctmask)) -+ return 0; -+ -+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, eventmask | missed, &item); -+ } -+ -+ return 0; -+} -+#else - int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct, - u32 portid, int report) - { -@@ -197,10 +229,52 @@ int nf_conntrack_eventmask_report(unsign - - return ret; - } -+#endif - EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report); - - /* deliver cached events and clear cache entry - must be called with locally - * disabled softirqs */ -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+void nf_ct_deliver_cached_events(struct nf_conn *ct) -+{ -+ unsigned long events, missed; -+ struct nf_conntrack_ecache *e; -+ struct nf_ct_event item; -+ struct net *net = nf_ct_net(ct); -+ -+ e = nf_ct_ecache_find(ct); -+ if (e == NULL) -+ return; -+ -+ events = xchg(&e->cache, 0); -+ -+ if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events) -+ return; -+ -+ /* We make a copy of the missed event cache without taking -+ * the lock, thus we may send missed events twice. However, -+ * this does not harm and it happens very rarely. */ -+ missed = e->missed; -+ -+ if (!((events | missed) & e->ctmask)) -+ return; -+ -+ item.ct = ct; -+ item.portid = 0; -+ item.report = 0; -+ -+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, -+ events | missed, -+ &item); -+ -+ if (likely(!missed)) -+ return; -+ -+ spin_lock_bh(&ct->lock); -+ e->missed &= ~missed; -+ spin_unlock_bh(&ct->lock); -+} -+#else - void nf_ct_deliver_cached_events(struct nf_conn *ct) - { - struct nf_conntrack_ecache *e; -@@ -226,6 +300,7 @@ void nf_ct_deliver_cached_events(struct - */ - __nf_conntrack_eventmask_report(e, events, e->missed, &item); - } -+#endif - EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); - - void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, -@@ -258,20 +333,43 @@ out_unlock: - rcu_read_unlock(); - } - --void nf_conntrack_register_notifier(struct net *net, -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+int nf_conntrack_register_notifier(struct net *net, -+ struct notifier_block *nb) -+{ -+ return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); -+} -+#else -+int nf_conntrack_register_notifier(struct net *net, - const struct nf_ct_event_notifier *new) - { -+ int ret; - struct nf_ct_event_notifier *notify; - - mutex_lock(&nf_ct_ecache_mutex); - notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb, - lockdep_is_held(&nf_ct_ecache_mutex)); - WARN_ON_ONCE(notify); -+ if (notify != NULL) { -+ ret = -EBUSY; -+ goto out_unlock; -+ } -+ - rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new); -- mutex_unlock(&nf_ct_ecache_mutex); -+ ret = 0; -+out_unlock: -+ mutex_unlock(&nf_ct_ecache_mutex); -+ return ret; - } -+#endif - EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier); - -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb) -+{ -+ return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); -+} -+#else - void nf_conntrack_unregister_notifier(struct net *net) - { - mutex_lock(&nf_ct_ecache_mutex); -@@ -279,6 +377,7 @@ void nf_conntrack_unregister_notifier(st - mutex_unlock(&nf_ct_ecache_mutex); - /* synchronize_rcu() is called after netns pre_exit */ - } -+#endif - EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); - - void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state) ---- a/net/netfilter/nf_conntrack_netlink.c -+++ b/net/netfilter/nf_conntrack_netlink.c -@@ -723,12 +723,19 @@ static size_t ctnetlink_nlmsg_size(const - } - - static int -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ctnetlink_conntrack_event(struct notifier_block *this, unsigned long events, void *ptr) -+#else - ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item) -+#endif - { - const struct nf_conntrack_zone *zone; - struct net *net; - struct nlmsghdr *nlh; - struct nlattr *nest_parms; -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ struct nf_ct_event *item = (struct nf_ct_event *)ptr; -+#endif - struct nf_conn *ct = item->ct; - struct sk_buff *skb; - unsigned int type; -@@ -3751,11 +3758,17 @@ static int ctnetlink_stat_exp_cpu(struct - } - - #ifdef CONFIG_NF_CONNTRACK_EVENTS -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+static struct notifier_block ctnl_notifier = { -+ .notifier_call = ctnetlink_conntrack_event -+}; -+#else - static struct nf_ct_event_notifier ctnl_notifier = { - .ct_event = ctnetlink_conntrack_event, - .exp_event = ctnetlink_expect_event, - }; - #endif -+#endif - - static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { - [IPCTNL_MSG_CT_NEW] = { -@@ -3854,8 +3867,12 @@ static int __net_init ctnetlink_net_init - static void ctnetlink_net_pre_exit(struct net *net) - { - #ifdef CONFIG_NF_CONNTRACK_EVENTS -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ nf_conntrack_unregister_notifier(net,&ctnl_notifier); -+#else - nf_conntrack_unregister_notifier(net); - #endif -+#endif - } - - static struct pernet_operations ctnetlink_net_ops = { diff --git a/openwrt/patch/kernel-6.6/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.6/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch deleted file mode 100644 index c6d7c36ce..000000000 --- a/openwrt/patch/kernel-6.6/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ /dev/null @@ -1,219 +0,0 @@ -From 737595f75328d06ba4f1fb12dd39c233b9919259 Mon Sep 17 00:00:00 2001 -From: Xiaoping Fan -Date: Fri, 26 Feb 2016 15:01:53 -0800 -Subject: [PATCH 2/2] net: patch linux kernel to support shortcut-fe - -Change-Id: Icaa7c172a06df1c3bc89ff89814d1136772fe217 -Signed-off-by: Xiaoping Fan ---- - include/linux/if_bridge.h | 3 +++ - include/linux/skbuff.h | 4 +++ - include/linux/timer.h | 4 +++ - include/net/netfilter/nf_conntrack_ecache.h | 2 ++ - net/Kconfig | 3 +++ - net/bridge/br_if.c | 20 +++++++++++++++ - net/core/dev.c | 27 +++++++++++++++++++++ - net/netfilter/nf_conntrack_ecache.c | 24 +++++++++++++++++- - 8 files changed, 86 insertions(+), 1 deletion(-) - ---- a/include/linux/if_bridge.h -+++ b/include/linux/if_bridge.h -@@ -72,6 +72,9 @@ void brioctl_set(int (*hook)(struct net - int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, - struct ifreq *ifr, void __user *uarg); - -+extern void br_dev_update_stats(struct net_device *dev, -+ struct rtnl_link_stats64 *nlstats); -+ - #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) - int br_multicast_list_adjacent(struct net_device *dev, - struct list_head *br_ip_list); ---- a/include/linux/skbuff.h -+++ b/include/linux/skbuff.h -@@ -985,6 +985,10 @@ struct sk_buff { - __u8 csum_not_inet:1; - #endif - -+#ifdef CONFIG_SHORTCUT_FE -+ __u8 fast_forwarded:1; -+#endif -+ - #if defined(CONFIG_NET_SCHED) || defined(CONFIG_NET_XGRESS) - __u16 tc_index; /* traffic control index */ - #endif ---- a/include/linux/timer.h -+++ b/include/linux/timer.h -@@ -18,6 +18,10 @@ struct timer_list { - void (*function)(struct timer_list *); - u32 flags; - -+#ifdef CONFIG_SHORTCUT_FE -+ unsigned long cust_data; -+#endif -+ - #ifdef CONFIG_LOCKDEP - struct lockdep_map lockdep_map; - #endif ---- a/include/net/netfilter/nf_conntrack_ecache.h -+++ b/include/net/netfilter/nf_conntrack_ecache.h -@@ -68,6 +68,8 @@ struct nf_ct_event_notifier { - #ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS - extern int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb); - extern int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb); -+extern int nf_conntrack_register_chain_notifier(struct net *net, struct notifier_block *nb); -+extern int nf_conntrack_unregister_chain_notifier(struct net *net, struct notifier_block *nb); - #else - int nf_conntrack_register_notifier(struct net *net, - const struct nf_ct_event_notifier *nb); ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -504,6 +504,9 @@ config FAILOVER - migration of VMs with direct attached VFs by failing over to the - paravirtual datapath when the VF is unplugged. - -+config SHORTCUT_FE -+ bool "Enables kernel network stack path for Shortcut Forwarding Engine" -+ - config ETHTOOL_NETLINK - bool "Netlink interface for ethtool" - default y ---- a/net/bridge/br_if.c -+++ b/net/bridge/br_if.c -@@ -764,6 +764,26 @@ void br_port_flags_change(struct net_bri - br_recalculate_neigh_suppress_enabled(br); - } - -+void br_dev_update_stats(struct net_device *dev, -+ struct rtnl_link_stats64 *nlstats) -+{ -+ struct pcpu_sw_netstats *stats; -+ -+ /* Is this a bridge? */ -+ if (!(dev->priv_flags & IFF_EBRIDGE)) -+ return; -+ -+ stats = this_cpu_ptr(dev->tstats); -+ -+ u64_stats_update_begin(&stats->syncp); -+ u64_stats_add(&stats->rx_packets, nlstats->rx_packets); -+ u64_stats_add(&stats->rx_bytes, nlstats->rx_bytes); -+ u64_stats_add(&stats->tx_packets, nlstats->tx_packets); -+ u64_stats_add(&stats->tx_bytes, nlstats->tx_bytes); -+ u64_stats_update_end(&stats->syncp); -+} -+EXPORT_SYMBOL_GPL(br_dev_update_stats); -+ - bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) - { - struct net_bridge_port *p; ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -3594,8 +3594,17 @@ static int xmit_one(struct sk_buff *skb, - unsigned int len; - int rc; - -+#ifdef CONFIG_SHORTCUT_FE -+ /* If this skb has been fast forwarded then we don't want it to -+ * go to any taps (by definition we're trying to bypass them). -+ */ -+ if (!skb->fast_forwarded) { -+#endif - if (dev_nit_active(dev)) - dev_queue_xmit_nit(skb, dev); -+#ifdef CONFIG_SHORTCUT_FE -+ } -+#endif - - #ifdef CONFIG_ETHERNET_PACKET_MANGLE - if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) -@@ -5355,6 +5364,11 @@ void netdev_rx_handler_unregister(struct - } - EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); - -+#ifdef CONFIG_SHORTCUT_FE -+int (*athrs_fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly; -+EXPORT_SYMBOL_GPL(athrs_fast_nat_recv); -+#endif -+ - /* - * Limit the use of PFMEMALLOC reserves to those protocols that implement - * the special handling of PFMEMALLOC skbs. -@@ -5403,6 +5417,10 @@ static int __netif_receive_skb_core(stru - int ret = NET_RX_DROP; - __be16 type; - -+#ifdef CONFIG_SHORTCUT_FE -+ int (*fast_recv)(struct sk_buff *skb); -+#endif -+ - net_timestamp_check(!READ_ONCE(netdev_tstamp_prequeue), skb); - - trace_netif_receive_skb(skb); -@@ -5440,6 +5458,15 @@ another_round: - goto out; - } - -+#ifdef CONFIG_SHORTCUT_FE -+ fast_recv = rcu_dereference(athrs_fast_nat_recv); -+ if (fast_recv) { -+ if (fast_recv(skb)) { -+ ret = NET_RX_SUCCESS; -+ goto out; -+ } -+ } -+#endif - if (skb_skip_tc_classify(skb)) - goto skip_classify; - ---- a/net/netfilter/nf_conntrack_ecache.c -+++ b/net/netfilter/nf_conntrack_ecache.c -@@ -143,12 +143,24 @@ static int __nf_conntrack_eventmask_repo - rcu_read_lock(); - - notify = rcu_dereference(net->ct.nf_conntrack_event_cb); -- if (!notify) { -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ if (!notify && !rcu_dereference_raw(net->ct.nf_conntrack_chain.head)) -+#else -+ if (!notify) -+#endif -+ { - rcu_read_unlock(); - return 0; - } - -+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS -+ ret = atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, -+ events | missed, &item); -+ if (notify) -+ ret = notify->ct_event(events | missed, item); -+#else - ret = notify->ct_event(events | missed, item); -+#endif - rcu_read_unlock(); - - if (likely(ret >= 0 && missed == 0)) -@@ -339,6 +351,11 @@ int nf_conntrack_register_notifier(struc - { - return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); - } -+int nf_conntrack_register_chain_notifier(struct net *net, struct notifier_block *nb) -+{ -+ return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); -+} -+EXPORT_SYMBOL_GPL(nf_conntrack_register_chain_notifier); - #else - int nf_conntrack_register_notifier(struct net *net, - const struct nf_ct_event_notifier *new) -@@ -369,6 +386,11 @@ int nf_conntrack_unregister_notifier(str - { - return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); - } -+int nf_conntrack_unregister_chain_notifier(struct net *net, struct notifier_block *nb) -+{ -+ return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); -+} -+EXPORT_SYMBOL_GPL(nf_conntrack_unregister_chain_notifier); - #else - void nf_conntrack_unregister_notifier(struct net *net) - { diff --git a/openwrt/patch/kernel-6.6/net/982-add-bcm-fullcone-support.patch b/openwrt/patch/kernel-6.6/net/982-add-bcm-fullcone-support.patch deleted file mode 100644 index 446f6bba5..000000000 --- a/openwrt/patch/kernel-6.6/net/982-add-bcm-fullcone-support.patch +++ /dev/null @@ -1,235 +0,0 @@ ---- a/net/netfilter/nf_nat_masquerade.c -+++ b/net/netfilter/nf_nat_masquerade.c -@@ -8,6 +8,9 @@ - #include - - #include -+#include -+#include -+#include - - struct masq_dev_work { - struct work_struct work; -@@ -24,6 +27,129 @@ static DEFINE_MUTEX(masq_mutex); - static unsigned int masq_refcnt __read_mostly; - static atomic_t masq_worker_count __read_mostly; - -+static void bcm_nat_expect(struct nf_conn *ct, -+ struct nf_conntrack_expect *exp) -+{ -+ struct nf_nat_range2 range; -+ -+ /* This must be a fresh one. */ -+ BUG_ON(ct->status & IPS_NAT_DONE_MASK); -+ -+ /* Change src to where new ct comes from */ -+ range.flags = NF_NAT_RANGE_MAP_IPS; -+ range.min_addr = range.max_addr = -+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3; -+ nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); -+ -+ /* For DST manip, map port here to where it's expected. */ -+ range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); -+ range.min_proto = range.max_proto = exp->saved_proto; -+ range.min_addr = range.max_addr = exp->saved_addr; -+ nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); -+} -+ -+/****************************************************************************/ -+static int bcm_nat_help(struct sk_buff *skb, unsigned int protoff, -+ struct nf_conn *ct, enum ip_conntrack_info ctinfo) -+{ -+ int dir = CTINFO2DIR(ctinfo); -+ struct nf_conn_help *help = nfct_help(ct); -+ struct nf_conntrack_expect *exp; -+ -+ if (dir != IP_CT_DIR_ORIGINAL || -+ help->expecting[NF_CT_EXPECT_CLASS_DEFAULT]) -+ return NF_ACCEPT; -+ -+ pr_debug("bcm_nat: packet[%d bytes] ", skb->len); -+ nf_ct_dump_tuple(&ct->tuplehash[dir].tuple); -+ pr_debug("reply: "); -+ nf_ct_dump_tuple(&ct->tuplehash[!dir].tuple); -+ -+ /* Create expect */ -+ if ((exp = nf_ct_expect_alloc(ct)) == NULL) -+ return NF_ACCEPT; -+ -+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, AF_INET, NULL, -+ &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_UDP, -+ NULL, &ct->tuplehash[!dir].tuple.dst.u.udp.port); -+ exp->flags = NF_CT_EXPECT_PERMANENT; -+ exp->saved_addr = ct->tuplehash[dir].tuple.src.u3; -+ exp->saved_proto.udp.port = ct->tuplehash[dir].tuple.src.u.udp.port; -+ exp->dir = !dir; -+ exp->expectfn = bcm_nat_expect; -+ -+ /* Setup expect */ -+ nf_ct_expect_related(exp, 0); -+ nf_ct_expect_put(exp); -+ pr_debug("bcm_nat: expect setup\n"); -+ -+ return NF_ACCEPT; -+} -+ -+/****************************************************************************/ -+static struct nf_conntrack_expect_policy bcm_nat_exp_policy __read_mostly = { -+ .max_expected = 1000, -+ .timeout = 240, -+}; -+ -+/****************************************************************************/ -+static struct nf_conntrack_helper nf_conntrack_helper_bcm_nat __read_mostly = { -+ .name = "BCM-NAT", -+ .me = THIS_MODULE, -+ .tuple.src.l3num = AF_INET, -+ .tuple.dst.protonum = IPPROTO_UDP, -+ .expect_policy = &bcm_nat_exp_policy, -+ .expect_class_max = 1, -+ .help = bcm_nat_help, -+}; -+ -+/****************************************************************************/ -+static inline int find_exp(__be32 ip, __be16 port, struct nf_conn *ct) -+{ -+ struct nf_conntrack_tuple tuple; -+ struct nf_conntrack_expect *i = NULL; -+ -+ -+ memset(&tuple, 0, sizeof(tuple)); -+ tuple.src.l3num = AF_INET; -+ tuple.dst.protonum = IPPROTO_UDP; -+ tuple.dst.u3.ip = ip; -+ tuple.dst.u.udp.port = port; -+ -+ rcu_read_lock(); -+ i = __nf_ct_expect_find(nf_ct_net(ct), nf_ct_zone(ct), &tuple); -+ rcu_read_unlock(); -+ -+ return i != NULL; -+} -+ -+/****************************************************************************/ -+static inline struct nf_conntrack_expect *find_fullcone_exp(struct nf_conn *ct) -+{ -+ struct nf_conntrack_tuple * tp = -+ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; -+ struct nf_conntrack_expect * exp = NULL; -+ struct nf_conntrack_expect * i; -+ unsigned int h; -+ -+ rcu_read_lock(); -+ for (h = 0; h < nf_ct_expect_hsize; h++) { -+ hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) { -+ if (nf_inet_addr_cmp(&i->saved_addr, &tp->src.u3) && -+ i->saved_proto.all == tp->src.u.all && -+ i->tuple.dst.protonum == tp->dst.protonum && -+ i->tuple.src.u3.ip == 0 && -+ i->tuple.src.u.udp.port == 0) { -+ exp = i; -+ break; -+ } -+ } -+ } -+ rcu_read_unlock(); -+ -+ return exp; -+} -+ - unsigned int - nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, - const struct nf_nat_range2 *range, -@@ -61,6 +187,72 @@ nf_nat_masquerade_ipv4(struct sk_buff *s - if (nat) - nat->masq_index = out->ifindex; - -+/* RFC 4787 - 4.2.2. Port Parity -+ i.e., an even port will be mapped to an even port, and an odd port will be mapped to an odd port. -+*/ -+#define CHECK_PORT_PARITY(a, b) ((a%2)==(b%2)) -+ if (range->min_addr.ip != 0 /* nat_mode == full cone */ -+ && (nfct_help(ct) == NULL || nfct_help(ct)->helper == NULL) -+ && nf_ct_protonum(ct) == IPPROTO_UDP) { -+ unsigned int ret; -+ u_int16_t minport; -+ u_int16_t maxport; -+ struct nf_conntrack_expect *exp; -+ -+ pr_debug("bcm_nat: need full cone NAT\n"); -+ -+ /* Choose port */ -+ spin_lock_bh(&nf_conntrack_expect_lock); -+ /* Look for existing expectation */ -+ exp = find_fullcone_exp(ct); -+ if (exp) { -+ minport = maxport = exp->tuple.dst.u.udp.port; -+ pr_debug("bcm_nat: existing mapped port = %hu\n", -+ ntohs(minport)); -+ } else { /* no previous expect */ -+ u_int16_t newport, tmpport, orgport; -+ -+ minport = range->min_proto.all == 0? -+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src. -+ u.udp.port : range->min_proto.all; -+ maxport = range->max_proto.all == 0? -+ htons(65535) : range->max_proto.all; -+ orgport = ntohs(minport); -+ for (newport = ntohs(minport),tmpport = ntohs(maxport); -+ newport <= tmpport; newport++) { -+ if (CHECK_PORT_PARITY(orgport, newport) && !find_exp(newsrc, htons(newport), ct)) { -+ pr_debug("bcm_nat: new mapped port = " -+ "%hu\n", newport); -+ minport = maxport = htons(newport); -+ break; -+ } -+ } -+ } -+ spin_unlock_bh(&nf_conntrack_expect_lock); -+ -+ -+ memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); -+ memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); -+ -+ newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS | -+ NF_NAT_RANGE_PROTO_SPECIFIED; -+ newrange.max_addr.ip = newrange.min_addr.ip = newsrc; -+ newrange.min_proto.udp.port = newrange.max_proto.udp.port = minport; -+ -+ /* Set ct helper */ -+ ret = nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); -+ if (ret == NF_ACCEPT) { -+ struct nf_conn_help *help = nfct_help(ct); -+ if (help == NULL) -+ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); -+ if (help != NULL) { -+ help->helper = &nf_conntrack_helper_bcm_nat; -+ pr_debug("bcm_nat: helper set\n"); -+ } -+ } -+ return ret; -+ } -+ - /* Transfer from original range. */ - memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); - memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); -@@ -352,6 +544,7 @@ EXPORT_SYMBOL_GPL(nf_nat_masquerade_inet - - void nf_nat_masquerade_inet_unregister_notifiers(void) - { -+ nf_conntrack_helper_unregister(&nf_conntrack_helper_bcm_nat); - mutex_lock(&masq_mutex); - /* check if the notifiers still have clients */ - if (--masq_refcnt > 0) ---- a/net/netfilter/xt_MASQUERADE.c -+++ b/net/netfilter/xt_MASQUERADE.c -@@ -42,6 +42,9 @@ masquerade_tg(struct sk_buff *skb, const - range.min_proto = mr->range[0].min; - range.max_proto = mr->range[0].max; - -+ range.min_addr.ip = mr->range[0].min_ip; -+ range.max_addr.ip = mr->range[0].max_ip; -+ - return nf_nat_masquerade_ipv4(skb, xt_hooknum(par), &range, - xt_out(par)); - } diff --git a/openwrt/patch/kernel-6.6/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.6/net/983-add-bcm-fullcone-nft_masq-support.patch deleted file mode 100644 index 4d2e84cc1..000000000 --- a/openwrt/patch/kernel-6.6/net/983-add-bcm-fullcone-nft_masq-support.patch +++ /dev/null @@ -1,114 +0,0 @@ ---- a/include/uapi/linux/netfilter/nf_tables.h -+++ b/include/uapi/linux/netfilter/nf_tables.h -@@ -1477,12 +1477,16 @@ enum nft_tproxy_attributes { - * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) - * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) - * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) -+ * @NFTA_MASQ_REG_ADDR_MIN: source register of address range start (NLA_U32: nft_registers) non zero to enable bcm fullcone -+ * @NFTA_MASQ_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers) - */ - enum nft_masq_attributes { - NFTA_MASQ_UNSPEC, - NFTA_MASQ_FLAGS, - NFTA_MASQ_REG_PROTO_MIN, - NFTA_MASQ_REG_PROTO_MAX, -+ NFTA_MASQ_REG_ADDR_MIN, -+ NFTA_MASQ_REG_ADDR_MAX, - __NFTA_MASQ_MAX - }; - #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) ---- a/net/netfilter/nft_masq.c -+++ b/net/netfilter/nft_masq.c -@@ -17,6 +17,8 @@ struct nft_masq { - u32 flags; - u8 sreg_proto_min; - u8 sreg_proto_max; -+ u8 sreg_addr_min; // non zero to enable brcm fullconenat -+ u8 sreg_addr_max; - }; - - static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { -@@ -24,6 +26,8 @@ static const struct nla_policy nft_masq_ - NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), - [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, - [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, -+ [NFTA_MASQ_REG_ADDR_MIN] = { .type = NLA_U32 }, -+ [NFTA_MASQ_REG_ADDR_MAX] = { .type = NLA_U32 }, - }; - - static int nft_masq_validate(const struct nft_ctx *ctx, -@@ -45,6 +49,7 @@ static int nft_masq_init(const struct nf - const struct nlattr * const tb[]) - { - u32 plen = sizeof_field(struct nf_nat_range, min_proto.all); -+ u32 alen = sizeof_field(struct nf_nat_range, min_addr.all); - struct nft_masq *priv = nft_expr_priv(expr); - int err; - -@@ -68,6 +73,25 @@ static int nft_masq_init(const struct nf - } - } - -+ if (tb[NFTA_MASQ_REG_ADDR_MIN]) { -+ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MIN], -+ &priv->sreg_addr_min, alen); -+ if (err < 0) -+ return err; -+ -+ if (tb[NFTA_MASQ_REG_ADDR_MAX]) { -+ err = nft_parse_register_load(tb[NFTA_MASQ_REG_ADDR_MAX], -+ &priv->sreg_addr_max, -+ alen); -+ if (err < 0) -+ return err; -+ } else { -+ priv->sreg_addr_max = priv->sreg_addr_min; -+ } -+ -+ priv->flags |= NF_NAT_RANGE_MAP_IPS; -+ } -+ - return nf_ct_netns_get(ctx->net, ctx->family); - } - -@@ -88,6 +112,14 @@ static int nft_masq_dump(struct sk_buff - goto nla_put_failure; - } - -+ if (priv->sreg_addr_min) { -+ if (nft_dump_register(skb, NFTA_MASQ_REG_ADDR_MIN, -+ priv->sreg_addr_min) || -+ nft_dump_register(skb, NFTA_MASQ_REG_ADDR_MAX, -+ priv->sreg_addr_max)) -+ goto nla_put_failure; -+ } -+ - return 0; - - nla_put_failure: -@@ -112,6 +144,12 @@ static void nft_masq_eval(const struct n - - switch (nft_pf(pkt)) { - case NFPROTO_IPV4: -+ if (priv->sreg_addr_min) { -+ range.min_addr.ip = (__force __be32) -+ regs->data[priv->sreg_addr_min]; -+ range.max_addr.ip = (__force __be32) -+ regs->data[priv->sreg_addr_max]; -+ } - regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, - nft_hook(pkt), - &range, -@@ -119,6 +157,12 @@ static void nft_masq_eval(const struct n - break; - #ifdef CONFIG_NF_TABLES_IPV6 - case NFPROTO_IPV6: -+ if (priv->sreg_addr_min) { -+ memcpy(range.min_addr.ip6, ®s->data[priv->sreg_addr_min], -+ sizeof(range.min_addr.ip6)); -+ memcpy(range.max_addr.ip6, ®s->data[priv->sreg_addr_max], -+ sizeof(range.max_addr.ip6)); -+ } - regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, - nft_out(pkt)); - break; diff --git a/openwrt/patch/kernel-6.6/net/README.md b/openwrt/patch/kernel-6.6/net/README.md deleted file mode 100644 index 105c48c9f..000000000 --- a/openwrt/patch/kernel-6.6/net/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Patches - -## Fullcone - -- [x] Patch 1: [952-net-conntrack-events-support-multiple-registrant.patch](./952-net-conntrack-events-support-multiple-registrant.patch) - -## BCM-Fullcone - -- [x] Patch 1: [982-add-bcm-fullcone-support.patch](./982-add-bcm-fullcone-support.patch) -- [x] Patch 2: [983-add-bcm-fullcone-nft_masq-support.patch](./983-add-bcm-fullcone-nft_masq-support.patch) - -## Shortcut Forwarding Engine - -- [x] Patch 1: [601-netfilter-export-udp_get_timeouts-function.patch](./601-netfilter-export-udp_get_timeouts-function.patch) -- [x] Patch 2: [953-net-patch-linux-kernel-to-support-shortcut-fe.patch](./953-net-patch-linux-kernel-to-support-shortcut-fe.patch) diff --git a/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-23.05.patch b/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-23.05.patch deleted file mode 100644 index 2344cafe5..000000000 --- a/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-23.05.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js -+++ b/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js -@@ -24,7 +24,7 @@ var commonConf = [ - [form.ListValue, 'log_level', _('Log level'), _('LogLevel specifies the minimum log level. Valid values are "trace", "debug", "info", "warn", and "error".
By default, this value is "info".'), {values: ['trace', 'debug', 'info', 'warn', 'error']}], - [form.Value, 'log_max_days', _('Log max days'), _('LogMaxDays specifies the maximum number of days to store log information before deletion. This is only used if LogWay == "file".
By default, this value is 0.'), {datatype: 'uinteger'}], - [form.Flag, 'disable_log_color', _('Disable log color'), _('DisableLogColor disables log colors when LogWay == "console" when set to true.'), {datatype: 'bool', default: 'false'}], -- [form.Value, 'token', _('Token'), _('Token specifies the authorization token used to create keys to be sent to the server. The server must have a matching token for authorization to succeed.
By default, this value is "".')], -+ [form.Value, 'token', _('Token'), _('Token specifies the authorization token used to create keys to be sent to the server. The server must have a matching token for authorization to succeed.
By default, this value is "".'), {password: true}], - [form.Value, 'admin_addr', _('Admin address'), _('AdminAddr specifies the address that the admin server binds to.
By default, this value is "127.0.0.1".'), {datatype: 'ipaddr'}], - [form.Value, 'admin_port', _('Admin port'), _('AdminPort specifies the port for the admin server to listen on. If this value is 0, the admin server will not be started.
By default, this value is 0.'), {datatype: 'port'}], - [form.Value, 'admin_user', _('Admin user'), _('AdminUser specifies the username that the admin server will use for login.
By default, this value is "admin".')], diff --git a/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-24.10.patch b/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch similarity index 100% rename from openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-openwrt-24.10.patch rename to openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch diff --git a/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch b/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch deleted file mode 100644 index 189d53666..000000000 --- a/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-24.10.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js -+++ b/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js -@@ -7,11 +7,10 @@ - - // [Widget, Option, Title, Description, {Param: 'Value'}], - var startupConf = [ -- [form.Flag, 'stdout', _('Log stdout')], -- [form.Flag, 'stderr', _('Log stderr')], -+ [form.Flag, 'enable', _('Enable'), undefined, {datatype: 'bool', default: 'true', rmempty: false}], - [widgets.UserSelect, 'user', _('Run daemon as user')], - [widgets.GroupSelect, 'group', _('Run daemon as group')], -- [form.Flag, 'respawn', _('Respawn when crashed')], -+ [form.Flag, 'respawn', _('Respawn when crashed'), undefined, {datatype: 'bool', default: 'true', rmempty: false}], - [form.DynamicList, 'env', _('Environment variable'), _('OS environments pass to frp for config file template, see frp README'), {placeholder: 'ENV_NAME=value'}], - [form.DynamicList, 'conf_inc', _('Additional configs'), _('Config files include in temporary config file'), {placeholder: '/etc/frp/frpc.d/frpc_full.ini'}] - ]; diff --git a/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-23.05.patch b/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch similarity index 100% rename from openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-openwrt-23.05.patch rename to openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch diff --git a/openwrt/patch/luci/dhcp/README.md b/openwrt/patch/luci/dhcp/README.md deleted file mode 100644 index 0a838365e..000000000 --- a/openwrt/patch/luci/dhcp/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### LuCI DHCP COMMIT: - -openwrt-23.05: https://github.com/openwrt/luci/commit/1f36628bc60f6e1f33667b025917eebec19d3162 diff --git a/openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js b/openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js deleted file mode 100644 index 1074beb66..000000000 --- a/openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js +++ /dev/null @@ -1,1110 +0,0 @@ -'use strict'; -'require view'; -'require dom'; -'require poll'; -'require rpc'; -'require uci'; -'require form'; -'require network'; -'require validation'; -'require tools.widgets as widgets'; - -var callHostHints, callDUIDHints, callDHCPLeases, CBILeaseStatus, CBILease6Status; - -callHostHints = rpc.declare({ - object: 'luci-rpc', - method: 'getHostHints', - expect: { '': {} } -}); - -callDUIDHints = rpc.declare({ - object: 'luci-rpc', - method: 'getDUIDHints', - expect: { '': {} } -}); - -callDHCPLeases = rpc.declare({ - object: 'luci-rpc', - method: 'getDHCPLeases', - expect: { '': {} } -}); - -CBILeaseStatus = form.DummyValue.extend({ - renderWidget: function(section_id, option_id, cfgvalue) { - return E([ - E('h4', _('Active DHCP Leases')), - E('table', { 'id': 'lease_status_table', 'class': 'table' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th' }, _('Hostname')), - E('th', { 'class': 'th' }, _('IPv4 address')), - E('th', { 'class': 'th' }, _('MAC address')), - E('th', { 'class': 'th' }, _('Lease time remaining')) - ]), - E('tr', { 'class': 'tr placeholder' }, [ - E('td', { 'class': 'td' }, E('em', _('Collecting data...'))) - ]) - ]) - ]); - } -}); - -CBILease6Status = form.DummyValue.extend({ - renderWidget: function(section_id, option_id, cfgvalue) { - return E([ - E('h4', _('Active DHCPv6 Leases')), - E('table', { 'id': 'lease6_status_table', 'class': 'table' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th' }, _('Host')), - E('th', { 'class': 'th' }, _('IPv6 address')), - E('th', { 'class': 'th' }, _('DUID')), - E('th', { 'class': 'th' }, _('Lease time remaining')) - ]), - E('tr', { 'class': 'tr placeholder' }, [ - E('td', { 'class': 'td' }, E('em', _('Collecting data...'))) - ]) - ]) - ]); - } -}); - -function calculateNetwork(addr, mask) { - addr = validation.parseIPv4(String(addr)); - - if (!isNaN(mask)) - mask = validation.parseIPv4(network.prefixToMask(+mask)); - else - mask = validation.parseIPv4(String(mask)); - - if (addr == null || mask == null) - return null; - - return [ - [ - addr[0] & (mask[0] >>> 0 & 255), - addr[1] & (mask[1] >>> 0 & 255), - addr[2] & (mask[2] >>> 0 & 255), - addr[3] & (mask[3] >>> 0 & 255) - ].join('.'), - mask.join('.') - ]; -} - -function generateDnsmasqInstanceEntry(data) { - const nameValueMap = new Map(Object.entries(data)); - let formatString = nameValueMap.get('.index') + ' (' + _('Name') + (nameValueMap.get('.anonymous') ? ': dnsmasq[' + nameValueMap.get('.index') + ']': ': ' + nameValueMap.get('.name')); - - if (data.domain) { - formatString += ', ' + _('Domain') + ': ' + data.domain; - } - if (data.local) { - formatString += ', ' + _('Local') + ': ' + data.local; - } - formatString += ')'; - - return [nameValueMap.get('.name'), formatString]; -} - -function getDHCPPools() { - return uci.load('dhcp').then(function() { - let sections = uci.sections('dhcp', 'dhcp'), - tasks = [], pools = []; - - for (var i = 0; i < sections.length; i++) { - if (sections[i].ignore == '1' || !sections[i].interface) - continue; - - tasks.push(network.getNetwork(sections[i].interface).then(L.bind(function(section_id, net) { - var cidr = net ? (net.getIPAddrs()[0] || '').split('/') : null; - - if (cidr && cidr.length == 2) { - var net_mask = calculateNetwork(cidr[0], cidr[1]); - - pools.push({ - section_id: section_id, - network: net_mask[0], - netmask: net_mask[1] - }); - } - }, null, sections[i]['.name']))); - } - - return Promise.all(tasks).then(function() { - return pools; - }); - }); -} - -function validateHostname(sid, s) { - if (s == null || s == '') - return true; - - if (s.length > 256) - return _('Expecting: %s').format(_('valid hostname')); - - var labels = s.replace(/^\*?\.?|\.$/g, '').split(/\./); - - for (var i = 0; i < labels.length; i++) - if (!labels[i].match(/^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i)) - return _('Expecting: %s').format(_('valid hostname')); - - return true; -} - -function validateAddressList(sid, s) { - if (s == null || s == '') - return true; - - var m = s.match(/^\/(.+)\/$/), - names = m ? m[1].split(/\//) : [ s ]; - - for (var i = 0; i < names.length; i++) { - var res = validateHostname(sid, names[i]); - - if (res !== true) - return res; - } - - return true; -} - -function validateServerSpec(sid, s) { - if (s == null || s == '') - return true; - - var m = s.match(/^(\/.*\/)?(.*)$/); - if (!m) - return _('Expecting: %s').format(_('valid hostname')); - - if (m[1] != '//' && m[1] != '/#/') { - var res = validateAddressList(sid, m[1]); - if (res !== true) - return res; - } - - if (m[2] == '' || m[2] == '#') - return true; - - // ipaddr%scopeid#srvport@source@interface#srcport - - m = m[2].match(/^([0-9a-f:.]+)(?:%[^#@]+)?(?:#(\d+))?(?:@([0-9a-f:.]+)(?:@[^#]+)?(?:#(\d+))?)?$/); - - if (!m) - return _('Expecting: %s').format(_('valid IP address')); - - if (validation.parseIPv4(m[1])) { - if (m[3] != null && !validation.parseIPv4(m[3])) - return _('Expecting: %s').format(_('valid IPv4 address')); - } - else if (validation.parseIPv6(m[1])) { - if (m[3] != null && !validation.parseIPv6(m[3])) - return _('Expecting: %s').format(_('valid IPv6 address')); - } - else { - return _('Expecting: %s').format(_('valid IP address')); - } - - if ((m[2] != null && +m[2] > 65535) || (m[4] != null && +m[4] > 65535)) - return _('Expecting: %s').format(_('valid port value')); - - return true; -} - -function expandAndFormatMAC(macs) { - let result = []; - - macs.forEach(mac => { - if (isValidMAC(mac)) { - const expandedMac = mac.split(':').map(part => { - return (part.length === 1 && part !== '*') ? '0' + part : part; - }).join(':').toUpperCase(); - result.push(expandedMac); - } - }); - - return result.length ? result : null; -} - -function isValidMAC(sid, s) { - if (!s) - return true; - - let macaddrs = L.toArray(s); - - for (var i = 0; i < macaddrs.length; i++) - if (!macaddrs[i].match(/^(([0-9a-f]{1,2}|\*)[:-]){5}([0-9a-f]{1,2}|\*)$/i)) - return _('Expecting a valid MAC address, optionally including wildcards') + _('; invalid MAC: ') + macaddrs[i]; - - return true; -} - -function validateMACAddr(pools, sid, s) { - if (s == null || s == '') - return true; - - var leases = uci.sections('dhcp', 'host'), - this_macs = L.toArray(s).map(function(m) { return m.toUpperCase() }); - - for (var i = 0; i < pools.length; i++) { - var this_net_mask = calculateNetwork(this.section.formvalue(sid, 'ip'), pools[i].netmask); - - if (!this_net_mask) - continue; - - for (var j = 0; j < leases.length; j++) { - if (leases[j]['.name'] == sid || !leases[j].ip) - continue; - - var lease_net_mask = calculateNetwork(leases[j].ip, pools[i].netmask); - - if (!lease_net_mask || this_net_mask[0] != lease_net_mask[0]) - continue; - - var lease_macs = L.toArray(leases[j].mac).map(function(m) { return m.toUpperCase() }); - - for (var k = 0; k < lease_macs.length; k++) - for (var l = 0; l < this_macs.length; l++) - if (lease_macs[k] == this_macs[l]) - return _('The MAC address %h is already used by another static lease in the same DHCP pool').format(this_macs[l]); - } - } - - return isValidMAC(sid, s); -} - -return view.extend({ - load: function() { - return Promise.all([ - callHostHints(), - callDUIDHints(), - getDHCPPools(), - network.getNetworks() - ]); - }, - - render: function(hosts_duids_pools) { - var has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'), - hosts = hosts_duids_pools[0], - duids = hosts_duids_pools[1], - pools = hosts_duids_pools[2], - networks = hosts_duids_pools[3], - m, s, o, ss, so; - - let noi18nstrings = { - etc_hosts: '/etc/hosts', - etc_ethers: '/etc/ethers', - localhost_v6: '::1', - loopback_slash_8_v4: '127.0.0.0/8', - not_found: 'Not found', - nxdomain: 'NXDOMAIN', - rfc_1918_link: 'RFC1918', - rfc_4193_link: 'RFC4193', - rfc_4291_link: 'RFC4291', - rfc_6303_link: 'RFC6303', - reverse_arpa: '*.IN-ADDR.ARPA,*.IP6.ARPA', - servers_file_entry01: 'server=1.2.3.4', - servers_file_entry02: 'server=/domain/1.2.3.4', - - }; - - function customi18n(template, values) { - if (!values) - values = noi18nstrings; - return template.replace(/\{(\w+)\}/g, (match, key) => values[key] || match); - }; - - m = new form.Map('dhcp', _('DHCP and DNS'), - _('Dnsmasq is a lightweight DHCP server and DNS forwarder.')); - - s = m.section(form.TypedSection, 'dnsmasq'); - s.anonymous = true; - s.addremove = false; - - s.tab('general', _('General Settings')); - s.tab('advanced', _('Advanced Settings')); - s.tab('leases', _('Static Leases')); - s.tab('files', _('Resolv and Hosts Files')); - s.tab('hosts', _('Hostnames')); - s.tab('ipsets', _('IP Sets')); - s.tab('relay', _('Relay')); - s.tab('srvhosts', _('SRV')); - s.tab('mxhosts', _('MX')); - s.tab('cnamehosts', _('CNAME')); - s.tab('pxe_tftp', _('PXE/TFTP Settings')); - - s.taboption('general', form.Flag, 'domainneeded', - _('Domain required'), - _('Never forward DNS queries which lack dots or domain parts.') + '
' + - customi18n(_('Names not in {etc_hosts} are answered {not_found}.') ) - ); - s.taboption('general', form.Flag, 'authoritative', - _('Authoritative'), - _('This is the only DHCP server in the local network.')); - - o = s.taboption('general', form.Value, 'local', - _('Resolve these locally'), - _('Never forward these matching domains or subdomains; resolve from DHCP or hosts files only.')); - o.placeholder = '/internal.example.com/private.example.com/example.org'; - - s.taboption('general', form.Value, 'domain', - _('Local domain'), - _('Local domain suffix appended to DHCP names and hosts file entries.')); - - o = s.taboption('general', form.Flag, 'logqueries', - _('Log queries'), - _('Write received DNS queries to syslog.') + ' ' + _('Dump cache on SIGUSR1, include requesting IP.')); - o.optional = true; - - o = s.taboption('general', form.DynamicList, 'server', - _('DNS forwardings'), - _('Forward specific domain queries to specific upstream servers.')); - o.optional = true; - o.placeholder = '/*.example.org/10.1.2.3'; - o.validate = validateServerSpec; - - o = s.taboption('general', form.DynamicList, 'address', - _('Addresses'), - _('Resolve specified FQDNs to an IP.') + '
' + - customi18n(_('Syntax: {code_syntax}.'), - {code_syntax: '/fqdn[/fqdn…]/[ipaddr]'}) + '
' + - customi18n(_('{example_nx} returns {nxdomain}.', - 'hint: /example.com/ returns NXDOMAIN.'), - {example_nx: '/example.com/', nxdomain: 'NXDOMAIN'}) + '
' + - customi18n(_('{any_domain} matches any domain (and returns {nxdomain}).', - 'hint: /#/ matches any domain (and returns NXDOMAIN).'), - {any_domain:'/#/', nxdomain: 'NXDOMAIN'}) + '
' + - customi18n( - _('{example_null} returns {null_addr} addresses ({null_ipv4}, {null_ipv6}) for {example_com} and its subdomains.', - 'hint: /example.com/# returns NULL addresses (0.0.0.0, ::) for example.com and its subdomains.'), - { example_null: '/example.com/#', - null_addr: 'NULL', - null_ipv4: '0.0.0.0', - null_ipv6: '::', - example_com: 'example.com', - } - ) - ); - o.optional = true; - o.placeholder = '/router.local/router.lan/192.168.0.1'; - - o = s.taboption('general', form.DynamicList, 'ipset', - _('IP sets'), - _('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.')); - o.optional = true; - o.placeholder = '/example.org/ipset,ipset6'; - - o = s.taboption('general', form.Flag, 'rebind_protection', - _('Rebind protection'), - customi18n(_('Discard upstream responses containing {rfc_1918_link} addresses.') ) + '
' + - customi18n(_('Discard also upstream responses containing {rfc_4193_link}, Link-Local and private IPv4-Mapped {rfc_4291_link} IPv6 Addresses.') ) - ); - o.rmempty = false; - - o = s.taboption('general', form.Flag, 'rebind_localhost', - _('Allow localhost'), - customi18n( - _('Exempt {loopback_slash_8_v4} and {localhost_v6} from rebinding checks, e.g. for RBL services.') - ) - ); - o.depends('rebind_protection', '1'); - - o = s.taboption('general', form.DynamicList, 'rebind_domain', - _('Domain whitelist'), - customi18n(_('List of domains to allow {rfc_1918_link} responses for.') ) - ); - o.depends('rebind_protection', '1'); - o.optional = true; - o.placeholder = 'ihost.netflix.com'; - o.validate = validateAddressList; - - o = s.taboption('general', form.Flag, 'localservice', - _('Local service only'), - _('Accept DNS queries only from hosts whose address is on a local subnet.')); - o.optional = false; - o.rmempty = false; - - o = s.taboption('general', form.Flag, 'nonwildcard', - _('Non-wildcard'), - _('Bind only to configured interface addresses, instead of the wildcard address.')); - o.default = o.enabled; - o.optional = false; - o.rmempty = true; - - o = s.taboption('general', widgets.NetworkSelect, 'interface', - _('Listen interfaces'), - _('Listen only on the specified interfaces, and loopback if not excluded explicitly.')); - o.multiple = true; - o.nocreate = true; - - o = s.taboption('general', widgets.NetworkSelect, 'notinterface', - _('Exclude interfaces'), - _('Do not listen on the specified interfaces.')); - o.loopback = true; - o.multiple = true; - o.nocreate = true; - - o = s.taboption('relay', form.SectionValue, '__relays__', form.TableSection, 'relay', null, - _('Relay DHCP requests elsewhere. OK: v4↔v4, v6↔v6. Not OK: v4↔v6, v6↔v4.') - + '
' + _('Note: you may also need a DHCP Proxy (currently unavailable) when specifying a non-standard Relay To port(addr#port).') - + '
' + _('You may add multiple unique Relay To on the same Listen addr.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'local_addr', _('Relay from')); - so.rmempty = false; - so.datatype = 'ipaddr'; - - for (var family = 4; family <= 6; family += 2) { - for (var i = 0; i < networks.length; i++) { - if (networks[i].getName() != 'loopback') { - var addrs = (family == 6) ? networks[i].getIP6Addrs() : networks[i].getIPAddrs(); - for (var j = 0; j < addrs.length; j++) { - var addr = addrs[j].split('/')[0]; - so.value(addr, E([], [ - addr, ' (', - widgets.NetworkSelect.prototype.renderIfaceBadge(networks[i]), - ')' - ])); - } - } - } - } - - so = ss.option(form.Value, 'server_addr', _('Relay to address')); - so.rmempty = false; - so.optional = false; - so.placeholder = '192.168.10.1#535'; - - so.validate = function(section, value) { - var m = this.section.formvalue(section, 'local_addr'), - n = this.section.formvalue(section, 'server_addr'), - p; - - if (!m || !n) { - return _('Both "Relay from" and "Relay to address" must be specified.'); - } - else { - p = n.split('#'); - if (p.length > 1 && !/^[0-9]+$/.test(p[1])) - return _('Expected port number.'); - else - n = p[0]; - - if ((validation.parseIPv6(m) && validation.parseIPv6(n)) || - validation.parseIPv4(m) && validation.parseIPv4(n)) - return true; - else - return _('Address families of "Relay from" and "Relay to address" must match.') - } - return true; - }; - - - so = ss.option(widgets.NetworkSelect, 'interface', _('Only accept replies via')); - so.optional = true; - so.rmempty = false; - so.placeholder = 'lan'; - - s.taboption('files', form.Flag, 'readethers', - customi18n(_('Use {etc_ethers}') ), - customi18n(_('Read {etc_ethers} to configure the DHCP server.') ) - ); - - s.taboption('files', form.Value, 'leasefile', - _('Lease file'), - _('File to store DHCP lease information.')); - - o = s.taboption('files', form.Flag, 'noresolv', - _('Ignore resolv file')); - o.optional = true; - - o = s.taboption('files', form.Value, 'resolvfile', - _('Resolv file'), - _('File with upstream resolvers.')); - o.depends('noresolv', '0'); - o.placeholder = '/tmp/resolv.conf.d/resolv.conf.auto'; - o.optional = true; - - o = s.taboption('files', form.Flag, 'nohosts', - customi18n(_('Ignore {etc_hosts}') ) - ); - o.optional = true; - - o = s.taboption('files', form.DynamicList, 'addnhosts', - _('Additional hosts files')); - o.optional = true; - o.placeholder = '/etc/dnsmasq.hosts'; - - o = s.taboption('advanced', form.Flag, 'quietdhcp', - _('Suppress logging'), - _('Suppress logging of the routine operation for the DHCP protocol.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'sequential_ip', - _('Allocate IPs sequentially'), - _('Allocate IP addresses sequentially, starting from the lowest available address.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'boguspriv', - _('Filter private'), - customi18n( - _('Reject reverse lookups to {rfc_6303_link} IP ranges ({reverse_arpa}) not in {etc_hosts}.') ) - ); - o.default = o.enabled; - - s.taboption('advanced', form.Flag, 'filterwin2k', - _('Filter SRV/SOA service discovery'), - _('Filters SRV/SOA service discovery, to avoid triggering dial-on-demand links.') + '
' + - _('May prevent VoIP or other services from working.')); - - o = s.taboption('advanced', form.Flag, 'filter_aaaa', - _('Filter IPv6 AAAA records'), - _('Remove IPv6 addresses from the results and only return IPv4 addresses.') + '
' + - _('Can be useful if ISP has IPv6 nameservers but does not provide IPv6 routing.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'filter_a', - _('Filter IPv4 A records'), - _('Remove IPv4 addresses from the results and only return IPv6 addresses.')); - o.optional = true; - - s.taboption('advanced', form.Flag, 'localise_queries', - _('Localise queries'), - customi18n(_('Limit response records (from {etc_hosts}) to those that fall within the subnet of the querying interface.') ) + '
' + - _('This prevents unreachable IPs in subnets not accessible to you.') + '
' + - _('Note: IPv4 only.')); - - if (L.hasSystemFeature('dnsmasq', 'dnssec')) { - o = s.taboption('advanced', form.Flag, 'dnssec', - _('DNSSEC'), - _('Validate DNS replies and cache DNSSEC data, requires upstream to support DNSSEC.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'dnsseccheckunsigned', - _('DNSSEC check unsigned'), - _('Verify unsigned domain responses really come from unsigned domains.')); - o.default = o.enabled; - o.optional = true; - } - - s.taboption('advanced', form.Flag, 'expandhosts', - _('Expand hosts'), - _('Add local domain suffix to names served from hosts files.')); - - s.taboption('advanced', form.Flag, 'nonegcache', - _('No negative cache'), - _('Do not cache negative replies, e.g. for non-existent domains.')); - - o = s.taboption('advanced', form.Value, 'serversfile', - _('Additional servers file'), - customi18n(_('File listing upstream resolvers, optionally domain-specific, e.g. {servers_file_entry01}, {servers_file_entry02}.') ) - ); - o.placeholder = '/etc/dnsmasq.servers'; - - o = s.taboption('advanced', form.Flag, 'strictorder', - _('Strict order'), - _('Upstream resolvers will be queried in the order of the resolv file.')); - o.optional = true; - - o = s.taboption('advanced', form.Flag, 'allservers', - _('All servers'), - _('Query all available upstream resolvers.')); - o.optional = true; - - o = s.taboption('advanced', form.DynamicList, 'bogusnxdomain', - customi18n(_('IPs to override with {nxdomain}') ), - customi18n(_('Transform replies which contain the specified addresses or subnets into {nxdomain} responses.') ) - ); - o.optional = true; - o.placeholder = '64.94.110.11'; - - o = s.taboption('advanced', form.Value, 'port', - _('DNS server port'), - _('Listening port for inbound DNS queries.')); - o.optional = true; - o.datatype = 'port'; - o.placeholder = 53; - - o = s.taboption('advanced', form.Value, 'queryport', - _('DNS query port'), - _('Fixed source port for outbound DNS queries.')); - o.optional = true; - o.datatype = 'port'; - o.placeholder = _('any'); - - o = s.taboption('advanced', form.Value, 'dhcpleasemax', - _('Max. DHCP leases'), - _('Maximum allowed number of active DHCP leases.')); - o.optional = true; - o.datatype = 'uinteger'; - o.placeholder = _('unlimited'); - - o = s.taboption('advanced', form.Value, 'ednspacket_max', - _('Max. EDNS0 packet size'), - _('Maximum allowed size of EDNS0 UDP packets.')); - o.optional = true; - o.datatype = 'uinteger'; - o.placeholder = 1280; - - o = s.taboption('advanced', form.Value, 'dnsforwardmax', - _('Max. concurrent queries'), - _('Maximum allowed number of concurrent DNS queries.')); - o.optional = true; - o.datatype = 'uinteger'; - o.placeholder = 150; - - o = s.taboption('advanced', form.Value, 'cachesize', - _('Size of DNS query cache'), - _('Number of cached DNS entries, 10000 is maximum, 0 is no caching.')); - o.optional = true; - o.datatype = 'range(0,10000)'; - o.placeholder = 1000; - - o = s.taboption('pxe_tftp', form.Flag, 'enable_tftp', - _('Enable TFTP server'), - _('Enable the built-in single-instance TFTP server.')); - o.optional = true; - - o = s.taboption('pxe_tftp', form.Value, 'tftp_root', - _('TFTP server root'), - _('Root directory for files served via TFTP. Enable TFTP server and TFTP server root turn on the TFTP server and serve files from TFTP server root.')); - o.depends('enable_tftp', '1'); - o.optional = true; - o.placeholder = '/'; - - o = s.taboption('pxe_tftp', form.Value, 'dhcp_boot', - _('Network boot image'), - _('Filename of the boot image advertised to clients.')); - o.depends('enable_tftp', '1'); - o.optional = true; - o.placeholder = 'pxelinux.0'; - - /* PXE - https://openwrt.org/docs/guide-user/base-system/dhcp#booting_options */ - o = s.taboption('pxe_tftp', form.SectionValue, '__pxe__', form.GridSection, 'boot', null, - _('Special PXE boot options for Dnsmasq.')); - ss = o.subsection; - ss.addremove = true; - ss.anonymous = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'filename', - _('Filename'), - _('Host requests this filename from the boot server.')); - so.optional = false; - so.placeholder = 'pxelinux.0'; - - so = ss.option(form.Value, 'servername', - _('Server name'), - _('The hostname of the boot server')); - so.optional = false; - so.placeholder = 'myNAS'; - - so = ss.option(form.Value, 'serveraddress', - _('Server address'), - _('The IP address of the boot server')); - so.optional = false; - so.placeholder = '192.168.1.2'; - - so = ss.option(form.DynamicList, 'dhcp_option', - _('DHCP Options'), - _('Options for the Network-ID. (Note: needs also Network-ID.) E.g. "42,192.168.1.4" for NTP server, "3,192.168.4.4" for default route. 0.0.0.0 means "the address of the system running dnsmasq".')); - so.optional = true; - so.placeholder = '42,192.168.1.4'; - - so = ss.option(widgets.DeviceSelect, 'networkid', - _('Network-ID'), - _('Apply DHCP Options to this net. (Empty = all clients).')); - so.optional = true; - so.noaliases = true; - - so = ss.option(form.Flag, 'force', - _('Force'), - _('Always send DHCP Options. Sometimes needed, with e.g. PXELinux.')); - so.optional = true; - - so = ss.option(form.Value, 'instance', - _('Instance'), - _('Dnsmasq instance to which this boot section is bound. If unspecified, the section is valid for all dnsmasq instances.')); - so.optional = true; - - Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); - so.value(name, display_str); - }); - - o = s.taboption('srvhosts', form.SectionValue, '__srvhosts__', form.TableSection, 'srvhost', null, - _('Bind service records to a domain name: specify the location of services. See RFC2782.').format('https://datatracker.ietf.org/doc/html/rfc2782') - + '
' + _('_service: _sip, _ldap, _imap, _stun, _xmpp-client, … . (Note: while _http is possible, no browsers support SRV records.)') - + '
' + _('_proto: _tcp, _udp, _sctp, _quic, … .') - + '
' + _('You may add multiple records for the same Target.') - + '
' + _('Larger weights (of the same prio) are given a proportionately higher probability of being selected.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - - so = ss.option(form.Value, 'srv', _('SRV'), _('Syntax:') + ' ' + '_service._proto.example.com.'); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = '_sip._tcp.example.com.'; - - so = ss.option(form.Value, 'target', _('Target'), _('CNAME or fqdn')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'sip.example.com.'; - - so = ss.option(form.Value, 'port', _('Port')); - so.rmempty = false; - so.datatype = 'port'; - so.placeholder = '5060'; - - so = ss.option(form.Value, 'class', _('Priority'), _('Ordinal: lower comes first.')); - so.rmempty = true; - so.datatype = 'range(0,65535)'; - so.placeholder = '10'; - - so = ss.option(form.Value, 'weight', _('Weight')); - so.rmempty = true; - so.datatype = 'range(0,65535)'; - so.placeholder = '50'; - - o = s.taboption('mxhosts', form.SectionValue, '__mxhosts__', form.TableSection, 'mxhost', null, - _('Bind service records to a domain name: specify the location of services.') - + '
' + _('You may add multiple records for the same domain.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'domain', _('Domain')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'example.com.'; - - so = ss.option(form.Value, 'relay', _('Relay')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'relay.example.com.'; - - so = ss.option(form.Value, 'pref', _('Priority'), _('Ordinal: lower comes first.')); - so.rmempty = true; - so.datatype = 'range(0,65535)'; - so.placeholder = '0'; - - o = s.taboption('cnamehosts', form.SectionValue, '__cname__', form.TableSection, 'cname', null, - _('Set an alias for a hostname.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - - so = ss.option(form.Value, 'cname', _('Domain')); - so.rmempty = false; - so.validate = validateHostname; - so.placeholder = 'www.example.com.'; - - so = ss.option(form.Value, 'target', _('Target')); - so.rmempty = false; - so.datatype = 'hostname'; - so.placeholder = 'example.com.'; - - o = s.taboption('hosts', form.SectionValue, '__hosts__', form.GridSection, 'domain', null, - _('Hostnames are used to bind a domain name to an IP address. This setting is redundant for hostnames already configured with static leases, but it can be useful to rebind an FQDN.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - - so = ss.option(form.Value, 'name', _('Hostname')); - so.rmempty = false; - so.datatype = 'hostname'; - - so = ss.option(form.Value, 'ip', _('IP address')); - so.rmempty = false; - so.datatype = 'ipaddr'; - - var ipaddrs = {}; - - Object.keys(hosts).forEach(function(mac) { - var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4); - - for (var i = 0; i < addrs.length; i++) - ipaddrs[addrs[i]] = hosts[mac].name || mac; - }); - - L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { - so.value(ipv4, '%s (%s)'.format(ipv4, ipaddrs[ipv4])); - }); - - o = s.taboption('ipsets', form.SectionValue, '__ipsets__', form.GridSection, 'ipset', null, - _('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.') + '
' + - _('The netfilter components below are only regarded when running fw4.')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.rowcolors = true; - ss.nodescriptions = true; - ss.modaltitle = _('Edit IP set'); - - so = ss.option(form.DynamicList, 'name', _('Name of the set')); - so.rmempty = false; - so.editable = true; - so.datatype = 'string'; - - so = ss.option(form.DynamicList, 'domain', _('FQDN')); - so.rmempty = false; - so.editable = true; - so.datatype = 'hostname'; - - so = ss.option(form.Value, 'table', _('Netfilter table name'), _('Defaults to fw4.')); - so.editable = true; - so.placeholder = 'fw4'; - so.rmempty = true; - - so = ss.option(form.ListValue, 'table_family', _('Table IP family'), _('Defaults to IPv4+6.') + ' ' + _('Can be hinted by adding 4 or 6 to the name.') + '
' + - _('Adding an IPv6 to an IPv4 set and vice-versa silently fails.')); - so.editable = true; - so.rmempty = true; - so.value('inet', _('IPv4+6')); - so.value('ip', _('IPv4')); - so.value('ip6', _('IPv6')); - - o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null, - _('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '

' + - _('Use the Add Button to add a new lease entry. The MAC address identifies the host, the IPv4 address specifies the fixed address to use, and the Hostname is assigned as a symbolic name to the requesting host. The optional Lease time can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.') + '

' + - _('The tag construct filters which host directives are used; more than one tag can be provided, in this case the request must match all of them. Tagged directives are used in preference to untagged ones. Note that one of mac, duid or hostname still needs to be specified (can be a wildcard).')); - - ss = o.subsection; - - ss.addremove = true; - ss.anonymous = true; - ss.sortable = true; - ss.nodescriptions = true; - ss.max_cols = 8; - ss.modaltitle = _('Edit static lease'); - - so = ss.option(form.Value, 'name', - _('Hostname'), - _('Optional hostname to assign')); - so.validate = validateHostname; - so.rmempty = true; - so.write = function(section, value) { - uci.set('dhcp', section, 'name', value); - uci.set('dhcp', section, 'dns', '1'); - }; - so.remove = function(section) { - uci.unset('dhcp', section, 'name'); - uci.unset('dhcp', section, 'dns'); - }; - - //this can be a .DynamicList or a .Value with a widget and dnsmasq handles multimac OK. - so = ss.option(form.DynamicList, 'mac', - _('MAC address(es)'), - _('The hardware address(es) of this entry/host.') + '

' + - _('In DHCPv4, it is possible to include more than one mac address. This allows an IP address to be associated with multiple macaddrs, and dnsmasq abandons a DHCP lease to one of the macaddrs when another asks for a lease. It only works reliably if only one of the macaddrs is active at any time.')); - //As a special case, in DHCPv4, it is possible to include more than one hardware address. eg: --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2 This allows an IP address to be associated with multiple hardware addresses, and gives dnsmasq permission to abandon a DHCP lease to one of the hardware addresses when another one asks for a lease - so.rmempty = true; - so.cfgvalue = function(section) { - var macs = uci.get('dhcp', section, 'mac'); - if(!Array.isArray(macs)){ - return expandAndFormatMAC(L.toArray(macs)); - } else { - return expandAndFormatMAC(macs); - } - }; - //removed jows renderwidget function which hindered multi-mac entry - so.validate = validateMACAddr.bind(so, pools); - Object.keys(hosts).forEach(function(mac) { - var hint = hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0]; - so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); - }); - - so = ss.option(form.Value, 'ip', _('IPv4 address'), _('The IP address to be used for this host, or ignore to ignore any DHCP request from this host.')); - so.value('ignore', _('Ignore')); - so.datatype = 'or(ip4addr,"ignore")'; - so.validate = function(section, value) { - var m = this.section.formvalue(section, 'mac'), - n = this.section.formvalue(section, 'name'); - - if ((m && !m.length > 0) && !n) - return _('One of hostname or MAC address must be specified!'); - - if (!value || value == 'ignore') - return true; - - var leases = uci.sections('dhcp', 'host'); - - for (var i = 0; i < leases.length; i++) - if (leases[i]['.name'] != section && leases[i].ip == value) - return _('The IP address %h is already used by another static lease').format(value); - - for (var i = 0; i < pools.length; i++) { - var net_mask = calculateNetwork(value, pools[i].netmask); - - if (net_mask && net_mask[0] == pools[i].network) - return true; - } - - return _('The IP address is outside of any DHCP pool address range'); - }; - - L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) { - so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4); - }); - - so = ss.option(form.Value, 'leasetime', - _('Lease time'), - _('Host-specific lease time, e.g. 5m, 3h, 7d.')); - so.rmempty = true; - so.value('5m', _('5m (5 minutes)')); - so.value('3h', _('3h (3 hours)')); - so.value('12h', _('12h (12 hours - default)')); - so.value('7d', _('7d (7 days)')); - so.value('infinite', _('infinite (lease does not expire)')); - - so = ss.option(form.Value, 'duid', - _('DUID'), - _('The DHCPv6-DUID (DHCP unique identifier) of this host.')); - so.datatype = 'and(rangelength(20,36),hexstring)'; - Object.keys(duids).forEach(function(duid) { - so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?')); - }); - - so = ss.option(form.Value, 'hostid', - _('IPv6-Suffix (hex)'), - _('The IPv6 interface identifier (address suffix) as hexadecimal number (max. 16 chars).')); - so.datatype = 'and(rangelength(0,16),hexstring)'; - - so = ss.option(form.DynamicList, 'tag', - _('Tag'), - _('Assign new, freeform tags to this entry.')); - - so = ss.option(form.DynamicList, 'match_tag', - _('Match Tag'), - _('When a host matches an entry then the special tag %s is set. Use %s to match all known hosts.').format('known', 'known') + '

' + - _('Ignore requests from unknown machines using %s.').format('!known') + '

' + - _('If a host matches an entry which cannot be used because it specifies an address on a different subnet, the tag %s is set.').format('known-othernet')); - so.value('known', _('known')); - so.value('!known', _('!known (not known)')); - so.value('known-othernet', _('known-othernet (on different subnet)')); - so.optional = true; - - so = ss.option(form.Value, 'instance', - _('Instance'), - _('Dnsmasq instance to which this DHCP host section is bound. If unspecified, the section is valid for all dnsmasq instances.')); - so.optional = true; - - Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) { - var [name, display_str] = generateDnsmasqInstanceEntry(val); - so.value(name, display_str); - }); - - - so = ss.option(form.Flag, 'broadcast', - _('Broadcast'), - _('Force broadcast DHCP response.')); - - so = ss.option(form.Flag, 'dns', - _('Forward/reverse DNS'), - _('Add static forward and reverse DNS entries for this host.')); - - o = s.taboption('leases', CBILeaseStatus, '__status__'); - - if (has_dhcpv6) - o = s.taboption('leases', CBILease6Status, '__status6__'); - - return m.render().then(function(mapEl) { - poll.add(function() { - return callDHCPLeases().then(function(leaseinfo) { - var leases = Array.isArray(leaseinfo.dhcp_leases) ? leaseinfo.dhcp_leases : [], - leases6 = Array.isArray(leaseinfo.dhcp6_leases) ? leaseinfo.dhcp6_leases : []; - - cbi_update_table(mapEl.querySelector('#lease_status_table'), - leases.map(function(lease) { - var exp; - - if (lease.expires === false) - exp = E('em', _('unlimited')); - else if (lease.expires <= 0) - exp = E('em', _('expired')); - else - exp = '%t'.format(lease.expires); - - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? hint.name : null, - host = null; - - if (name && lease.hostname && lease.hostname != name) - host = '%s (%s)'.format(lease.hostname, name); - else if (lease.hostname) - host = lease.hostname; - - return [ - host || '-', - lease.ipaddr, - lease.macaddr, - exp - ]; - }), - E('em', _('There are no active leases'))); - - if (has_dhcpv6) { - cbi_update_table(mapEl.querySelector('#lease6_status_table'), - leases6.map(function(lease) { - var exp; - - if (lease.expires === false) - exp = E('em', _('unlimited')); - else if (lease.expires <= 0) - exp = E('em', _('expired')); - else - exp = '%t'.format(lease.expires); - - var hint = lease.macaddr ? hosts[lease.macaddr] : null, - name = hint ? (hint.name || L.toArray(hint.ipaddrs || hint.ipv4)[0] || L.toArray(hint.ip6addrs || hint.ipv6)[0]) : null, - host = null; - - if (name && lease.hostname && lease.hostname != name && lease.ip6addr != name) - host = '%s (%s)'.format(lease.hostname, name); - else if (lease.hostname) - host = lease.hostname; - else if (name) - host = name; - - return [ - host || '-', - lease.ip6addrs ? lease.ip6addrs.join('
') : lease.ip6addr, - lease.duid, - exp - ]; - }), - E('em', _('There are no active leases'))); - } - }); - }); - - return mapEl; - }); - } -}); diff --git a/openwrt/patch/mbedtls-23.05/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch b/openwrt/patch/mbedtls-23.05/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch deleted file mode 100644 index 4b0106d15..000000000 --- a/openwrt/patch/mbedtls-23.05/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch +++ /dev/null @@ -1,390 +0,0 @@ -From dfb6015ca79a9fee28f7fcb0af7e350a83574b83 Mon Sep 17 00:00:00 2001 -From: "Markku-Juhani O. Saarinen" -Date: Mon, 20 Nov 2017 14:58:41 +0000 -Subject: Implements AES and GCM with ARMv8 Crypto Extensions - -A compact patch that provides AES and GCM implementations that utilize the -ARMv8 Crypto Extensions. The config flag is MBEDTLS_ARMV8CE_AES_C, which -is disabled by default as we don't do runtime checking for the feature. -The new implementation lives in armv8ce_aes.c. - -Provides similar functionality to https://github.com/ARMmbed/mbedtls/pull/432 -Thanks to Barry O'Rourke and others for that contribtion. - -Tested on a Cortex A53 device and QEMU. On a midrange phone the real AES-GCM -throughput increases about 4x, while raw AES speed is up to 10x faster. - -When cross-compiling, you want to set something like: - - export CC='aarch64-linux-gnu-gcc' - export CFLAGS='-Ofast -march=armv8-a+crypto' - scripts/config.pl set MBEDTLS_ARMV8CE_AES_C - -QEMU seems to also need - - export LDFLAGS='-static' - -Then run normal make or cmake etc. ---- - ---- /dev/null -+++ b/ChangeLog.d/armv8_crypto_extensions.txt -@@ -0,0 +1,2 @@ -+Features -+ * Support ARMv8 Cryptography Extensions for AES and GCM. ---- /dev/null -+++ b/include/mbedtls/armv8ce_aes.h -@@ -0,0 +1,63 @@ -+/** -+ * \file armv8ce_aes.h -+ * -+ * \brief ARMv8 Cryptography Extensions -- Optimized code for AES and GCM -+ */ -+ -+/* -+ * -+ * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved -+ * SPDX-License-Identifier: Apache-2.0 -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); you may -+ * not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ * -+ * This file is part of mbed TLS (https://tls.mbed.org) -+ */ -+ -+#ifndef MBEDTLS_ARMV8CE_AES_H -+#define MBEDTLS_ARMV8CE_AES_H -+ -+#include "aes.h" -+ -+/** -+ * \brief [ARMv8 Crypto Extensions] AES-ECB block en(de)cryption -+ * -+ * \param ctx AES context -+ * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT -+ * \param input 16-byte input block -+ * \param output 16-byte output block -+ * -+ * \return 0 on success (cannot fail) -+ */ -+ -+int mbedtls_armv8ce_aes_crypt_ecb( mbedtls_aes_context *ctx, -+ int mode, -+ const unsigned char input[16], -+ unsigned char output[16] ); -+ -+/** -+ * \brief [ARMv8 Crypto Extensions] Multiply in GF(2^128) for GCM -+ * -+ * \param c Result -+ * \param a First operand -+ * \param b Second operand -+ * -+ * \note Both operands and result are bit strings interpreted as -+ * elements of GF(2^128) as per the GCM spec. -+ */ -+ -+void mbedtls_armv8ce_gcm_mult( unsigned char c[16], -+ const unsigned char a[16], -+ const unsigned char b[16] ); -+ -+#endif /* MBEDTLS_ARMV8CE_AES_H */ ---- a/include/mbedtls/check_config.h -+++ b/include/mbedtls/check_config.h -@@ -69,6 +69,10 @@ - #error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense" - #endif - -+#if defined(MBEDTLS_ARMV8CE_AES_C) && !defined(MBEDTLS_HAVE_ASM) -+#error "MBEDTLS_ARMV8CE_AES_C defined, but not all prerequisites" -+#endif -+ - #if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C) - #error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites" - #endif -@@ -959,3 +963,4 @@ typedef int mbedtls_iso_c_forbids_empty_ - - /* *INDENT-ON* */ - #endif /* MBEDTLS_CHECK_CONFIG_H */ -+ ---- a/include/mbedtls/config.h -+++ b/include/mbedtls/config.h -@@ -46,6 +46,7 @@ - * Requires support for asm() in compiler. - * - * Used in: -+ * library/armv8ce_aes.c - * library/aria.c - * library/timing.c - * include/mbedtls/bn_mul.h -@@ -2471,6 +2472,21 @@ - #define MBEDTLS_AESNI_C - - /** -+ * \def MBEDTLS_ARMV8CE_AES_C -+ * -+ * Enable ARMv8 Crypto Extensions for AES and GCM -+ * -+ * Module: library/armv8ce_aes.c -+ * Caller: library/aes.c -+ * library/gcm.c -+ * -+ * Requires: MBEDTLS_HAVE_ASM -+ * -+ * This module adds support for Armv8 Cryptography Extensions for AES and GCM. -+ */ -+//#define MBEDTLS_ARMV8CE_AES_C -+ -+/** - * \def MBEDTLS_AES_C - * - * Enable the AES block cipher. ---- a/library/aes.c -+++ b/library/aes.c -@@ -39,7 +39,9 @@ - #if defined(MBEDTLS_AESNI_C) - #include "mbedtls/aesni.h" - #endif -- -+#if defined(MBEDTLS_ARMV8CE_AES_C) -+#include "mbedtls/armv8ce_aes.h" -+#endif - #include "mbedtls/platform.h" - - #if !defined(MBEDTLS_AES_ALT) -@@ -1076,6 +1078,11 @@ int mbedtls_aes_crypt_ecb(mbedtls_aes_co - } - #endif - -+#if defined(MBEDTLS_ARMV8CE_AES_C) -+ // We don't do runtime checking for ARMv8 Crypto Extensions -+ return mbedtls_armv8ce_aes_crypt_ecb( ctx, mode, input, output ); -+#endif -+ - #if defined(MBEDTLS_VIA_PADLOCK_HAVE_CODE) - if (aes_padlock_ace) { - return mbedtls_padlock_xcryptecb(ctx, mode, input, output); ---- /dev/null -+++ b/library/armv8ce_aes.c -@@ -0,0 +1,142 @@ -+/* -+ * ARMv8 Cryptography Extensions -- Optimized code for AES and GCM -+ * -+ * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved -+ * SPDX-License-Identifier: Apache-2.0 -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); you may -+ * not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ * -+ * This file is part of mbed TLS (https://tls.mbed.org) -+ */ -+ -+#if !defined(MBEDTLS_CONFIG_FILE) -+#include "mbedtls/config.h" -+#else -+#include MBEDTLS_CONFIG_FILE -+#endif -+ -+#if defined(MBEDTLS_ARMV8CE_AES_C) -+ -+#include -+#include "mbedtls/armv8ce_aes.h" -+ -+#ifndef asm -+#define asm __asm -+#endif -+ -+/* -+ * [Armv8 Cryptography Extensions] AES-ECB block en(de)cryption -+ */ -+ -+#if defined(MBEDTLS_AES_C) -+ -+int mbedtls_armv8ce_aes_crypt_ecb( mbedtls_aes_context *ctx, -+ int mode, -+ const unsigned char input[16], -+ unsigned char output[16] ) -+{ -+ unsigned int i; -+ const uint8_t *rk; -+ uint8x16_t x, k; -+ -+ x = vld1q_u8( input ); /* input block */ -+ rk = (const uint8_t *) ctx->rk; /* round keys */ -+ -+ if( mode == MBEDTLS_AES_ENCRYPT ) -+ { -+ for( i = ctx->nr - 1; i != 0; i-- ) /* encryption loop */ -+ { -+ k = vld1q_u8( rk ); -+ rk += 16; -+ x = vaeseq_u8( x, k ); -+ x = vaesmcq_u8( x ); -+ } -+ k = vld1q_u8( rk ); -+ rk += 16; -+ x = vaeseq_u8( x, k ); -+ } -+ else -+ { -+ for( i = ctx->nr - 1; i != 0 ; i-- ) /* decryption loop */ -+ { -+ k = vld1q_u8( rk ); -+ rk += 16; -+ x = vaesdq_u8( x, k ); -+ x = vaesimcq_u8( x ); -+ } -+ k = vld1q_u8( rk ); -+ rk += 16; -+ x = vaesdq_u8( x, k ); -+ } -+ -+ k = vld1q_u8( rk ); /* final key just XORed */ -+ x = veorq_u8( x, k ); -+ vst1q_u8( output, x ); /* write out */ -+ -+ return ( 0 ); -+} -+ -+#endif /* MBEDTLS_AES_C */ -+ -+ -+/* -+ * [Armv8 Cryptography Extensions] Multiply in GF(2^128) for GCM -+ */ -+ -+#if defined(MBEDTLS_GCM_C) -+ -+void mbedtls_armv8ce_gcm_mult( unsigned char c[16], -+ const unsigned char a[16], -+ const unsigned char b[16] ) -+{ -+ /* GCM's GF(2^128) polynomial basis is x^128 + x^7 + x^2 + x + 1 */ -+ const uint64x2_t base = { 0, 0x86 }; /* note missing LS bit */ -+ -+ register uint8x16_t vc asm( "v0" ); /* named registers */ -+ register uint8x16_t va asm( "v1" ); /* (to avoid conflict) */ -+ register uint8x16_t vb asm( "v2" ); -+ register uint64x2_t vp asm( "v3" ); -+ -+ va = vld1q_u8( a ); /* load inputs */ -+ vb = vld1q_u8( b ); -+ vp = base; -+ -+ asm ( -+ "rbit %1.16b, %1.16b \n\t" /* reverse bit order */ -+ "rbit %2.16b, %2.16b \n\t" -+ "pmull2 %0.1q, %1.2d, %2.2d \n\t" /* v0 = a.hi * b.hi */ -+ "pmull2 v4.1q, %0.2d, %3.2d \n\t" /* mul v0 by x^64, reduce */ -+ "ext %0.16b, %0.16b, %0.16b, #8 \n\t" -+ "eor %0.16b, %0.16b, v4.16b \n\t" -+ "ext v5.16b, %2.16b, %2.16b, #8 \n\t" /* (swap hi and lo in b) */ -+ "pmull v4.1q, %1.1d, v5.1d \n\t" /* v0 ^= a.lo * b.hi */ -+ "eor %0.16b, %0.16b, v4.16b \n\t" -+ "pmull2 v4.1q, %1.2d, v5.2d \n\t" /* v0 ^= a.hi * b.lo */ -+ "eor %0.16b, %0.16b, v4.16b \n\t" -+ "pmull2 v4.1q, %0.2d, %3.2d \n\t" /* mul v0 by x^64, reduce */ -+ "ext %0.16b, %0.16b, %0.16b, #8 \n\t" -+ "eor %0.16b, %0.16b, v4.16b \n\t" -+ "pmull v4.1q, %1.1d, %2.1d \n\t" /* v0 ^= a.lo * b.lo */ -+ "eor %0.16b, %0.16b, v4.16b \n\t" -+ "rbit %0.16b, %0.16b \n\t" /* reverse bits for output */ -+ : "=w" (vc) /* q0: output */ -+ : "w" (va), "w" (vb), "w" (vp) /* q1, q2: input */ -+ : "v4", "v5" /* q4, q5: clobbered */ -+ ); -+ -+ vst1q_u8( c, vc ); /* write out */ -+} -+ -+#endif /* MBEDTLS_GCM_C */ -+ -+#endif /* MBEDTLS_ARMV8CE_AES_C */ ---- a/library/CMakeLists.txt -+++ b/library/CMakeLists.txt -@@ -15,6 +15,7 @@ set(src_crypto - aesni.c - arc4.c - aria.c -+ armv8ce_aes.c - asn1parse.c - asn1write.c - base64.c ---- a/library/gcm.c -+++ b/library/gcm.c -@@ -43,6 +43,10 @@ - #include "mbedtls/aesni.h" - #endif - -+#if defined(MBEDTLS_ARMV8CE_AES_C) -+#include "mbedtls/armv8ce_aes.h" -+#endif -+ - #if !defined(MBEDTLS_GCM_ALT) - - /* Parameter validation macros */ -@@ -81,6 +85,12 @@ static int gcm_gen_table(mbedtls_gcm_con - return ret; - } - -+#if defined(MBEDTLS_ARMV8CE_AES_C) -+ // we don't do feature testing with ARMv8 cryptography extensions -+ memcpy( ctx ->HL, h, 16 ); // put H at the beginning of buffer -+ return( 0 ); // that's all we need -+#endif -+ - /* pack h as two 64-bits ints, big-endian */ - hi = MBEDTLS_GET_UINT32_BE(h, 0); - lo = MBEDTLS_GET_UINT32_BE(h, 4); -@@ -191,6 +201,11 @@ static void gcm_mult(mbedtls_gcm_context - unsigned char lo, hi, rem; - uint64_t zh, zl; - -+#if defined(MBEDTLS_ARMV8CE_AES_C) -+ mbedtls_armv8ce_gcm_mult( output, x, (const unsigned char *) ctx->HL ); -+ return; -+#endif -+ - #if defined(MBEDTLS_AESNI_HAVE_CODE) - if (mbedtls_aesni_has_support(MBEDTLS_AESNI_CLMUL)) { - unsigned char h[16]; ---- a/library/Makefile -+++ b/library/Makefile -@@ -74,6 +74,7 @@ OBJS_CRYPTO= \ - aria.o \ - asn1parse.o \ - asn1write.o \ -+ armv8ce_aes.o \ - base64.o \ - bignum.o \ - blowfish.o \ ---- a/library/version_features.c -+++ b/library/version_features.c -@@ -636,6 +636,9 @@ static const char * const features[] = { - #if defined(MBEDTLS_AESNI_C) - "MBEDTLS_AESNI_C", - #endif /* MBEDTLS_AESNI_C */ -+#if defined(MBEDTLS_ARMV8CE_AES_C) -+ "MBEDTLS_ARMV8CE_AES_C", -+#endif /* MBEDTLS_ARMV8CE_AES_C */ - #if defined(MBEDTLS_AES_C) - "MBEDTLS_AES_C", - #endif /* MBEDTLS_AES_C */ diff --git a/openwrt/patch/mbedtls-23.05/mbedtls.patch b/openwrt/patch/mbedtls-23.05/mbedtls.patch deleted file mode 100644 index ee9029040..000000000 --- a/openwrt/patch/mbedtls-23.05/mbedtls.patch +++ /dev/null @@ -1,34 +0,0 @@ ---- a/package/libs/mbedtls/Config.in -+++ b/package/libs/mbedtls/Config.in -@@ -140,6 +140,11 @@ config MBEDTLS_ECP_DP_CURVE448_ENABLED - - comment "Build Options - unselect features to reduce binary size" - -+config MBEDTLS_ARMV8CE_AES_C -+ bool "MBEDTLS_ARMV8CE_AES_C" -+ default y -+ depends on aarch64 && !TARGET_bcm27xx -+ - config MBEDTLS_CERTS_C - bool "MBEDTLS_CERTS_C" - default n ---- a/package/libs/mbedtls/Makefile -+++ b/package/libs/mbedtls/Makefile -@@ -60,6 +60,7 @@ MBEDTLS_BUILD_OPTS_CIPHERS= \ - MBEDTLS_BUILD_OPTS= \ - $(MBEDTLS_BUILD_OPTS_CURVES) \ - $(MBEDTLS_BUILD_OPTS_CIPHERS) \ -+ CONFIG_MBEDTLS_ARMV8CE_AES_C \ - CONFIG_MBEDTLS_CERTS_C \ - CONFIG_MBEDTLS_CIPHER_MODE_OFB \ - CONFIG_MBEDTLS_CIPHER_MODE_XTS \ -@@ -122,6 +123,9 @@ CSR generation (gen_key, cert_req) - endef - - TARGET_CFLAGS := $(filter-out -O%,$(TARGET_CFLAGS)) -+ifneq ($(CONFIG_MBEDTLS_ARMV8CE_AES_C),) -+ TARGET_CFLAGS := $(filter-out -march=%,$(TARGET_CFLAGS)) -+endif - - CMAKE_OPTIONS += \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ diff --git a/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-23.05.patch b/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-23.05.patch deleted file mode 100644 index e3df56b57..000000000 --- a/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-23.05.patch +++ /dev/null @@ -1,320 +0,0 @@ -From 726ca5340823e2d5f3b5e7b6ad83e52ba3be14a9 Mon Sep 17 00:00:00 2001 -From: Aviana Cruz -Date: Sat, 16 Sep 2023 15:04:12 +0000 -Subject: [PATCH] odhcpd: improve RFC 9096 compliance - -and allow configuring upper limit for preferred and valid lifetime. - -Signed-off-by: Aviana Cruz ---- - README | 12 ++++++------ - src/config.c | 35 +++++++++++++++++++++------------- - src/dhcpv6-ia.c | 50 ++++++++++++++++++++++++++++++------------------- - src/odhcpd.h | 8 ++++++-- - src/router.c | 17 ++++++++--------- - 5 files changed, 73 insertions(+), 49 deletions(-) - ---- a/README -+++ b/README -@@ -116,7 +116,9 @@ domain list Sear - leasetime string 12h DHCPv4 address leasetime - start integer 100 DHCPv4 pool start - limit integer 150 DHCPv4 pool size --preferred_lifetime string 12h Value for the preferred lifetime -+max_preferred_lifetime string 45m Upper limit for the preferred lifetime -+ for a prefix -+max_valid_lifetime string 90m Upper limit for the valid lifetime - for a prefix - ra_default integer 0 Override default route - 0: default, 1: ignore no public address, 2: ignore all -@@ -131,11 +133,9 @@ ra_maxinterval integer 600 Maximum ti - sending unsolicited RA - ra_mininterval integer 200 Minimum time allowed between - sending unsolicited RA --ra_lifetime integer 1800 Value to be placed in Router -- Lifetime field of RA --ra_useleasetime bool 0 Use configured leasetime as -- limit for the preferred and -- valid lifetime of a prefix -+ra_lifetime integer 2700 Value to be placed in Router -+ Lifetime field of RA. Not recommended to be -+ more than 2700 (RFC9096). - ra_reachabletime integer 0 Reachable Time in milliseconds to be - advertised in RA messages - ra_retranstime integer 0 Retransmit Time in milliseconds to be ---- a/src/config.c -+++ b/src/config.c -@@ -79,7 +79,6 @@ enum { - IFACE_ATTR_RA_MININTERVAL, - IFACE_ATTR_RA_MAXINTERVAL, - IFACE_ATTR_RA_LIFETIME, -- IFACE_ATTR_RA_USELEASETIME, - IFACE_ATTR_RA_REACHABLETIME, - IFACE_ATTR_RA_RETRANSTIME, - IFACE_ATTR_RA_HOPLIMIT, -@@ -91,7 +90,8 @@ enum { - IFACE_ATTR_NDPROXY_ROUTING, - IFACE_ATTR_NDPROXY_SLAVE, - IFACE_ATTR_PREFIX_FILTER, -- IFACE_ATTR_PREFERRED_LIFETIME, -+ IFACE_ATTR_MAX_PREFERRED_LIFETIME, -+ IFACE_ATTR_MAX_VALID_LIFETIME, - IFACE_ATTR_NTP, - IFACE_ATTR_MAX - }; -@@ -134,7 +134,6 @@ static const struct blobmsg_policy iface - [IFACE_ATTR_RA_MININTERVAL] = { .name = "ra_mininterval", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_MAXINTERVAL] = { .name = "ra_maxinterval", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_LIFETIME] = { .name = "ra_lifetime", .type = BLOBMSG_TYPE_INT32 }, -- [IFACE_ATTR_RA_USELEASETIME] = { .name = "ra_useleasetime", .type = BLOBMSG_TYPE_BOOL }, - [IFACE_ATTR_RA_REACHABLETIME] = { .name = "ra_reachabletime", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_RETRANSTIME] = { .name = "ra_retranstime", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_HOPLIMIT] = { .name = "ra_hoplimit", .type = BLOBMSG_TYPE_INT32 }, -@@ -144,7 +143,8 @@ static const struct blobmsg_policy iface - [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL }, - [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL }, - [IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING }, -- [IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING }, -+ [IFACE_ATTR_MAX_PREFERRED_LIFETIME] = { .name = "max_preferred_lifetime", .type = BLOBMSG_TYPE_STRING }, -+ [IFACE_ATTR_MAX_VALID_LIFETIME] = { .name = "max_valid_lifetime", .type = BLOBMSG_TYPE_STRING }, - [IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY }, - }; - -@@ -215,7 +215,8 @@ static void set_interface_defaults(struc - iface->ndp = MODE_DISABLED; - iface->learn_routes = 1; - iface->dhcp_leasetime = 43200; -- iface->preferred_lifetime = 43200; -+ iface->max_preferred_lifetime = ND_PREFERRED_LIMIT; -+ iface->max_valid_lifetime = ND_VALID_LIMIT; - iface->dhcpv4_start.s_addr = htonl(START_DEFAULT); - iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1); - iface->dhcpv6_assignall = true; -@@ -647,15 +648,26 @@ int config_parse_interface(void *data, s - - } - -- if ((c = tb[IFACE_ATTR_PREFERRED_LIFETIME])) { -+ if ((c = tb[IFACE_ATTR_MAX_PREFERRED_LIFETIME])) { - double time = parse_leasetime(c); - -- if (time >= 0) -- iface->preferred_lifetime = time; -- else -+ if (time >= 0) { -+ iface->max_preferred_lifetime = time; -+ } else { - syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", -- iface_attrs[IFACE_ATTR_PREFERRED_LIFETIME].name, iface->name); -+ iface_attrs[IFACE_ATTR_MAX_PREFERRED_LIFETIME].name, iface->name); -+ } -+ } - -+ if ((c = tb[IFACE_ATTR_MAX_VALID_LIFETIME])) { -+ double time = parse_leasetime(c); -+ -+ if (time >= 0) { -+ iface->max_valid_lifetime = time; -+ } else { -+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", -+ iface_attrs[IFACE_ATTR_MAX_VALID_LIFETIME].name, iface->name); -+ } - } - - if ((c = tb[IFACE_ATTR_START])) { -@@ -978,9 +990,6 @@ int config_parse_interface(void *data, s - if ((c = tb[IFACE_ATTR_RA_LIFETIME])) - iface->ra_lifetime = blobmsg_get_u32(c); - -- if ((c = tb[IFACE_ATTR_RA_USELEASETIME])) -- iface->ra_useleasetime = blobmsg_get_bool(c); -- - if ((c = tb[IFACE_ATTR_RA_DNS])) - iface->ra_dns = blobmsg_get_bool(c); - ---- a/src/dhcpv6-ia.c -+++ b/src/dhcpv6-ia.c -@@ -120,7 +120,7 @@ static inline bool valid_prefix_length(c - - static inline bool valid_addr(const struct odhcpd_ipaddr *addr, time_t now) - { -- return (addr->prefix <= 96 && addr->preferred > (uint32_t)now); -+ return (addr->prefix <= 96 && addr->valid > (uint32_t)now && addr->preferred > (uint32_t)now); - } - - static size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen) -@@ -1037,17 +1037,27 @@ static size_t build_ia(uint8_t *buf, siz - } - - if (a) { -- uint32_t leasetime, pref; -+ uint32_t leasetime; - - if (a->leasetime) { - leasetime = a->leasetime; -- pref = a->leasetime; - } else { - leasetime = iface->dhcp_leasetime; -- pref = iface->preferred_lifetime; - } - -- uint32_t valid = leasetime; -+ uint32_t floor_preferred_lifetime, floor_valid_lifetime; /* For calculating T1 / T2 */ -+ -+ if (iface->max_preferred_lifetime && iface->max_preferred_lifetime < leasetime) { -+ floor_preferred_lifetime = iface->max_preferred_lifetime; -+ } else { -+ floor_preferred_lifetime = leasetime; -+ } -+ -+ if (iface->max_valid_lifetime && iface->max_valid_lifetime < leasetime) { -+ floor_valid_lifetime = iface->max_valid_lifetime; -+ } else { -+ floor_valid_lifetime = leasetime; -+ } - - struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6; - size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len; -@@ -1071,17 +1081,19 @@ static size_t build_ia(uint8_t *buf, siz - prefix_pref = addrs[i].preferred; - prefix_valid = addrs[i].valid; - -- if (prefix_pref != UINT32_MAX) -+ if (prefix_pref != UINT32_MAX) { - prefix_pref -= now; - -- if (prefix_pref > pref) -- prefix_pref = pref; -+ if (iface->max_preferred_lifetime && prefix_pref > iface->max_preferred_lifetime) -+ prefix_pref = iface->max_preferred_lifetime; -+ } - -- if (prefix_valid != UINT32_MAX) -+ if (prefix_valid != UINT32_MAX) { - prefix_valid -= now; - -- if (prefix_valid > leasetime) -- prefix_valid = leasetime; -+ if (iface->max_valid_lifetime && prefix_valid > iface->max_valid_lifetime) -+ prefix_valid = iface->max_valid_lifetime; -+ } - - if (prefix_pref > prefix_valid) - prefix_pref = prefix_valid; -@@ -1133,24 +1145,24 @@ static size_t build_ia(uint8_t *buf, siz - - /* Calculate T1 / T2 based on non-deprecated addresses */ - if (prefix_pref > 0) { -- if (prefix_pref < pref) -- pref = prefix_pref; -+ if (floor_preferred_lifetime > prefix_pref) -+ floor_preferred_lifetime = prefix_pref; - -- if (prefix_valid < valid) -- valid = prefix_valid; -+ if (floor_valid_lifetime > prefix_valid) -+ floor_valid_lifetime = prefix_valid; - } - } - - if (!INFINITE_VALID(a->valid_until)) - /* UINT32_MAX is considered as infinite leasetime */ -- a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now; -+ a->valid_until = (floor_valid_lifetime == UINT32_MAX) ? 0 : floor_valid_lifetime + now; - - if (!INFINITE_VALID(a->preferred_until)) - /* UINT32_MAX is considered as infinite leasetime */ -- a->preferred_until = (pref == UINT32_MAX) ? 0 : pref + now; -+ a->preferred_until = (floor_preferred_lifetime == UINT32_MAX) ? 0 : floor_preferred_lifetime + now; - -- o_ia.t1 = htonl((pref == UINT32_MAX) ? pref : pref * 5 / 10); -- o_ia.t2 = htonl((pref == UINT32_MAX) ? pref : pref * 8 / 10); -+ o_ia.t1 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 5 / 10); -+ o_ia.t2 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 8 / 10); - - if (!o_ia.t1) - o_ia.t1 = htonl(1); ---- a/src/odhcpd.h -+++ b/src/odhcpd.h -@@ -37,6 +37,10 @@ - // RFC 8781 defines PREF64 option - #define ND_OPT_PREF64 38 - -+// RFC9096 defines recommended option lifetimes configuration values -+#define ND_PREFERRED_LIMIT 2700 -+#define ND_VALID_LIMIT 5400 -+ - #define INFINITE_VALID(x) ((x) == 0) - - #define _unused __attribute__((unused)) -@@ -302,7 +306,6 @@ struct interface { - bool ra_slaac; - bool ra_not_onlink; - bool ra_advrouter; -- bool ra_useleasetime; - bool ra_dns; - uint8_t pref64_length; - struct in6_addr pref64_addr; -@@ -319,7 +322,8 @@ struct interface { - uint32_t ra_retranstime; - uint32_t ra_hoplimit; - int ra_mtu; -- uint32_t preferred_lifetime; -+ uint32_t max_preferred_lifetime; -+ uint32_t max_valid_lifetime; - - // DHCP - uint32_t dhcp_leasetime; ---- a/src/router.c -+++ b/src/router.c -@@ -371,7 +371,7 @@ static int calc_adv_interval(struct inte - - static uint32_t calc_ra_lifetime(struct interface *iface, uint32_t maxival) - { -- uint32_t lifetime = 3*maxival; -+ uint32_t lifetime = maxival * 3; - - if (iface->ra_lifetime >= 0) { - lifetime = iface->ra_lifetime; -@@ -590,16 +590,15 @@ static int send_router_advert(struct int - if (addr->preferred > (uint32_t)now) { - preferred = TIME_LEFT(addr->preferred, now); - -- if (iface->ra_useleasetime && -- preferred > iface->preferred_lifetime) -- preferred = iface->preferred_lifetime; -+ if (iface->max_preferred_lifetime && preferred > iface->max_preferred_lifetime) -+ preferred = iface->max_preferred_lifetime; - } - - if (addr->valid > (uint32_t)now) { - valid = TIME_LEFT(addr->valid, now); - -- if (iface->ra_useleasetime && valid > iface->dhcp_leasetime) -- valid = iface->dhcp_leasetime; -+ if (iface->max_valid_lifetime && valid > iface->max_valid_lifetime) -+ valid = iface->max_valid_lifetime; - } - - if (minvalid > valid) -@@ -643,9 +642,9 @@ static int send_router_advert(struct int - - if (default_route) { - syslog(LOG_WARNING, "A default route is present but there is no public prefix " -- "on %s thus we don't announce a default route by overriding ra_lifetime!", iface->name); -+ "on %s thus we don't announce a default route by setting ra_lifetime to zero!", iface->name); - } else { -- syslog(LOG_WARNING, "No default route present, overriding ra_lifetime!"); -+ syslog(LOG_WARNING, "No default route present, setting ra_lifetime to zero!"); - } - } - -@@ -710,7 +709,7 @@ static int send_router_advert(struct int - - if (iface->pref64_length) { - /* RFC 8781 § 4.1 rounding up lifetime to multiply of 8 */ -- uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : UINT16_MAX; -+ uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : (UINT16_MAX - 7); - uint8_t prefix_length_code; - uint32_t mask_a1, mask_a2; - diff --git a/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch b/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch index f62f283b7..93ad88e83 100644 --- a/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch +++ b/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch @@ -1,6 +1,6 @@ --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js -@@ -889,6 +889,20 @@ return view.extend({ +@@ -847,6 +847,20 @@ return view.extend({ so.depends('ra', 'server'); so.depends({ ra: 'hybrid', master: '0' }); diff --git a/openwrt/patch/openwrt-6.x/dwarves/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch b/openwrt/patch/openwrt-6.x/dwarves/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch deleted file mode 100644 index 002f10fa3..000000000 --- a/openwrt/patch/openwrt-6.x/dwarves/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/btf_encoder.c -+++ b/btf_encoder.c -@@ -394,7 +394,7 @@ static int32_t btf_encoder__add_base_typ - * these non-regular int types to avoid libbpf/kernel complaints. - */ - byte_sz = BITS_ROUNDUP_BYTES(bt->bit_size); -- if (!byte_sz || (byte_sz & (byte_sz - 1))) { -+ if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 16) { - name = "__SANITIZED_FAKE_INT__"; - byte_sz = 4; - } diff --git a/openwrt/patch/openwrt-6.x/gcc-14/README.md b/openwrt/patch/openwrt-6.x/gcc-14/README.md deleted file mode 100644 index fa77ba492..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/README.md +++ /dev/null @@ -1 +0,0 @@ -### Fix build with Gcc 14 \ No newline at end of file diff --git a/openwrt/patch/openwrt-6.x/gcc-14/grub2/900-fix-incompatible-pointer-type.patch b/openwrt/patch/openwrt-6.x/gcc-14/grub2/900-fix-incompatible-pointer-type.patch deleted file mode 100644 index 2588b30ce..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/grub2/900-fix-incompatible-pointer-type.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -394,9 +394,9 @@ luks2_verify_key (grub_luks2_digest_t *d - gcry_err_code_t gcry_ret; - - /* Decode both digest and salt */ -- if (!base64_decode (d->digest, grub_strlen (d->digest), (char *)digest, &digestlen)) -+ if (!base64_decode (d->digest, grub_strlen (d->digest), (char *)digest, (size_t *)&digestlen)) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid digest"); -- if (!base64_decode (d->salt, grub_strlen (d->salt), (char *)salt, &saltlen)) -+ if (!base64_decode (d->salt, grub_strlen (d->salt), (char *)salt, (size_t *)&saltlen)) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid digest salt"); - - /* Configure the hash used for the digest. */ -@@ -435,7 +435,7 @@ luks2_decrypt_key (grub_uint8_t *out_key - grub_err_t ret; - - if (!base64_decode (k->kdf.salt, grub_strlen (k->kdf.salt), -- (char *)salt, &saltlen)) -+ (char *)salt, (size_t *)&saltlen)) - { - ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid keyslot salt"); - goto err; diff --git a/openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch b/openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch deleted file mode 100644 index 061e7c477..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/tests/include/test/macros.h -+++ b/tests/include/test/macros.h -@@ -135,8 +135,8 @@ - do { \ - TEST_ASSERT((pointer) == NULL); \ - if ((item_count) != 0) { \ -- (pointer) = mbedtls_calloc(sizeof(*(pointer)), \ -- (item_count)); \ -+ (pointer) = mbedtls_calloc((item_count), \ -+ sizeof(*(pointer))); \ - TEST_ASSERT((pointer) != NULL); \ - } \ - } while (0) -@@ -153,8 +153,8 @@ - do { \ - TEST_ASSERT((pointer) == NULL); \ - if ((item_count) != 0) { \ -- (pointer) = mbedtls_calloc(sizeof(*(pointer)), \ -- (item_count)); \ -+ (pointer) = mbedtls_calloc((item_count), \ -+ sizeof(*(pointer))); \ - TEST_ASSUME((pointer) != NULL); \ - } \ - } while (0) diff --git a/openwrt/patch/openwrt-6.x/gcc-14/openvswitch/0008-ovs-atomic-Fix-inclusion-of-Clang-header-by-GCC-14.patch b/openwrt/patch/openwrt-6.x/gcc-14/openvswitch/0008-ovs-atomic-Fix-inclusion-of-Clang-header-by-GCC-14.patch deleted file mode 100644 index e61211a20..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/openvswitch/0008-ovs-atomic-Fix-inclusion-of-Clang-header-by-GCC-14.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 1c31a87ef6e16f2bcf6b81f5e1bf369c97db0537 Mon Sep 17 00:00:00 2001 -From: Ilya Maximets -Date: Thu, 18 Jan 2024 15:59:05 +0100 -Subject: [PATCH] ovs-atomic: Fix inclusion of Clang header by GCC 14. - -GCC 14 started to advertise c_atomic extension, older versions didn't -do that. Add check for __clang__, so GCC doesn't include headers -designed for Clang. - -Another option would be to prefer stdatomic implementation instead, -but some older versions of Clang are not able to use stdatomic.h -supplied by GCC as described in commit: - 07ece367fb5f ("ovs-atomic: Prefer Clang intrinsics over .") - -This change fixes OVS build with GCC on Fedora Rawhide (40). - -Reported-by: Jakob Meng -Acked-by: Jakob Meng -Acked-by: Eelco Chaudron -Acked-by: Simon Horman -Signed-off-by: Ilya Maximets ---- - lib/ovs-atomic.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/lib/ovs-atomic.h -+++ b/lib/ovs-atomic.h -@@ -329,7 +329,7 @@ - #if __CHECKER__ - /* sparse doesn't understand some GCC extensions we use. */ - #include "ovs-atomic-pthreads.h" -- #elif __has_extension(c_atomic) -+ #elif __clang__ && __has_extension(c_atomic) - #include "ovs-atomic-clang.h" - #elif HAVE_ATOMIC && __cplusplus >= 201103L - #include "ovs-atomic-c++.h" diff --git a/openwrt/patch/openwrt-6.x/gcc-14/perl/1000-fix-implicit-declaration-error.patch b/openwrt/patch/openwrt-6.x/gcc-14/perl/1000-fix-implicit-declaration-error.patch deleted file mode 100644 index 76de471c8..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/perl/1000-fix-implicit-declaration-error.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- a/ext/POSIX/POSIX.xs -+++ b/ext/POSIX/POSIX.xs -@@ -36,11 +36,6 @@ static int not_here(const char *s); - #include - #endif - #include --#ifdef I_FENV --#if !(defined(__vax__) && defined(__NetBSD__)) --#include --#endif --#endif - #include - #include - #include -@@ -51,6 +46,7 @@ static int not_here(const char *s); - #include - #include - #include -+#include - - #ifdef I_UNISTD - #include diff --git a/openwrt/patch/openwrt-6.x/gcc-14/screen/900-fix-implicit-function-declaration.patch b/openwrt/patch/openwrt-6.x/gcc-14/screen/900-fix-implicit-function-declaration.patch deleted file mode 100644 index 16040e3f9..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/screen/900-fix-implicit-function-declaration.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/pty.c -+++ b/pty.c -@@ -51,11 +51,7 @@ - # include - #endif - --#ifdef ISC --# include --# include --# include --#endif -+#include - - #ifdef sgi - # include diff --git a/openwrt/patch/openwrt-6.x/gcc-14/wsdd2/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch b/openwrt/patch/openwrt-6.x/gcc-14/wsdd2/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch deleted file mode 100644 index 8c1e06178..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/wsdd2/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch +++ /dev/null @@ -1,23 +0,0 @@ -From bf77439f043c5df7102dc266b55e86ec524d17ee Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 13 Mar 2024 08:33:57 +0800 -Subject: [PATCH] wsdd2: cast from pointer to integer of different size - -* fix build with gcc 14 - -Signed-off-by: sbwml ---- - wsdd2.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/wsdd2.c -+++ b/wsdd2.c -@@ -543,7 +543,7 @@ static int netlink_recv(struct endpoint - char buf[PAGE_SIZE]; - struct sockaddr_nl sa; - struct iovec iov = { buf, sizeof buf }; -- struct msghdr msg = { &sa, sizeof sa, &iov, 1, NULL, 0, 0 }; -+ struct msghdr msg = { &sa, sizeof sa, &iov, 1, (intptr_t)NULL, 0, 0 }; - ssize_t msglen = recvmsg(ep->sock, &msg, 0); - - DEBUG(2, W, "%s: %zd bytes", __func__, msglen); diff --git a/openwrt/patch/openwrt-6.x/gcc-14/xdp-tools/900-Fix-transposed-calloc-arguments.patch b/openwrt/patch/openwrt-6.x/gcc-14/xdp-tools/900-Fix-transposed-calloc-arguments.patch deleted file mode 100644 index 144f3c813..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-14/xdp-tools/900-Fix-transposed-calloc-arguments.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/lib/util/xpcapng.c -+++ b/lib/util/xpcapng.c -@@ -226,7 +226,7 @@ static bool pcapng_write_shb(struct xpca - shb_length += sizeof(uint32_t); - - /* Allocate the SHB and fill it. */ -- shb = calloc(shb_length, 1); -+ shb = calloc(1, shb_length); - if (shb == NULL) { - errno = ENOMEM; - return false; -@@ -318,7 +318,7 @@ static bool pcapng_write_idb(struct xpca - idb_length += sizeof(uint32_t); - - /* Allocate the IDB and fill it. */ -- idb = calloc(idb_length, 1); -+ idb = calloc(1, idb_length); - if (idb == NULL) { - errno = ENOMEM; - return false; -@@ -549,7 +549,7 @@ struct xpcapng_dumper *xpcapng_dump_open - goto error_exit; - } - -- pd = calloc(sizeof(*pd), 1); -+ pd = calloc(1, sizeof(*pd)); - if (pd == NULL) { - errno = ENOMEM; - goto error_exit; diff --git a/openwrt/patch/openwrt-6.x/iwinfo/0001-devices-add-MediaTek-MT7922-device-id.patch b/openwrt/patch/openwrt-6.x/iwinfo/0001-devices-add-MediaTek-MT7922-device-id.patch deleted file mode 100644 index 56cfedfef..000000000 --- a/openwrt/patch/openwrt-6.x/iwinfo/0001-devices-add-MediaTek-MT7922-device-id.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0a38971e811573c65ab586aff19a5129b0d74479 Mon Sep 17 00:00:00 2001 -From: Marty Jones -Date: Fri, 18 Nov 2022 14:50:16 -0500 -Subject: [PATCH 46/52] iwinfo: add hardware id for MT7922 devices - -Signed-off-by: Marty Jones ---- - devices.txt | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/devices.txt b/devices.txt -index 82d8421..04b21e7 100644 ---- a/devices.txt -+++ b/devices.txt -@@ -189,6 +189,7 @@ - 0x14c3 0x7650 0x14c3 0x7650 0 0 "MediaTek" "MT7610E" - 0x14c3 0x7662 0x14c3 0x7662 0 0 "MediaTek" "MT76x2E" - 0x14c3 0x7915 0x14c3 0x7915 0 0 "MediaTek" "MT7915E" -+0x14c3 0x7922 0x1A3B 0x5300 0 0 "MediaTek" "MT7922" - 0x14e4 0xaa52 0x14e4 0xaa52 0 0 "Broadcom" "BCM43602" - 0x02d0 0xa9a6 0x0000 0x0000 0 0 "Cypress" "CYW43455" - 0x1ae9 0x0310 0x1ae9 0x0000 0 0 "Wilocity" "Wil6210" --- -2.38.1 - diff --git a/openwrt/patch/openwrt-6.x/iwinfo/0004-add-rtl8812au-devices.patch b/openwrt/patch/openwrt-6.x/iwinfo/0004-add-rtl8812au-devices.patch deleted file mode 100644 index 43feb6412..000000000 --- a/openwrt/patch/openwrt-6.x/iwinfo/0004-add-rtl8812au-devices.patch +++ /dev/null @@ -1,86 +0,0 @@ -diff --git a/devices.txt b/devices.txt -index 82d8421..f4408c2 100644 ---- a/devices.txt -+++ b/devices.txt -@@ -192,6 +192,7 @@ - 0x14e4 0xaa52 0x14e4 0xaa52 0 0 "Broadcom" "BCM43602" - 0x02d0 0xa9a6 0x0000 0x0000 0 0 "Cypress" "CYW43455" - 0x1ae9 0x0310 0x1ae9 0x0000 0 0 "Wilocity" "Wil6210" -+0x02d0 0xa9bf 0x0000 0x0000 0 0 "Broadcom" "BCM43456" - - # USB devices - # 0x0000 | 0x0000 | vendor id | product id | ... -@@ -236,7 +237,72 @@ - # mt7615/usb.c - 0x0000 0x0000 0x0e8d 0x7663 0 0 "MediaTek" "MT7663U" - 0x0000 0x0000 0x043e 0x310c 0 0 "LG" "LGSBWAC02" -- -+# RTL8812A -+0x0000 0x0000 0x0409 0x0408 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x0411 0x025D 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x04BB 0x0952 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x050D 0x1106 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x050D 0x1109 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x0586 0x3426 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x0789 0x016E 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x07B8 0x8812 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x0846 0x9051 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x0B05 0x17D2 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x0DF6 0x0074 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x0E66 0x0022 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x1058 0x0632 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x13B1 0x003F 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x148F 0x9097 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x1740 0x0100 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2001 0x330E 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2001 0x3313 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2001 0x3315 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2001 0x3316 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2019 0xAB30 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x20F4 0x805B 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2357 0x0101 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2357 0x0103 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2357 0x010D 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2357 0x010E 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2357 0x010F 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2357 0x0122 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x2604 0x0012 0 0 "Realtek" "RTL8812" -+0x0000 0x0000 0x7392 0xA822 0 0 "Realtek" "RTL8812" -+# RTL8814A -+0x0000 0x0000 0x0B05 0x1817 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x0B05 0x1852 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x0B05 0x1853 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x056E 0x400B 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x056E 0x400D 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x0846 0x9054 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x0E66 0x0026 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x2001 0x331A 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x20F4 0x809A 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x20F4 0x809B 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x2357 0x0106 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x7392 0xA834 0 0 "Realtek" "RTL8814A" -+0x0000 0x0000 0x7392 0xA833 0 0 "Realtek" "RTL8814A" -+# RTL8821A -+0x0000 0x0000 0x0bda 0x0811 0 0 "Realtek" "RTL8821" /* Alfa AWUS036ACS */ -+0x0000 0x0000 0x0411 0x0242 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x0411 0x029B 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x04BB 0x0953 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x056E 0x4007 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x056E 0x400E 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x056E 0x400F 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x0846 0x9052 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x0E66 0x0023 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x2001 0x3314 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x2001 0x3318 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x2019 0xAB32 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x2357 0x011E 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x2357 0x011F 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x2357 0x0120 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x3823 0x6249 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x7392 0xA811 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x7392 0xA812 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x7392 0xA813 0 0 "Realtek" "RTL8821" -+0x0000 0x0000 0x7392 0xB611 0 0 "Realtek" "RTL8821" - # FDT compatible strings - # "compatible" | txpower offset | frequency offset | ... - "qca,ar9130-wmac" 0 0 "Atheros" "AR9130" diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.6 b/openwrt/patch/openwrt-6.x/x86/64/config-6.6 deleted file mode 100644 index 689689ee9..000000000 --- a/openwrt/patch/openwrt-6.x/x86/64/config-6.6 +++ /dev/null @@ -1,663 +0,0 @@ -CONFIG_64BIT=y -# CONFIG_ACER_WMI is not set -CONFIG_ACPI=y -CONFIG_ACPI_AC=y -CONFIG_ACPI_BATTERY=y -# CONFIG_ACPI_BGRT is not set -CONFIG_ACPI_BUTTON=y -# CONFIG_ACPI_CMPC is not set -CONFIG_ACPI_CONTAINER=y -CONFIG_ACPI_CPPC_LIB=y -CONFIG_ACPI_CPU_FREQ_PSS=y -# CONFIG_ACPI_DEBUG is not set -# CONFIG_ACPI_DEBUGGER is not set -# CONFIG_ACPI_DOCK is not set -# CONFIG_ACPI_DPTF is not set -# CONFIG_ACPI_EC_DEBUGFS is not set -CONFIG_ACPI_FAN=y -# CONFIG_ACPI_FFH is not set -# CONFIG_ACPI_FPDT is not set -CONFIG_ACPI_HOTPLUG_CPU=y -CONFIG_ACPI_HOTPLUG_IOAPIC=y -# CONFIG_ACPI_I2C_OPREGION is not set -CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y -CONFIG_ACPI_LPIT=y -CONFIG_ACPI_PCC=y -# CONFIG_ACPI_PCI_SLOT is not set -# CONFIG_ACPI_PFRUT is not set -CONFIG_ACPI_PRMT=y -CONFIG_ACPI_PROCESSOR=y -# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set -CONFIG_ACPI_PROCESSOR_CSTATE=y -CONFIG_ACPI_PROCESSOR_IDLE=y -CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y -# CONFIG_ACPI_SBS is not set -CONFIG_ACPI_SPCR_TABLE=y -CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y -# CONFIG_ACPI_TAD is not set -CONFIG_ACPI_THERMAL=y -# CONFIG_ACPI_TOSHIBA is not set -CONFIG_ACPI_VIDEO=y -CONFIG_ACPI_VIOT=y -# CONFIG_ACPI_WMI is not set -# CONFIG_ACRN_GUEST is not set -# CONFIG_ADDRESS_MASKING is not set -# CONFIG_ADV_SWBUTTON is not set -CONFIG_AGP=y -# CONFIG_AGP_AMD64 is not set -CONFIG_AGP_INTEL=y -# CONFIG_AGP_SIS is not set -# CONFIG_AGP_VIA is not set -# CONFIG_AMD_HSMP is not set -# CONFIG_AMD_SFH_HID is not set -CONFIG_AMD_IOMMU=y -CONFIG_AMD_IOMMU_V2=y -# CONFIG_AMD_PMC is not set -# CONFIG_AMD_PMF is not set -# CONFIG_AMD_PTDMA is not set -CONFIG_APERTURE_HELPERS=y -CONFIG_ARCH_CPUIDLE_HALTPOLL=y -CONFIG_ARCH_DMA_ADDR_T_64BIT=y -CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y -CONFIG_ARCH_MMAP_RND_BITS=28 -CONFIG_ARCH_MMAP_RND_BITS_MAX=32 -CONFIG_ARCH_MMAP_RND_BITS_MIN=28 -CONFIG_ARCH_SPARSEMEM_DEFAULT=y -CONFIG_ARCH_WANTS_THP_SWAP=y -# CONFIG_ASUS_TF103C_DOCK is not set -# CONFIG_ASUS_WMI is not set -CONFIG_AUDIT_ARCH=y -CONFIG_AUXILIARY_BUS=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -CONFIG_BALLOON_COMPACTION=y -CONFIG_BLK_DEV_BSGLIB=y -CONFIG_BLK_DEV_BSG_COMMON=y -CONFIG_BLK_DEV_INTEGRITY=y -CONFIG_BLK_DEV_INTEGRITY_T10=y -CONFIG_BLK_DEV_NVME=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_MQ_VIRTIO=y -CONFIG_BLK_PM=y -CONFIG_BOOT_VESA_SUPPORT=y -CONFIG_BTT=y -CONFIG_CALL_DEPTH_TRACKING=y -CONFIG_CALL_PADDING=y -CONFIG_CALL_THUNKS=y -# CONFIG_CALL_THUNKS_DEBUG is not set -CONFIG_CDROM=y -CONFIG_CONNECTOR=y -CONFIG_CONTEXT_TRACKING=y -CONFIG_CONTEXT_TRACKING_IDLE=y -CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y -CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y -CONFIG_CPU_IBPB_ENTRY=y -CONFIG_CPU_IBRS_ENTRY=y -# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set -CONFIG_CPU_RMAP=y -CONFIG_CPU_SRSO=y -CONFIG_CPU_UNRET_ENTRY=y -CONFIG_CRC64=y -CONFIG_CRC64_ROCKSOFT=y -CONFIG_CRC_T10DIF=y -CONFIG_CRYPTO_AES_NI_INTEL=y -CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y -# CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64 is not set -# CONFIG_CRYPTO_ARIA_AESNI_AVX2_X86_64 is not set -# CONFIG_CRYPTO_ARIA_GFNI_AVX512_X86_64 is not set -CONFIG_CRYPTO_BLAKE2S_X86=y -# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set -# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set -# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set -# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set -# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set -# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set -CONFIG_CRYPTO_CRC64_ROCKSOFT=y -CONFIG_CRYPTO_CRCT10DIF=y -# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set -CONFIG_CRYPTO_CRYPTD=y -# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 -CONFIG_CRYPTO_LRW=y -# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set -# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set -# CONFIG_CRYPTO_POLYVAL_CLMUL_NI is not set -# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set -# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set -# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set -# CONFIG_CRYPTO_SHA1_SSSE3 is not set -# CONFIG_CRYPTO_SHA256_SSSE3 is not set -# CONFIG_CRYPTO_SHA512_SSSE3 is not set -CONFIG_CRYPTO_SIMD=y -# CONFIG_CRYPTO_SM3_AVX_X86_64 is not set -# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set -# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set -# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set -# CONFIG_CRYPTO_TWOFISH_X86_64 is not set -# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set -CONFIG_CRYPTO_XTS=y -CONFIG_DMAR_TABLE=y -CONFIG_DMA_ACPI=y -CONFIG_DMA_OPS=y -CONFIG_DMA_SHARED_BUFFER=y -# CONFIG_DRM_AMDGPU_WERROR is not set -# CONFIG_DRM_AMD_SECURE_DISPLAY is not set -CONFIG_DRM=y -CONFIG_DRM_BOCHS=y -CONFIG_DRM_BRIDGE=y -CONFIG_DRM_BUDDY=y -CONFIG_DRM_DISPLAY_DP_HELPER=y -CONFIG_DRM_DISPLAY_HDCP_HELPER=y -CONFIG_DRM_DISPLAY_HDMI_HELPER=y -CONFIG_DRM_DISPLAY_HELPER=y -CONFIG_DRM_FBDEV_EMULATION=y -CONFIG_DRM_FBDEV_OVERALLOC=100 -CONFIG_DRM_GEM_SHMEM_HELPER=y -# CONFIG_DRM_HYPERV is not set -CONFIG_DRM_I915_FORCE_PROBE="" -CONFIG_DRM_I915_REQUEST_TIMEOUT=20000 -CONFIG_DRM_I915_FENCE_TIMEOUT=10000 -CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 -CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500 -CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 -CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000 -CONFIG_DRM_I915_STOP_TIMEOUT=100 -CONFIG_DRM_I915_TIMESLICE_DURATION=1 -CONFIG_DRM_KMS_HELPER=y -CONFIG_DRM_MIPI_DSI=y -CONFIG_DRM_PANEL=y -CONFIG_DRM_PANEL_BRIDGE=y -CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y -CONFIG_DRM_TTM=y -CONFIG_DRM_TTM_HELPER=y -CONFIG_DRM_VIRTIO_GPU=y -CONFIG_DRM_VIRTIO_GPU_KMS=y -CONFIG_DRM_VRAM_HELPER=y -CONFIG_DYNAMIC_PHYSICAL_MASK=y -CONFIG_EFI=y -CONFIG_EFIVAR_FS=m -# CONFIG_EFI_BOOTLOADER_CONTROL is not set -# CONFIG_EFI_CAPSULE_LOADER is not set -# CONFIG_EFI_COCO_SECRET is not set -# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set -# CONFIG_EFI_DISABLE_PCI_DMA is not set -# CONFIG_EFI_DISABLE_RUNTIME is not set -CONFIG_EFI_DXE_MEM_ATTRIBUTES=y -CONFIG_EFI_EARLYCON=y -CONFIG_EFI_ESRT=y -# CONFIG_EFI_FAKE_MEMMAP is not set -CONFIG_EFI_HANDOVER_PROTOCOL=y -# CONFIG_EFI_MIXED is not set -# CONFIG_EFI_PGT_DUMP is not set -# CONFIG_EFI_RCI2_TABLE is not set -CONFIG_EFI_RUNTIME_MAP=y -CONFIG_EFI_RUNTIME_WRAPPERS=y -# CONFIG_EFI_SECRET is not set -CONFIG_EFI_STUB=y -# CONFIG_EFI_TEST is not set -# CONFIG_EFI_VARS is not set -# CONFIG_EFI_VARS_PSTORE is not set -# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set -CONFIG_FAILOVER=y -CONFIG_FB=y -CONFIG_FB_CFB_COPYAREA=y -CONFIG_FB_CFB_FILLRECT=y -CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_CORE=y -CONFIG_FB_DEFERRED_IO=y -CONFIG_FB_DEVICE=y -CONFIG_FB_EFI=y -CONFIG_FB_HYPERV=y -# CONFIG_FB_INTEL is not set -CONFIG_FB_IOMEM_FOPS=y -CONFIG_FB_IOMEM_HELPERS=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_SIMPLE=y -CONFIG_FB_SYSMEM_HELPERS=y -CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y -CONFIG_FB_SYS_COPYAREA=y -CONFIG_FB_SYS_FILLRECT=y -CONFIG_FB_SYS_FOPS=y -CONFIG_FB_SYS_IMAGEBLIT=y -CONFIG_FB_TILEBLITTING=y -# CONFIG_FB_VESA is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y -CONFIG_FONT_SUPPORT=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y -# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -CONFIG_FREEZER=y -CONFIG_FUSION_SAS=y -CONFIG_FW_CACHE=y -CONFIG_GART_IOMMU=y -CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y -CONFIG_GENERIC_CPU=y -CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y -CONFIG_GENERIC_IRQ_MIGRATION=y -CONFIG_GENERIC_PENDING_IRQ=y -CONFIG_GENERIC_PINCONF=y -# CONFIG_GIGABYTE_WMI is not set -# CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT is not set -# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set -# CONFIG_GOOGLE_SMI is not set -CONFIG_GPIOLIB_IRQCHIP=y -CONFIG_GPIO_ACPI=y -CONFIG_GPIO_ICH=y -CONFIG_GPIO_SCH=y -CONFIG_GUEST_PERF_EVENTS=y -CONFIG_HALTPOLL_CPUIDLE=y -CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y -CONFIG_HDMI=y -CONFIG_HIBERNATE_CALLBACKS=y -CONFIG_HID_BATTERY_STRENGTH=y -CONFIG_HID_GENERIC=y -CONFIG_HID_HYPERV_MOUSE=y -CONFIG_HOTPLUG_CORE_SYNC=y -CONFIG_HOTPLUG_CORE_SYNC_DEAD=y -CONFIG_HOTPLUG_CORE_SYNC_FULL=y -CONFIG_HOTPLUG_CPU=y -CONFIG_HOTPLUG_PARALLEL=y -CONFIG_HOTPLUG_PCI=y -CONFIG_HOTPLUG_PCI_ACPI=y -# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set -# CONFIG_HOTPLUG_PCI_CPCI is not set -# CONFIG_HOTPLUG_PCI_PCIE is not set -# CONFIG_HOTPLUG_PCI_SHPC is not set -CONFIG_HOTPLUG_SMT=y -CONFIG_HOTPLUG_SPLIT_STARTUP=y -CONFIG_HPET=y -CONFIG_HPET_MMAP=y -# CONFIG_HP_ACCEL is not set -# CONFIG_HUAWEI_WMI is not set -CONFIG_HVC_DRIVER=y -CONFIG_HVC_IRQ=y -CONFIG_HVC_XEN=y -CONFIG_HVC_XEN_FRONTEND=y -CONFIG_HWMON=y -CONFIG_HWMON_VID=y -CONFIG_HW_RANDOM_AMD=y -CONFIG_HW_RANDOM_INTEL=y -CONFIG_HW_RANDOM_VIRTIO=y -CONFIG_HYPERV=y -CONFIG_HYPERVISOR_GUEST=y -CONFIG_HYPERV_BALLOON=y -CONFIG_HYPERV_IOMMU=y -CONFIG_HYPERV_KEYBOARD=y -CONFIG_HYPERV_NET=y -CONFIG_HYPERV_STORAGE=y -# CONFIG_HYPERV_TESTING is not set -CONFIG_HYPERV_TIMER=y -CONFIG_HYPERV_UTILS=y -# CONFIG_HYPERV_VSOCKETS is not set -# CONFIG_HYPERV_VTL_MODE is not set -CONFIG_I2C=y -CONFIG_I2C_ALGOBIT=y -# CONFIG_I2C_AMD_MP2 is not set -CONFIG_I2C_BOARDINFO=y -# CONFIG_I2C_HID_ACPI is not set -# CONFIG_I2C_MULTI_INSTANTIATE is not set -# CONFIG_I8K is not set -# CONFIG_IA32_EMULATION is not set -CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 -# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set -CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y -CONFIG_INTEL_GTT=y -CONFIG_INTEL_IDLE=y -# CONFIG_INTEL_IDXD is not set -# CONFIG_INTEL_IDXD_COMPAT is not set -# CONFIG_INTEL_IFS is not set -CONFIG_INTEL_IOMMU=y -# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set -CONFIG_INTEL_IOMMU_FLOPPY_WA=y -CONFIG_INTEL_IOMMU_PERF_EVENTS=y -# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set -# CONFIG_INTEL_IOMMU_SVM is not set -# CONFIG_INTEL_IPS is not set -# CONFIG_INTEL_MEI_GSC_PROXY is not set -# CONFIG_INTEL_MEI_HDCP is not set -# CONFIG_INTEL_MEI_PXP is not set -# CONFIG_INTEL_MENLOW is not set -CONFIG_INTEL_PCH_THERMAL=y -# CONFIG_INTEL_SAR_INT1092 is not set -# CONFIG_INTEL_SCU_PLATFORM is not set -CONFIG_INTEL_SOC_DTS_IOSF_CORE=y -CONFIG_INTEL_SOC_DTS_THERMAL=y -# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set -CONFIG_INTEL_TCC=y -CONFIG_INTEL_TDX_GUEST=y -# CONFIG_INTEL_TURBO_MAX_3 is not set -# CONFIG_INTEL_TXT is not set -# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set -# CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set -# CONFIG_INTEL_WMI_THUNDERBOLT is not set -CONFIG_INTERVAL_TREE=y -# CONFIG_IOMMUFD is not set -CONFIG_IOMMU_API=y -# CONFIG_IOMMU_DEBUG is not set -# CONFIG_IOMMU_DEBUGFS is not set -CONFIG_IOMMU_DEFAULT_DMA_LAZY=y -# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set -# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set -CONFIG_IOMMU_DMA=y -CONFIG_IOMMU_HELPER=y -CONFIG_IOMMU_IOVA=y -CONFIG_IOMMU_IO_PGTABLE=y -CONFIG_IOMMU_SUPPORT=y -# CONFIG_IOMMUFD is not set -CONFIG_IOSF_MBI=y -# CONFIG_IOSF_MBI_DEBUG is not set -# CONFIG_IPU_BRIDGE is not set -CONFIG_IRQ_MSI_IOMMU=y -CONFIG_IRQ_REMAP=y -# CONFIG_ISCSI_IBFT is not set -CONFIG_ISO9660_FS=y -CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y -CONFIG_KCMP=y -# CONFIG_KMSAN is not set -CONFIG_KVM_GUEST=y -# CONFIG_KVM_XEN is not set -CONFIG_LEDS_GPIO=y -# CONFIG_LEGACY_VSYSCALL_EMULATE is not set -CONFIG_LEGACY_VSYSCALL_NONE=y -# CONFIG_LEGACY_VSYSCALL_XONLY is not set -# CONFIG_LENOVO_YMC is not set -# CONFIG_LG_LAPTOP is not set -CONFIG_LIBNVDIMM=y -CONFIG_LOCK_SPIN_ON_OWNER=y -CONFIG_LPC_ICH=y -CONFIG_LPC_SCH=y -CONFIG_MAILBOX=y -# CONFIG_MAXSMP is not set -CONFIG_MEMORY_BALLOON=y -CONFIG_MEMREGION=y -# CONFIG_MERAKI_MX100 is not set -CONFIG_MFD_CORE=y -# CONFIG_MFD_INTEL_LPSS_ACPI is not set -# CONFIG_MFD_INTEL_PMC_BXT is not set -CONFIG_MMC=y -CONFIG_MMC_BLOCK=y -CONFIG_MMC_CQHCI=y -CONFIG_MMC_RICOH_MMC=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_ACPI=y -CONFIG_MMC_SDHCI_IO_ACCESSORS=y -CONFIG_MMC_SDHCI_PCI=y -# CONFIG_MMC_SDHCI_PLTFM is not set -# CONFIG_MMC_WBSD is not set -CONFIG_MMU_NOTIFIER=y -CONFIG_MODULES_USE_ELF_RELA=y -# CONFIG_MPSC is not set -# CONFIG_MSI_EC is not set -# CONFIG_MSI_WMI is not set -CONFIG_MUTEX_SPIN_ON_OWNER=y -# CONFIG_MXM_WMI is not set -CONFIG_ND_CLAIM=y -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEED_SG_DMA_FLAGS=y -CONFIG_NET_FAILOVER=y -CONFIG_NET_FLOW_LIMIT=y -CONFIG_NET_PTP_CLASSIFY=y -# CONFIG_NITRO_ENCLAVES is not set -CONFIG_NR_CPUS=512 -CONFIG_NR_CPUS_DEFAULT=64 -CONFIG_NR_CPUS_RANGE_BEGIN=2 -CONFIG_NR_CPUS_RANGE_END=512 -# CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set -CONFIG_NVME_CORE=y -CONFIG_NVME_HWMON=y -CONFIG_NVME_MULTIPATH=y -CONFIG_OBJTOOL=y -CONFIG_OUTPUT_FORMAT="elf64-x86-64" -CONFIG_P2SB=y -CONFIG_PADATA=y -CONFIG_PAGE_REPORTING=y -CONFIG_PAGE_TABLE_ISOLATION=y -CONFIG_PARAVIRT=y -CONFIG_PARAVIRT_CLOCK=y -# CONFIG_PARAVIRT_DEBUG is not set -CONFIG_PARAVIRT_SPINLOCKS=y -CONFIG_PARAVIRT_XXL=y -CONFIG_PATA_AMD=y -CONFIG_PATA_ATIIXP=y -CONFIG_PATA_MPIIX=y -CONFIG_PATA_OLDPIIX=y -CONFIG_PATA_TIMINGS=y -CONFIG_PATA_VIA=y -CONFIG_PCC=y -# CONFIG_PCENGINES_APU2 is not set -CONFIG_PCIEAER=y -CONFIG_PCIEASPM=y -CONFIG_PCIEASPM_DEFAULT=y -# CONFIG_PCIEASPM_PERFORMANCE is not set -# CONFIG_PCIEASPM_POWERSAVE is not set -# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set -CONFIG_PCIEPORTBUS=y -CONFIG_PCIE_PME=y -CONFIG_PCI_HYPERV=y -CONFIG_PCI_HYPERV_INTERFACE=y -# CONFIG_PCI_MMCONFIG is not set -CONFIG_PCI_PASID=y -CONFIG_PCI_PRI=y -CONFIG_PCI_XEN=y -CONFIG_PER_VMA_LOCK=y -CONFIG_PGTABLE_LEVELS=4 -CONFIG_PHYSICAL_ALIGN=0x1000000 -CONFIG_PHYS_ADDR_T_64BIT=y -CONFIG_PINCTRL=y -CONFIG_PINCTRL_ALDERLAKE=y -CONFIG_PINCTRL_BAYTRAIL=y -CONFIG_PINCTRL_BROXTON=y -CONFIG_PINCTRL_CANNONLAKE=y -CONFIG_PINCTRL_CHERRYVIEW=y -CONFIG_PINCTRL_DENVERTON=y -CONFIG_PINCTRL_ELKHARTLAKE=y -CONFIG_PINCTRL_EMMITSBURG=y -CONFIG_PINCTRL_GEMINILAKE=y -CONFIG_PINCTRL_INTEL=y -CONFIG_PINCTRL_JASPERLAKE=y -CONFIG_PINCTRL_LAKEFIELD=y -CONFIG_PINCTRL_LEWISBURG=y -CONFIG_PINCTRL_LYNXPOINT=y -CONFIG_PINCTRL_METEORLAKE=y -CONFIG_PINCTRL_SUNRISEPOINT=y -CONFIG_PINCTRL_TIGERLAKE=y -CONFIG_PM=y -# CONFIG_PMIC_OPREGION is not set -CONFIG_PM_CLK=y -CONFIG_PM_SLEEP=y -CONFIG_PM_SLEEP_SMP=y -CONFIG_PNP=y -CONFIG_PNPACPI=y -CONFIG_PNP_DEBUG_MESSAGES=y -CONFIG_PPS=y -CONFIG_PREFIX_SYMBOLS=y -CONFIG_PROC_EVENTS=y -CONFIG_PTP_1588_CLOCK=y -CONFIG_PTP_1588_CLOCK_KVM=y -CONFIG_PTP_1588_CLOCK_VMW=y -CONFIG_PVH=y -CONFIG_QUEUED_RWLOCKS=y -CONFIG_QUEUED_SPINLOCKS=y -CONFIG_RAS=y -CONFIG_RELAY=y -CONFIG_RELOCATABLE=y -CONFIG_RESET_ATTACK_MITIGATION=y -CONFIG_RFS_ACCEL=y -CONFIG_RPS=y -CONFIG_RTC_I2C_AND_SPI=y -CONFIG_RWSEM_SPIN_ON_OWNER=y -# CONFIG_SAMSUNG_Q10 is not set -CONFIG_SATA_AHCI=y -# CONFIG_SCHED_CORE is not set -CONFIG_SCHED_MC=y -CONFIG_SCHED_MC_PRIO=y -CONFIG_SCHED_SMT=y -CONFIG_SCSI_SAS_ATTRS=y -CONFIG_SCSI_VIRTIO=y -# CONFIG_SEL3350_PLATFORM is not set -# CONFIG_SENSORS_ASUS_EC is not set -# CONFIG_SENSORS_ASUS_WMI is not set -CONFIG_SENSORS_CORETEMP=y -CONFIG_SENSORS_FAM15H_POWER=y -# CONFIG_SENSORS_HP_WMI is not set -CONFIG_SENSORS_I5500=y -CONFIG_SENSORS_K10TEMP=y -CONFIG_SENSORS_K8TEMP=y -# CONFIG_SENSORS_OXP is not set -CONFIG_SENSORS_VIA_CPUTEMP=y -CONFIG_SERIAL_8250_PNP=y -# CONFIG_SERIAL_MULTI_INSTANTIATE is not set -CONFIG_SLS=y -CONFIG_SMP=y -# CONFIG_SND_HDA_CTL_DEV_ID is not set -# CONFIG_SND_HDA_SCODEC_CS35L41_I2C is not set -# CONFIG_SND_HDA_SCODEC_CS35L41_SPI is not set -# CONFIG_SND_HDA_SCODEC_CS35L56_I2C is not set -# CONFIG_SND_HDA_SCODEC_CS35L56_SPI is not set -# CONFIG_SND_HDA_SCODEC_TAS2781_I2C is not set -# CONFIG_SND_SOC_AMD_ACP6x is not set -# CONFIG_SND_SOC_AMD_ACP_COMMON is not set -# CONFIG_SND_SOC_AMD_PS is not set -# CONFIG_SND_SOC_AMD_RPL_ACP6x is not set -# CONFIG_SND_SOC_INTEL_AVS is not set -CONFIG_SOCK_RX_QUEUE_MAPPING=y -CONFIG_SPARSEMEM=y -CONFIG_SPARSEMEM_EXTREME=y -# CONFIG_SPARSEMEM_VMEMMAP is not set -CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y -CONFIG_STACK_VALIDATION=y -CONFIG_SWIOTLB=y -CONFIG_SWIOTLB_XEN=y -CONFIG_SYNC_FILE=y -CONFIG_SYSFB=y -# CONFIG_SYSTEM76_ACPI is not set -CONFIG_SYS_HYPERVISOR=y -# CONFIG_TDX_GUEST_DRIVER is not set -CONFIG_THERMAL_ACPI=y -CONFIG_THERMAL_GOV_USER_SPACE=y -CONFIG_THERMAL_HWMON=y -CONFIG_THERMAL_WRITABLE_TRIPS=y -# CONFIG_THINKPAD_LMI is not set -# CONFIG_TOSHIBA_BT_RFKILL is not set -# CONFIG_TOSHIBA_WMI is not set -CONFIG_TREE_RCU=y -CONFIG_TREE_SRCU=y -# CONFIG_UACCE is not set -# CONFIG_UCLAMP_TASK is not set -CONFIG_UCS2_STRING=y -CONFIG_UNACCEPTED_MEMORY=y -# CONFIG_UNWINDER_ORC is not set -CONFIG_USB_STORAGE=y -CONFIG_VIDEO_CMDLINE=y -# CONFIG_VIDEO_IPU3_CIO2 is not set -CONFIG_VIDEO_NOMODESET=y -CONFIG_VIRTIO=y -CONFIG_VIRTIO_ANCHOR=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_BLK=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_VIRTIO_DMA_SHARED_BUFFER=y -CONFIG_VIRTIO_IOMMU=y -CONFIG_VIRTIO_MMIO=y -CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y -CONFIG_VIRTIO_NET=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_PCI_LEGACY=y -CONFIG_VIRTIO_PCI_LIB=y -CONFIG_VIRTIO_PCI_LIB_LEGACY=y -# CONFIG_VIRTIO_PMEM is not set -# CONFIG_VIRTIO_VSOCKETS is not set -CONFIG_VIRTIO_VSOCKETS_COMMON=y -CONFIG_VIRT_DRIVERS=y -CONFIG_VMAP_PFN=y -CONFIG_VMAP_STACK=y -# CONFIG_VMD is not set -CONFIG_VMGENID=y -CONFIG_VMWARE_BALLOON=y -CONFIG_VMWARE_PVSCSI=y -CONFIG_VMWARE_VMCI=y -CONFIG_VMWARE_VMCI_VSOCKETS=y -CONFIG_VMXNET3=y -CONFIG_VSOCKETS=y -CONFIG_VSOCKETS_LOOPBACK=y -CONFIG_VT_CONSOLE_SLEEP=y -CONFIG_WATCHDOG_CORE=y -# CONFIG_WIRELESS_HOTKEY is not set -# CONFIG_WMI_BMOF is not set -# CONFIG_X86_5LEVEL is not set -CONFIG_X86_64=y -CONFIG_X86_64_SMP=y -CONFIG_X86_ACPI_CPUFREQ=y -# CONFIG_X86_ACPI_CPUFREQ_CPB is not set -CONFIG_X86_AMD_FREQ_SENSITIVITY=y -CONFIG_X86_AMD_PLATFORM_DEVICE=y -CONFIG_X86_AMD_PSTATE=y -CONFIG_X86_AMD_PSTATE_DEFAULT_MODE=3 -# CONFIG_X86_AMD_PSTATE_UT is not set -CONFIG_X86_CPUID=y -CONFIG_X86_DIRECT_GBPAGES=y -CONFIG_X86_HV_CALLBACK_VECTOR=y -CONFIG_X86_INTEL_LPSS=y -# CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS is not set -CONFIG_X86_INTEL_PSTATE=y -# CONFIG_X86_KERNEL_IBT is not set -CONFIG_X86_MEM_ENCRYPT=y -CONFIG_X86_MINIMUM_CPU_FAMILY=64 -# CONFIG_X86_PCC_CPUFREQ is not set -CONFIG_X86_PKG_TEMP_THERMAL=y -# CONFIG_X86_PMEM_LEGACY is not set -CONFIG_X86_PM_TIMER=y -# CONFIG_X86_POWERNOW_K8 is not set -# CONFIG_X86_SGX is not set -# CONFIG_X86_USER_SHADOW_STACK is not set -# CONFIG_X86_VSYSCALL_EMULATION is not set -CONFIG_X86_X2APIC=y -# CONFIG_X86_X32 is not set -# CONFIG_X86_X32_ABI is not set -CONFIG_XEN=y -CONFIG_XENFS=y -CONFIG_XEN_512GB=y -CONFIG_XEN_ACPI=y -CONFIG_XEN_ACPI_PROCESSOR=y -CONFIG_XEN_AUTO_XLATE=y -# CONFIG_XEN_BACKEND is not set -CONFIG_XEN_BALLOON=y -CONFIG_XEN_BLKDEV_FRONTEND=y -CONFIG_XEN_COMPAT_XENFS=y -CONFIG_XEN_DEBUG_FS=y -CONFIG_XEN_DEV_EVTCHN=y -CONFIG_XEN_DOM0=y -CONFIG_XEN_EFI=y -CONFIG_XEN_FBDEV_FRONTEND=y -CONFIG_XEN_GNTDEV=y -CONFIG_XEN_GRANT_DEV_ALLOC=y -CONFIG_XEN_GRANT_DMA_OPS=y -CONFIG_XEN_HAVE_PVMMU=y -CONFIG_XEN_HAVE_VPMU=y -# CONFIG_XEN_MCE_LOG is not set -CONFIG_XEN_NETDEV_FRONTEND=y -CONFIG_XEN_PCIDEV_FRONTEND=y -CONFIG_XEN_PRIVCMD=y -# CONFIG_XEN_PRIVCMD_IRQFD is not set -CONFIG_XEN_PV=y -CONFIG_XEN_PVH=y -CONFIG_XEN_PVHVM=y -CONFIG_XEN_PVHVM_GUEST=y -CONFIG_XEN_PVHVM_SMP=y -CONFIG_XEN_PV_DOM0=y -CONFIG_XEN_PV_MSR_SAFE=y -CONFIG_XEN_PV_SMP=y -CONFIG_XEN_SAVE_RESTORE=y -CONFIG_XEN_SCSI_FRONTEND=y -CONFIG_XEN_SYMS=y -CONFIG_XEN_SYS_HYPERVISOR=y -CONFIG_XEN_VIRTIO=y -# CONFIG_XEN_VIRTIO_FORCE_GRANT is not set -CONFIG_XEN_WDT=y -CONFIG_XEN_XENBUS_FRONTEND=y -# CONFIG_XIAOMI_WMI is not set -CONFIG_XPS=y -# CONFIG_YOGABOOK is not set -CONFIG_ZLIB_DEFLATE=y -CONFIG_ZONE_DMA32=y diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.6 b/openwrt/patch/openwrt-6.x/x86/config-6.6 deleted file mode 100644 index 7031def6a..000000000 --- a/openwrt/patch/openwrt-6.x/x86/config-6.6 +++ /dev/null @@ -1,475 +0,0 @@ -# CONFIG_60XX_WDT is not set -# CONFIG_64BIT is not set -# CONFIG_ACPI is not set -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_ADVANTECH_EC_WDT is not set -# CONFIG_ADVANTECH_WDT is not set -# CONFIG_ALIM1535_WDT is not set -# CONFIG_ALIX is not set -CONFIG_AMD_NB=y -CONFIG_ARCH_32BIT_OFF_T=y -CONFIG_ARCH_CLOCKSOURCE_INIT=y -CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y -CONFIG_ARCH_HIBERNATION_POSSIBLE=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y -CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y -CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y -CONFIG_ARCH_SELECT_MEMORY_MODEL=y -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SPLIT_ARG64=y -CONFIG_ARCH_STACKWALK=y -CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USES_PG_UNCACHED=y -CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y -CONFIG_ARCH_WANTS_NO_INSTR=y -CONFIG_ATA=y -CONFIG_ATA_GENERIC=y -CONFIG_ATA_PIIX=y -# CONFIG_BARCO_P50_GPIO is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_SD=y -CONFIG_BLK_MQ_PCI=y -CONFIG_BOUNCE=y -CONFIG_BUFFER_HEAD=y -CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" -CONFIG_CC_NO_ARRAY_BOUNDS=y -CONFIG_CLKBLD_I8253=y -CONFIG_CLKEVT_I8253=y -CONFIG_CLKSRC_I8253=y -CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y -CONFIG_CLOCKSOURCE_WATCHDOG=y -CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100 -CONFIG_CLONE_BACKWARDS=y -CONFIG_COMMON_CLK=y -CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 -CONFIG_COMPAT_32=y -CONFIG_COMPAT_32BIT_TIME=y -# CONFIG_COMPAT_VDSO is not set -CONFIG_CONSOLE_TRANSLATIONS=y -# CONFIG_CPU5_WDT is not set -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -CONFIG_CPU_FREQ_GOV_ATTR_SET=y -CONFIG_CPU_FREQ_GOV_COMMON=y -# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_GOV_USERSPACE is not set -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_GOV_LADDER=y -CONFIG_CPU_MITIGATIONS=y -CONFIG_CPU_SUP_AMD=y -CONFIG_CPU_SUP_CENTAUR=y -CONFIG_CPU_SUP_CYRIX_32=y -CONFIG_CPU_SUP_HYGON=y -CONFIG_CPU_SUP_INTEL=y -CONFIG_CPU_SUP_TRANSMETA_32=y -CONFIG_CPU_SUP_UMC_32=y -CONFIG_CPU_SUP_VORTEX_32=y -CONFIG_CPU_SUP_ZHAOXIN=y -CONFIG_CRASH_CORE=y -# CONFIG_CRASH_HOTPLUG is not set -CONFIG_CRC16=y -CONFIG_CRYPTO_CRC32=y -CONFIG_CRYPTO_CRC32C=y -# CONFIG_CRYPTO_CRC32_PCLMUL is not set -CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y -CONFIG_CRYPTO_LIB_GF128MUL=y -CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1 -CONFIG_CRYPTO_LIB_SHA1=y -CONFIG_CRYPTO_LIB_UTILS=y -# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set -# CONFIG_CX_ECAT is not set -CONFIG_DCACHE_WORD_ACCESS=y -# CONFIG_DEBUG_BOOT_PARAMS is not set -# CONFIG_DEBUG_ENTRY is not set -CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP is not set -CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_DEBUG_MISC=y -# CONFIG_DEBUG_NMI_SELFTEST is not set -# CONFIG_DEBUG_TLBFLUSH is not set -CONFIG_DECOMPRESS_BZIP2=y -CONFIG_DECOMPRESS_GZIP=y -CONFIG_DMADEVICES=y -CONFIG_DMI=y -CONFIG_DMIID=y -CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y -CONFIG_DMI_SYSFS=y -CONFIG_DNOTIFY=y -# CONFIG_DRM_I915_GVT_KVMGT is not set -CONFIG_DUMMY_CONSOLE=y -CONFIG_DYNAMIC_SIGFRAME=y -CONFIG_EARLY_PRINTK=y -# CONFIG_EARLY_PRINTK_DBGP is not set -CONFIG_EDAC_ATOMIC_SCRUB=y -CONFIG_EDAC_SUPPORT=y -# CONFIG_EDD is not set -# CONFIG_EISA is not set -# CONFIG_EUROTECH_WDT is not set -# CONFIG_EXAR_WDT is not set -CONFIG_EXCLUSIVE_SYSTEM_RAM=y -CONFIG_EXT4_FS=y -CONFIG_F2FS_FS=y -# CONFIG_F71808E_WDT is not set -CONFIG_FIRMWARE_MEMMAP=y -CONFIG_FIX_EARLYCON_MEM=y -CONFIG_FRAME_POINTER=y -CONFIG_FS_IOMAP=y -CONFIG_FS_MBCACHE=y -CONFIG_FUNCTION_ALIGNMENT=16 -CONFIG_FUNCTION_ALIGNMENT_16B=y -CONFIG_FUNCTION_PADDING_BYTES=16 -CONFIG_FUNCTION_PADDING_CFI=11 -CONFIG_FUSION=y -# CONFIG_FUSION_CTL is not set -# CONFIG_FUSION_LOGGING is not set -CONFIG_FUSION_MAX_SGE=128 -CONFIG_FUSION_SPI=y -CONFIG_FW_LOADER_PAGED_BUF=y -CONFIG_FW_LOADER_SYSFS=y -CONFIG_GCC11_NO_ARRAY_BOUNDS=y -CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y -# CONFIG_GDS_FORCE_MITIGATION is not set -CONFIG_GENERIC_ALLOCATOR=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y -CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y -CONFIG_GENERIC_CMOS_UPDATE=y -CONFIG_GENERIC_CPU_AUTOPROBE=y -CONFIG_GENERIC_CPU_VULNERABILITIES=y -CONFIG_GENERIC_EARLY_IOREMAP=y -CONFIG_GENERIC_ENTRY=y -CONFIG_GENERIC_GETTIMEOFDAY=y -CONFIG_GENERIC_IOMAP=y -CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y -CONFIG_GENERIC_IRQ_RESERVATION_MODE=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_GENERIC_ISA_DMA=y -CONFIG_GENERIC_MSI_IRQ=y -CONFIG_GENERIC_PCI_IOMAP=y -CONFIG_GENERIC_SMP_IDLE_THREAD=y -CONFIG_GENERIC_STRNCPY_FROM_USER=y -CONFIG_GENERIC_STRNLEN_USER=y -CONFIG_GENERIC_TIME_VSYSCALL=y -CONFIG_GENERIC_VDSO_32=y -# CONFIG_GEOS is not set -CONFIG_GLOB=y -CONFIG_GPIO_CDEV=y -# CONFIG_GPIO_ELKHARTLAKE is not set -# CONFIG_HANGCHECK_TIMER is not set -CONFIG_HARDIRQS_SW_RESEND=y -CONFIG_HAS_DMA=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAS_IOPORT_MAP=y -CONFIG_HID=y -CONFIG_HID_SUPPORT=y -CONFIG_HIGHMEM=y -CONFIG_HIGHMEM4G=y -# CONFIG_HIGHMEM64G is not set -CONFIG_HIGHPTE=y -CONFIG_HPET_EMULATE_RTC=y -CONFIG_HPET_TIMER=y -CONFIG_HW_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_GEODE=y -CONFIG_HW_RANDOM_VIA=y -# CONFIG_HYPERVISOR_GUEST is not set -CONFIG_HZ_PERIODIC=y -CONFIG_I8253_LOCK=y -CONFIG_IA32_FEAT_CTL=y -# CONFIG_IB700_WDT is not set -# CONFIG_IBMASR is not set -# CONFIG_IBM_RTL is not set -# CONFIG_IE6XX_WDT is not set -CONFIG_ILLEGAL_POINTER_VALUE=0 -CONFIG_INITRAMFS_SOURCE="" -CONFIG_INPUT=y -CONFIG_INPUT_KEYBOARD=y -CONFIG_INPUT_VIVALDIFMAP=y -CONFIG_INSTRUCTION_DECODER=y -# CONFIG_INTEL_HFI_THERMAL is not set -# CONFIG_INTEL_LDMA is not set -# CONFIG_INTEL_PCH_THERMAL is not set -# CONFIG_INTEL_POWERCLAMP is not set -# CONFIG_INTEL_SCU_PCI is not set -# CONFIG_INTEL_TCC_COOLING is not set -# CONFIG_INTEL_VSEC is not set -# CONFIG_IOSF_MBI is not set -CONFIG_IO_DELAY_0X80=y -# CONFIG_IO_DELAY_0XED is not set -# CONFIG_IO_DELAY_NONE is not set -# CONFIG_IO_DELAY_UDELAY is not set -CONFIG_IRQ_DOMAIN=y -CONFIG_IRQ_DOMAIN_HIERARCHY=y -CONFIG_IRQ_FORCED_THREADING=y -CONFIG_IRQ_WORK=y -# CONFIG_ISA is not set -CONFIG_ISA_DMA_API=y -# CONFIG_IT8712F_WDT is not set -# CONFIG_IT87_WDT is not set -# CONFIG_ITCO_WDT is not set -CONFIG_JBD2=y -CONFIG_KALLSYMS=y -CONFIG_KEXEC=y -CONFIG_KEXEC_CORE=y -CONFIG_KEYBOARD_ATKBD=y -CONFIG_KMAP_LOCAL=y -# CONFIG_KVM_PROVE_MMU is not set -CONFIG_LOCK_DEBUGGING_SUPPORT=y -# CONFIG_M486 is not set -# CONFIG_M486SX is not set -# CONFIG_M586 is not set -# CONFIG_M586MMX is not set -# CONFIG_M586TSC is not set -CONFIG_M686=y -# CONFIG_MACHZ_WDT is not set -# CONFIG_MATOM is not set -# CONFIG_MCORE2 is not set -# CONFIG_MCRUSOE is not set -# CONFIG_MCYRIXIII is not set -# CONFIG_MEFFICEON is not set -# CONFIG_MELAN is not set -# CONFIG_MFD_INTEL_LPSS_PCI is not set -# CONFIG_MGEODEGX1 is not set -# CONFIG_MGEODE_LX is not set -CONFIG_MICROCODE=y -CONFIG_MICROCODE_LATE_LOADING=y -CONFIG_MIGRATION=y -CONFIG_MITIGATION_RFDS=y -CONFIG_MITIGATION_SPECTRE_BHI=y -# CONFIG_MK6 is not set -# CONFIG_MK7 is not set -# CONFIG_MK8 is not set -CONFIG_MMU_GATHER_MERGE_VMAS=y -CONFIG_MMU_LAZY_TLB_REFCOUNT=y -# CONFIG_MODIFY_LDT_SYSCALL is not set -CONFIG_MODULES_TREE_LOOKUP=y -CONFIG_MODULES_USE_ELF_REL=y -# CONFIG_MPENTIUM4 is not set -# CONFIG_MPENTIUMII is not set -# CONFIG_MPENTIUMIII is not set -# CONFIG_MPENTIUMM is not set -# CONFIG_MTD is not set -CONFIG_MTRR=y -# CONFIG_MTRR_SANITIZER is not set -# CONFIG_MVIAC3_2 is not set -# CONFIG_MVIAC7 is not set -# CONFIG_MWINCHIP3D is not set -# CONFIG_MWINCHIPC6 is not set -CONFIG_NAMESPACES=y -CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y -CONFIG_NEED_PER_CPU_KM=y -CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y -CONFIG_NEED_SG_DMA_LENGTH=y -# CONFIG_NET5501 is not set -CONFIG_NET_EGRESS=y -CONFIG_NET_INGRESS=y -# CONFIG_NET_NS is not set -CONFIG_NET_XGRESS=y -CONFIG_NLS=y -# CONFIG_NMI_CHECK_CPU is not set -# CONFIG_NOHIGHMEM is not set -CONFIG_NR_CPUS=1 -CONFIG_NR_CPUS_DEFAULT=1 -CONFIG_NR_CPUS_RANGE_BEGIN=1 -CONFIG_NR_CPUS_RANGE_END=1 -# CONFIG_NSC_GPIO is not set -CONFIG_NVRAM=y -# CONFIG_OF is not set -CONFIG_OLD_SIGACTION=y -CONFIG_OLD_SIGSUSPEND3=y -# CONFIG_OLPC is not set -CONFIG_OUTPUT_FORMAT="elf32-i386" -CONFIG_PAGE_OFFSET=0xC0000000 -CONFIG_PAGE_POOL=y -CONFIG_PAGE_SIZE_LESS_THAN_256KB=y -CONFIG_PAGE_SIZE_LESS_THAN_64KB=y -CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y -CONFIG_PC104=y -# CONFIG_PC8736x_GPIO is not set -# CONFIG_PC87413_WDT is not set -# CONFIG_PCENGINES_APU2 is not set -CONFIG_PCI=y -CONFIG_PCI_ATS=y -CONFIG_PCI_BIOS=y -CONFIG_PCI_DIRECT=y -CONFIG_PCI_DOMAINS=y -CONFIG_PCI_GOANY=y -# CONFIG_PCI_GOBIOS is not set -# CONFIG_PCI_GODIRECT is not set -# CONFIG_PCI_GOMMCONFIG is not set -CONFIG_PCI_IOV=y -CONFIG_PCI_LABEL=y -CONFIG_PCI_LOCKLESS_CONFIG=y -CONFIG_PCI_MSI=y -CONFIG_PCSPKR_PLATFORM=y -CONFIG_PERF_EVENTS=y -# CONFIG_PERF_EVENTS_AMD_BRS is not set -# CONFIG_PERF_EVENTS_AMD_UNCORE is not set -CONFIG_PERF_EVENTS_INTEL_CSTATE=y -CONFIG_PERF_EVENTS_INTEL_RAPL=y -CONFIG_PERF_EVENTS_INTEL_UNCORE=y -CONFIG_PGTABLE_LEVELS=2 -CONFIG_PHYSICAL_ALIGN=0x100000 -CONFIG_PHYSICAL_START=0x1000000 -# CONFIG_PHY_INTEL_LGM_EMMC is not set -CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y -CONFIG_POWER_SUPPLY=y -CONFIG_PREEMPT_NONE_BUILD=y -# CONFIG_PROCESSOR_SELECT is not set -CONFIG_PROC_PAGE_MONITOR=y -CONFIG_PROC_PID_ARCH_STATUS=y -# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set -CONFIG_PTP_1588_CLOCK_OPTIONAL=y -# CONFIG_PUNIT_ATOM_DEBUG is not set -CONFIG_RANDSTRUCT_NONE=y -CONFIG_RATIONAL=y -CONFIG_RD_BZIP2=y -CONFIG_RD_GZIP=y -CONFIG_RETHUNK=y -CONFIG_RETPOLINE=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_MC146818_LIB=y -CONFIG_SATA_HOST=y -# CONFIG_SBC7240_WDT is not set -# CONFIG_SBC8360_WDT is not set -# CONFIG_SBC_EPX_C3_WATCHDOG is not set -# CONFIG_SC1200_WDT is not set -CONFIG_SCSI=y -CONFIG_SCSI_COMMON=y -CONFIG_SCSI_SPI_ATTRS=y -CONFIG_SCx200=y -CONFIG_SCx200HR_TIMER=y -# CONFIG_SCx200_GPIO is not set -# CONFIG_SCx200_WDT is not set -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_PCILIB=y -# CONFIG_SERIAL_LANTIQ is not set -CONFIG_SERIAL_MCTRL_GPIO=y -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_LIBPS2=y -CONFIG_SERIO_SERPORT=y -CONFIG_SG_POOL=y -# CONFIG_SIEMENS_SIMATIC_IPC is not set -# CONFIG_SMSC37B787_WDT is not set -# CONFIG_SMSC_SCH311X_WDT is not set -CONFIG_SOFTIRQ_ON_OWN_STACK=y -CONFIG_SPARSEMEM_STATIC=y -CONFIG_SPARSE_IRQ=y -CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y -# CONFIG_STATIC_CALL_SELFTEST is not set -# CONFIG_STRICT_SIGALTSTACK_SIZE is not set -CONFIG_SYSCTL_EXCEPTION_TRACE=y -# CONFIG_SYSFB_SIMPLEFB is not set -# CONFIG_TELCLOCK is not set -# CONFIG_TEST_FPU is not set -CONFIG_THERMAL=y -CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y -CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 -CONFIG_THERMAL_GOV_STEP_WISE=y -CONFIG_THREAD_INFO_IN_TASK=y -CONFIG_TICK_CPU_ACCOUNTING=y -CONFIG_TINY_SRCU=y -CONFIG_TOOLS_SUPPORT_RELR=y -# CONFIG_TOSHIBA is not set -# CONFIG_TQMX86_WDT is not set -CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y -CONFIG_UNWINDER_FRAME_POINTER=y -# CONFIG_UNWINDER_GUESS is not set -CONFIG_UP_LATE_INIT=y -CONFIG_USB=y -CONFIG_USB_COMMON=y -CONFIG_USB_EHCI_HCD=y -# CONFIG_USB_EHCI_HCD_PLATFORM is not set -CONFIG_USB_EHCI_PCI=y -CONFIG_USB_HID=y -CONFIG_USB_HIDDEV=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PCI=y -# CONFIG_USB_OHCI_HCD_PLATFORM is not set -CONFIG_USB_PCI=y -CONFIG_USB_SUPPORT=y -CONFIG_USB_UHCI_HCD=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_XHCI_PCI=y -# CONFIG_USB_XHCI_PLATFORM is not set -# CONFIG_USER_NS is not set -CONFIG_USER_STACKTRACE_SUPPORT=y -CONFIG_VGA_CONSOLE=y -# CONFIG_VIA_WDT is not set -CONFIG_VM_EVENT_COUNTERS=y -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y -# CONFIG_WAFER_WDT is not set -# CONFIG_WINMATE_FM07_KEYS is not set -CONFIG_X86=y -CONFIG_X86_32=y -# CONFIG_X86_32_IRIS is not set -# CONFIG_X86_ANCIENT_MCE is not set -# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set -CONFIG_X86_CMOV=y -CONFIG_X86_CMPXCHG64=y -# CONFIG_X86_CPA_STATISTICS is not set -# CONFIG_X86_CPUFREQ_NFORCE2 is not set -# CONFIG_X86_CPUID is not set -# CONFIG_X86_CPU_RESCTRL is not set -CONFIG_X86_DEBUGCTLMSR=y -# CONFIG_X86_DEBUG_FPU is not set -# CONFIG_X86_DECODER_SELFTEST is not set -# CONFIG_X86_EXTENDED_PLATFORM is not set -CONFIG_X86_GENERIC=y -# CONFIG_X86_GX_SUSPMOD is not set -# CONFIG_X86_INTEL_PSTATE is not set -# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set -CONFIG_X86_INTEL_TSX_MODE_OFF=y -# CONFIG_X86_INTEL_TSX_MODE_ON is not set -CONFIG_X86_INTEL_USERCOPY=y -CONFIG_X86_INTERNODE_CACHE_SHIFT=6 -CONFIG_X86_IOPL_IOPERM=y -CONFIG_X86_IO_APIC=y -CONFIG_X86_L1_CACHE_SHIFT=6 -# CONFIG_X86_LEGACY_VM86 is not set -CONFIG_X86_LOCAL_APIC=y -# CONFIG_X86_LONGRUN is not set -CONFIG_X86_MCE=y -# CONFIG_X86_MCELOG_LEGACY is not set -CONFIG_X86_MCE_AMD=y -# CONFIG_X86_MCE_INJECT is not set -CONFIG_X86_MCE_INTEL=y -CONFIG_X86_MCE_THRESHOLD=y -CONFIG_X86_MINIMUM_CPU_FAMILY=6 -CONFIG_X86_MPPARSE=y -CONFIG_X86_MSR=y -# CONFIG_X86_P4_CLOCKMOD is not set -CONFIG_X86_PAT=y -CONFIG_X86_PLATFORM_DEVICES=y -# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set -# CONFIG_X86_PLATFORM_DRIVERS_HP is not set -# CONFIG_X86_POWERNOW_K6 is not set -# CONFIG_X86_POWERNOW_K7 is not set -# CONFIG_X86_REBOOTFIXUPS is not set -CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y -# CONFIG_X86_SPEEDSTEP_CENTRINO is not set -# CONFIG_X86_SPEEDSTEP_ICH is not set -# CONFIG_X86_SPEEDSTEP_SMI is not set -CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y -CONFIG_X86_THERMAL_VECTOR=y -CONFIG_X86_TSC=y -CONFIG_X86_UMIP=y -CONFIG_X86_UP_APIC=y -CONFIG_X86_UP_IOAPIC=y -CONFIG_X86_USE_PPRO_CHECKSUM=y -CONFIG_X86_VERBOSE_BOOTUP=y -CONFIG_X86_VMX_FEATURE_NAMES=y -CONFIG_XZ_DEC_BCJ=y -CONFIG_XZ_DEC_X86=y -CONFIG_ZLIB_INFLATE=y diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.6/100-fix_cs5535_clockevt.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.6/100-fix_cs5535_clockevt.patch deleted file mode 100644 index d4de2027b..000000000 --- a/openwrt/patch/openwrt-6.x/x86/patches-6.6/100-fix_cs5535_clockevt.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- a/drivers/clocksource/timer-cs5535.c -+++ b/drivers/clocksource/timer-cs5535.c -@@ -127,7 +127,9 @@ static irqreturn_t mfgpt_tick(int irq, v - cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, - MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); - -- cs5535_clockevent.event_handler(&cs5535_clockevent); -+ if (cs5535_clockevent.event_handler) -+ cs5535_clockevent.event_handler(&cs5535_clockevent); -+ - return IRQ_HANDLED; - } - diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.6/103-pcengines_apu6_platform.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.6/103-pcengines_apu6_platform.patch deleted file mode 100644 index 1fd6fc89c..000000000 --- a/openwrt/patch/openwrt-6.x/x86/patches-6.6/103-pcengines_apu6_platform.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 970d9af9015a387bb81841faf05dcc1a171eb97a Mon Sep 17 00:00:00 2001 -From: Philip Prindeville -Date: Sun, 1 Jan 2023 15:25:04 -0700 -Subject: [PATCH v3 1/1] x86: Support APU5 in PCEngines platform driver -To: platform-driver-x86@vger.kernel.org, linux-x86_64@vger.kernel.org -Cc: Ed Wildgoose , Andres Salomon , Andreas Eberlein , Paul Spooren - -PCEngines make a number of SBC. APU5 has 5 mpcie slots + MSATA. -It also has support for 3x LTE modems with 6x SIM slots (pairs with a -SIM switch device). Each mpcie slot for modems has a reset GPIO - -To ensure that the naming is sane between APU2-6 the GPIOS are -renamed to be modem1-reset, modem2-reset, etc. This is significant -because the slots that can be reset change between APU2 and APU3/4 - -GPIO for simswap is moved to the end of the list as it could be dropped -for APU2 boards (but causes no harm to leave it in, hardware could be -added to a future rev of the board). - -Structure of the GPIOs for APU5 is extremely similar to APU2-4, but -many lines are moved around and there are simply more -modems/resets/sim-swap lines to breakout. - -Also added APU6, which is essentially APU4 with a different ethernet -interface and SFP cage on eth0. - -Revision history: - -v1: originally titled, "apu6: add apu6 variation to apu2 driver family" -this dealt only with detecting the APUv6, which is otherwise identical -to the v4 excepting the SFP cage on eth0. - -v2: at Ed's request, merged with his previous pull-request titled -"x86: Support APU5 in PCEngines platform driver", and some cleanup -to that changeset (including dropping the table "apu5_driver_data" -which did not have a defined type "struct apu_driver_data"), but got -mistitled when the Subject of that commit got accidentally dropped. - -v3: retitled to match Ed's previous pull-request. - -Cc: platform-driver-x86@vger.kernel.org -Cc: linux-x86_64@vger.kernel.org -Reviewed-by: Andreas Eberlein -Reviewed-by: Paul Spooren -Signed-off-by: Ed Wildgoose -Sighed-off-by: Philip Prindeville ---- - drivers/leds/leds-apu.c | 2 +- - drivers/platform/x86/Kconfig | 4 +- - drivers/platform/x86/pcengines-apuv2.c | 118 ++++++++++++++++++++++--- - 3 files changed, 107 insertions(+), 17 deletions(-) - ---- a/drivers/leds/leds-apu.c -+++ b/drivers/leds/leds-apu.c -@@ -183,7 +183,7 @@ static int __init apu_led_init(void) - - if (!(dmi_match(DMI_SYS_VENDOR, "PC Engines") && - (dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "apu1")))) { -- pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n"); -+ pr_err("No PC Engines APUv1 board detected. For APUv2,3,4,5,6 support, enable CONFIG_PCENGINES_APU2\n"); - return -ENODEV; - } - ---- a/drivers/platform/x86/Kconfig -+++ b/drivers/platform/x86/Kconfig -@@ -707,7 +707,7 @@ config XO1_RFKILL - laptop. - - config PCENGINES_APU2 -- tristate "PC Engines APUv2/3 front button and LEDs driver" -+ tristate "PC Engines APUv2/3/4/5/6 front button and LEDs driver" - depends on INPUT && INPUT_KEYBOARD && GPIOLIB - depends on LEDS_CLASS - select GPIO_AMD_FCH -@@ -715,7 +715,7 @@ config PCENGINES_APU2 - select LEDS_GPIO - help - This driver provides support for the front button and LEDs on -- PC Engines APUv2/APUv3 board. -+ PC Engines APUv2/APUv3/APUv4/APUv5/APUv6 board. - - To compile this driver as a module, choose M here: the module - will be called pcengines-apuv2. ---- a/drivers/platform/x86/pcengines-apuv2.c -+++ b/drivers/platform/x86/pcengines-apuv2.c -@@ -1,10 +1,12 @@ - // SPDX-License-Identifier: GPL-2.0+ - - /* -- * PC-Engines APUv2/APUv3 board platform driver -+ * PC-Engines APUv2-6 board platform driver - * for GPIO buttons and LEDs - * - * Copyright (C) 2018 metux IT consult -+ * Copyright (C) 2022 Ed Wildgoose -+ * Copyright (C) 2022 Philip Prindeville - * Author: Enrico Weigelt - */ - -@@ -22,38 +24,70 @@ - #include - - /* -- * NOTE: this driver only supports APUv2/3 - not APUv1, as this one -+ * NOTE: this driver only supports APUv2-6 - not APUv1, as this one - * has completely different register layouts. - */ - -+/* -+ * There are a number of APU variants, with differing features -+ * APU2 has SIM slots 1/2 mapping to mPCIe sockets 1/2 -+ * APU3/4 moved SIM slot 1 to mPCIe socket 3, ie logically reversed -+ * However, most APU3/4 have a SIM switch which we default on to reverse -+ * the order and keep physical SIM order matching physical modem order -+ * APU6 is approximately the same as APU4 with different ethernet layout -+ * -+ * APU5 has 3x SIM sockets, all with a SIM switch -+ * several GPIOs are shuffled (see schematic), including MODESW -+ */ -+ - /* Register mappings */ - #define APU2_GPIO_REG_LED1 AMD_FCH_GPIO_REG_GPIO57 - #define APU2_GPIO_REG_LED2 AMD_FCH_GPIO_REG_GPIO58 - #define APU2_GPIO_REG_LED3 AMD_FCH_GPIO_REG_GPIO59_DEVSLP1 - #define APU2_GPIO_REG_MODESW AMD_FCH_GPIO_REG_GPIO32_GE1 - #define APU2_GPIO_REG_SIMSWAP AMD_FCH_GPIO_REG_GPIO33_GE2 --#define APU2_GPIO_REG_MPCIE2 AMD_FCH_GPIO_REG_GPIO55_DEVSLP0 --#define APU2_GPIO_REG_MPCIE3 AMD_FCH_GPIO_REG_GPIO51 -+#define APU2_GPIO_REG_RESETM1 AMD_FCH_GPIO_REG_GPIO51 -+#define APU2_GPIO_REG_RESETM2 AMD_FCH_GPIO_REG_GPIO55_DEVSLP0 -+ -+#define APU5_GPIO_REG_MODESW AMT_FCH_GPIO_REG_GEVT22 -+#define APU5_GPIO_REG_SIMSWAP1 AMD_FCH_GPIO_REG_GPIO68 -+#define APU5_GPIO_REG_SIMSWAP2 AMD_FCH_GPIO_REG_GPIO32_GE1 -+#define APU5_GPIO_REG_SIMSWAP3 AMD_FCH_GPIO_REG_GPIO33_GE2 -+#define APU5_GPIO_REG_RESETM1 AMD_FCH_GPIO_REG_GPIO51 -+#define APU5_GPIO_REG_RESETM2 AMD_FCH_GPIO_REG_GPIO55_DEVSLP0 -+#define APU5_GPIO_REG_RESETM3 AMD_FCH_GPIO_REG_GPIO64 - - /* Order in which the GPIO lines are defined in the register list */ - #define APU2_GPIO_LINE_LED1 0 - #define APU2_GPIO_LINE_LED2 1 - #define APU2_GPIO_LINE_LED3 2 - #define APU2_GPIO_LINE_MODESW 3 --#define APU2_GPIO_LINE_SIMSWAP 4 --#define APU2_GPIO_LINE_MPCIE2 5 --#define APU2_GPIO_LINE_MPCIE3 6 -+#define APU2_GPIO_LINE_RESETM1 4 -+#define APU2_GPIO_LINE_RESETM2 5 -+#define APU2_GPIO_LINE_SIMSWAP 6 -+ -+#define APU5_GPIO_LINE_LED1 0 -+#define APU5_GPIO_LINE_LED2 1 -+#define APU5_GPIO_LINE_LED3 2 -+#define APU5_GPIO_LINE_MODESW 3 -+#define APU5_GPIO_LINE_RESETM1 4 -+#define APU5_GPIO_LINE_RESETM2 5 -+#define APU5_GPIO_LINE_RESETM3 6 -+#define APU5_GPIO_LINE_SIMSWAP1 7 -+#define APU5_GPIO_LINE_SIMSWAP2 8 -+#define APU5_GPIO_LINE_SIMSWAP3 9 -+ - --/* GPIO device */ -+/* GPIO device - APU2/3/4/6 */ - - static int apu2_gpio_regs[] = { - [APU2_GPIO_LINE_LED1] = APU2_GPIO_REG_LED1, - [APU2_GPIO_LINE_LED2] = APU2_GPIO_REG_LED2, - [APU2_GPIO_LINE_LED3] = APU2_GPIO_REG_LED3, - [APU2_GPIO_LINE_MODESW] = APU2_GPIO_REG_MODESW, -+ [APU2_GPIO_LINE_RESETM1] = APU2_GPIO_REG_RESETM1, -+ [APU2_GPIO_LINE_RESETM2] = APU2_GPIO_REG_RESETM2, - [APU2_GPIO_LINE_SIMSWAP] = APU2_GPIO_REG_SIMSWAP, -- [APU2_GPIO_LINE_MPCIE2] = APU2_GPIO_REG_MPCIE2, -- [APU2_GPIO_LINE_MPCIE3] = APU2_GPIO_REG_MPCIE3, - }; - - static const char * const apu2_gpio_names[] = { -@@ -61,9 +95,9 @@ static const char * const apu2_gpio_name - [APU2_GPIO_LINE_LED2] = "front-led2", - [APU2_GPIO_LINE_LED3] = "front-led3", - [APU2_GPIO_LINE_MODESW] = "front-button", -+ [APU2_GPIO_LINE_RESETM1] = "modem1-reset", -+ [APU2_GPIO_LINE_RESETM2] = "modem2-reset", - [APU2_GPIO_LINE_SIMSWAP] = "simswap", -- [APU2_GPIO_LINE_MPCIE2] = "mpcie2_reset", -- [APU2_GPIO_LINE_MPCIE3] = "mpcie3_reset", - }; - - static const struct amd_fch_gpio_pdata board_apu2 = { -@@ -72,6 +106,40 @@ static const struct amd_fch_gpio_pdata b - .gpio_names = apu2_gpio_names, - }; - -+/* GPIO device - APU5 */ -+ -+static int apu5_gpio_regs[] = { -+ [APU5_GPIO_LINE_LED1] = APU2_GPIO_REG_LED1, -+ [APU5_GPIO_LINE_LED2] = APU2_GPIO_REG_LED2, -+ [APU5_GPIO_LINE_LED3] = APU2_GPIO_REG_LED3, -+ [APU5_GPIO_LINE_MODESW] = APU5_GPIO_REG_MODESW, -+ [APU5_GPIO_LINE_RESETM1] = APU5_GPIO_REG_RESETM1, -+ [APU5_GPIO_LINE_RESETM2] = APU5_GPIO_REG_RESETM2, -+ [APU5_GPIO_LINE_RESETM3] = APU5_GPIO_REG_RESETM3, -+ [APU5_GPIO_LINE_SIMSWAP1] = APU5_GPIO_REG_SIMSWAP1, -+ [APU5_GPIO_LINE_SIMSWAP2] = APU5_GPIO_REG_SIMSWAP2, -+ [APU5_GPIO_LINE_SIMSWAP3] = APU5_GPIO_REG_SIMSWAP3, -+}; -+ -+static const char * const apu5_gpio_names[] = { -+ [APU5_GPIO_LINE_LED1] = "front-led1", -+ [APU5_GPIO_LINE_LED2] = "front-led2", -+ [APU5_GPIO_LINE_LED3] = "front-led3", -+ [APU5_GPIO_LINE_MODESW] = "front-button", -+ [APU5_GPIO_LINE_RESETM1] = "modem1-reset", -+ [APU5_GPIO_LINE_RESETM2] = "modem2-reset", -+ [APU5_GPIO_LINE_RESETM3] = "modem3-reset", -+ [APU5_GPIO_LINE_SIMSWAP1] = "simswap1", -+ [APU5_GPIO_LINE_SIMSWAP2] = "simswap2", -+ [APU5_GPIO_LINE_SIMSWAP3] = "simswap3", -+}; -+ -+static const struct amd_fch_gpio_pdata board_apu5 = { -+ .gpio_num = ARRAY_SIZE(apu5_gpio_regs), -+ .gpio_reg = apu5_gpio_regs, -+ .gpio_names = apu5_gpio_names, -+}; -+ - /* GPIO LEDs device */ - - static const struct gpio_led apu2_leds[] = { -@@ -215,6 +283,24 @@ static const struct dmi_system_id apu_gp - }, - .driver_data = (void *)&board_apu2, - }, -+ /* APU5 w/ mainline BIOS */ -+ { -+ .ident = "apu5", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), -+ DMI_MATCH(DMI_BOARD_NAME, "apu5") -+ }, -+ .driver_data = (void *)&board_apu5, -+ }, -+ /* APU6 w/ mainline BIOS */ -+ { -+ .ident = "apu6", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), -+ DMI_MATCH(DMI_BOARD_NAME, "apu6") -+ }, -+ .driver_data = (void *)&board_apu2, -+ }, - {} - }; - -@@ -249,7 +335,7 @@ static int __init apu_board_init(void) - - id = dmi_first_match(apu_gpio_dmi_table); - if (!id) { -- pr_err("failed to detect APU board via DMI\n"); -+ pr_err("No APU board detected via DMI\n"); - return -ENODEV; - } - -@@ -288,7 +374,7 @@ module_init(apu_board_init); - module_exit(apu_board_exit); - - MODULE_AUTHOR("Enrico Weigelt, metux IT consult "); --MODULE_DESCRIPTION("PC Engines APUv2/APUv3 board GPIO/LEDs/keys driver"); -+MODULE_DESCRIPTION("PC Engines APUv2-6 board GPIO/LEDs/keys driver"); - MODULE_LICENSE("GPL"); - MODULE_DEVICE_TABLE(dmi, apu_gpio_dmi_table); - MODULE_SOFTDEP("pre: platform:" AMD_FCH_GPIO_DRIVER_NAME " platform:leds-gpio platform:gpio_keys_polled"); diff --git a/openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch deleted file mode 100644 index 162e7e24c..000000000 --- a/openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch +++ /dev/null @@ -1,84 +0,0 @@ -From bd7418182b6c5a782730b80f40b25a0ae9a6d096 Mon Sep 17 00:00:00 2001 -From: Joan Bruguera -Date: Sat, 18 Feb 2023 23:36:56 +0000 -Subject: [PATCH] Fix build for Linux 6.3-rc1 - -The 1st parameter of `crypto_completion_t` is now the user data passed to the -callback instead of the `crypto_async_request`. -Migrate to the new API and add a shim to keep compatibility with old kernels. - -See also: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=255e48eb17684157336bd6dd98d22c1b2d9e3f43 - -Signed-off-by: Joan Bruguera ---- - cryptlib.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - ---- a/cryptlib.c -+++ b/cryptlib.c -@@ -42,9 +42,9 @@ - extern const struct crypto_type crypto_givcipher_type; - #endif - --static void cryptodev_complete(struct crypto_async_request *req, int err) -+static void cryptodev_complete(void *data, int err) - { -- struct cryptodev_result *res = req->data; -+ struct cryptodev_result *res = data; - - if (err == -EINPROGRESS) - return; -@@ -53,6 +53,14 @@ static void cryptodev_complete(struct cr - complete(&res->completion); - } - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) -+static void cryptodev_complete_shim(struct crypto_async_request *req, int err) -+{ -+ cryptodev_complete(req->data, err); -+} -+#define cryptodev_complete cryptodev_complete_shim -+#endif -+ - int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop, - int aead) - { ---- a/ioctl.c -+++ b/ioctl.c -@@ -1184,7 +1184,6 @@ static struct ctl_table verbosity_ctl_ro - { - .procname = "ioctl", - .mode = 0555, -- .child = verbosity_ctl_dir, - }, - {}, - }; -@@ -1205,7 +1204,6 @@ static int __init init_cryptodev(void) - return rc; - } - -- verbosity_sysctl_header = register_sysctl_table(verbosity_ctl_root); - - pr_info(PFX "driver %s loaded.\n", VERSION); - -@@ -1217,9 +1215,6 @@ static void __exit exit_cryptodev(void) - flush_workqueue(cryptodev_wq); - destroy_workqueue(cryptodev_wq); - -- if (verbosity_sysctl_header) -- unregister_sysctl_table(verbosity_sysctl_header); -- - cryptodev_deregister(); - pr_info(PFX "driver unloaded.\n"); - } ---- a/zc.c -+++ b/zc.c -@@ -83,7 +83,7 @@ int __get_userbuf(uint8_t __user *addr, - #else - ret = get_user_pages_remote(mm, - (unsigned long)addr, pgcount, write ? FOLL_WRITE : 0, -- pg, NULL, NULL); -+ pg, NULL); - #endif - #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)) - up_read(&mm->mmap_sem); diff --git a/openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch deleted file mode 100644 index 4fded72fa..000000000 --- a/openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 5e7121e45ff283d30097da381fd7e97c4bb61364 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= -Date: Sun, 10 Dec 2023 13:57:55 +0000 -Subject: [PATCH] Fix build for Linux 6.7-rc1 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since Linux 6.7-rc1, no ahash algorithms set a nonzero alignmask, -and therefore `crypto_ahash_alignmask` has been removed. - -See also: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0f8660c82b79af595b056f6b9f4f227edeb88574 - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c626910f3f1bbce6ad18bc613d895d2a089ed95e - -Signed-off-by: Joan Bruguera Micó ---- - cryptlib.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/cryptlib.c -+++ b/cryptlib.c -@@ -381,7 +381,11 @@ int cryptodev_hash_init(struct hash_data - } - - hdata->digestsize = crypto_ahash_digestsize(hdata->async.s); -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)) - hdata->alignmask = crypto_ahash_alignmask(hdata->async.s); -+#else -+ hdata->alignmask = 0; -+#endif - - init_completion(&hdata->async.result.completion); - diff --git a/openwrt/patch/packages-patches/dmx_usb_module/900-fix-linux-6.6.patch b/openwrt/patch/packages-patches/dmx_usb_module/900-fix-linux-6.6.patch deleted file mode 100644 index f634e5cb3..000000000 --- a/openwrt/patch/packages-patches/dmx_usb_module/900-fix-linux-6.6.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/dmx_usb.c b/dmx_usb.c -index 4e3372d..7dfb814 100644 ---- a/dmx_usb.c -+++ b/dmx_usb.c -@@ -97,7 +97,7 @@ struct dmx_usb_device { - - - /* prevent races between open() and disconnect() */ -- static DEFINE_SEMAPHORE(disconnect_sem); -+ static DEFINE_SEMAPHORE(disconnect_sem, 1); - - /* local function prototypes */ - static ssize_t dmx_usb_write (struct file *file, const char *buffer, size_t count, loff_t *ppos); diff --git a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch index 3e5e21907..a48fed524 100644 --- a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch +++ b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch @@ -1,8 +1,8 @@ diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -index 6220ad1..9e83a29 100644 +index 52346c2..75f6155 100644 --- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -@@ -672,7 +672,11 @@ static void gpio_keys_irq_close(struct gpio_keys_button_dev *bdev) +@@ -674,7 +674,11 @@ static void gpio_keys_irq_close(struct gpio_keys_button_dev *bdev) } } @@ -14,7 +14,7 @@ index 6220ad1..9e83a29 100644 { struct gpio_keys_button_dev *bdev = platform_get_drvdata(pdev); -@@ -683,7 +687,9 @@ static int gpio_keys_remove(struct platform_device *pdev) +@@ -685,7 +689,9 @@ static int gpio_keys_remove(struct platform_device *pdev) else gpio_keys_irq_close(bdev); diff --git a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch deleted file mode 100644 index 474da9e74..000000000 --- a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -index 522085b..6220ad1 100644 ---- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -+++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -@@ -538,8 +538,7 @@ static int gpio_keys_button_probe(struct platform_device *pdev, - struct device_node *child = - of_get_next_child(dev->of_node, prev); - -- bdata->gpiod = devm_gpiod_get_from_of_node(dev, -- child, "gpios", 0, GPIOD_IN, desc); -+ bdata->gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - - prev = child; - } diff --git a/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch b/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch deleted file mode 100644 index e6b11b9d5..000000000 --- a/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- a/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c -+++ b/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c -@@ -18,6 +18,10 @@ - #include - #include - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,6,0) -+#include -+#endif -+ - #define DRVNAME "gpio-nct5104d" - - /* diff --git a/openwrt/patch/packages-patches/jool/Makefile b/openwrt/patch/packages-patches/jool/Makefile index c264b2f84..685239a44 100644 --- a/openwrt/patch/packages-patches/jool/Makefile +++ b/openwrt/patch/packages-patches/jool/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=jool -PKG_VERSION:=4.1.10 +PKG_VERSION:=4.1.13 PKG_RELEASE:=1 PKG_LICENSE:=GPL-2.0-only @@ -16,8 +16,8 @@ PKG_LICENSE_FILES:=COPYING PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/NICMx/Jool.git -PKG_SOURCE_VERSION:=741baa890489d4a3985da45551e203aebf078a93 -PKG_MIRROR_HASH:=543fbec0bd00870a1d72731ad0504fe2b88f1bf5f2c4366d362195739a932cee +PKG_SOURCE_VERSION:=39ca69f8717a83733548bea3b7bfad2a4799572a +PKG_MIRROR_HASH:=f00592d639f34bc6c38e9d012d59a694b159a57ada1b86985cd4df38e4f85d5f PKG_BUILD_DIR=$(KERNEL_BUILD_DIR)/$(PKG_SOURCE_SUBDIR) PKG_BUILD_PARALLEL:=1 @@ -69,7 +69,7 @@ endef define Package/jool/Default SECTION:=net CATEGORY:=Network - URL:=https://www.jool.mx + URL:=https://nicmx.github.io/Jool/ endef define Package/jool/Default/description @@ -104,7 +104,7 @@ endef define Package/jool-tools-netfilter $(call Package/jool/Default) TITLE:=Jool userspace control programs - DEPENDS:=+libnl +kmod-jool-netfilter + DEPENDS:=+libnl +libnl-genl +kmod-jool-netfilter +ethtool endef define Package/jool-tools-netfilter/description @@ -137,6 +137,9 @@ define Package/jool-tools-netfilter/install $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/jool.init $(1)/etc/init.d/jool + $(INSTALL_DIR) $(1)/etc/hotplug.d/net + $(INSTALL_BIN) ./files/jool-disable-fraglist-gro.sh $(1)/etc/hotplug.d/net/90-jool-disable-fraglist-gro.sh + $(INSTALL_DIR) $(1)/etc/jool $(INSTALL_CONF) ./files/jool-nat64.conf.json $(1)/etc/jool/jool-nat64.conf.json $(INSTALL_CONF) ./files/jool-siit.conf.json $(1)/etc/jool/jool-siit.conf.json diff --git a/openwrt/patch/packages-patches/jool/Makefile.24 b/openwrt/patch/packages-patches/jool/Makefile.24 deleted file mode 100644 index 685239a44..000000000 --- a/openwrt/patch/packages-patches/jool/Makefile.24 +++ /dev/null @@ -1,150 +0,0 @@ -# -# Copyright (C) 2016-2017 Dan Luedtke -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. - -include $(TOPDIR)/rules.mk -include $(INCLUDE_DIR)/kernel.mk - -PKG_NAME:=jool -PKG_VERSION:=4.1.13 -PKG_RELEASE:=1 - -PKG_LICENSE:=GPL-2.0-only -PKG_LICENSE_FILES:=COPYING - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://github.com/NICMx/Jool.git -PKG_SOURCE_VERSION:=39ca69f8717a83733548bea3b7bfad2a4799572a -PKG_MIRROR_HASH:=f00592d639f34bc6c38e9d012d59a694b159a57ada1b86985cd4df38e4f85d5f - -PKG_BUILD_DIR=$(KERNEL_BUILD_DIR)/$(PKG_SOURCE_SUBDIR) -PKG_BUILD_PARALLEL:=1 -PKG_BUILD_DEPENDS:=!USE_GLIBC:argp-standalone - -PKG_FIXUP:=autoreconf - -MAKE_PATH:=src/usr -CONFIGURE_PATH:=src/usr - -include $(INCLUDE_DIR)/package.mk - -define Build/Compile - $(MAKE) -C "$(LINUX_DIR)" \ - KERNEL_DIR="$(LINUX_DIR)" \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - M="$(PKG_BUILD_DIR)/src/mod/common" \ - V="$(V)" \ - CFLAGS_MODULE=$(NOXTABLES) \ - modules - $(MAKE) -C "$(LINUX_DIR)" \ - KBUILD_MODPOST_WARN=1 \ - KERNEL_DIR="$(LINUX_DIR)" \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - M="$(PKG_BUILD_DIR)/src/mod/nat64" \ - CFLAGS_MODULE=$(NOXTABLES) \ - V="$(V)" \ - modules - $(MAKE) -C "$(LINUX_DIR)" \ - KBUILD_MODPOST_WARN=1 \ - KERNEL_DIR="$(LINUX_DIR)" \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - M="$(PKG_BUILD_DIR)/src/mod/siit" \ - CFLAGS_MODULE=$(NOXTABLES) \ - V="$(V)" \ - modules - $(call Build/Compile/Default) -endef - -define Build/Configure - (cd $(PKG_BUILD_DIR); ./autogen.sh ); - $(call Build/Configure/Default, --with-xtables=no) -endef - - -define Package/jool/Default - SECTION:=net - CATEGORY:=Network - URL:=https://nicmx.github.io/Jool/ -endef - -define Package/jool/Default/description - Jool is an Open Source SIIT and NAT64 for Linux. -endef - - -define KernelPackage/jool-netfilter - SECTION:=kernel - CATEGORY:=Kernel modules - SUBMENU:=Network Support - TITLE:=Jool kernel module - DEPENDS:= \ - @IPV6 \ - +kmod-crypto-md5 \ - +kmod-nf-conntrack \ - +kmod-nf-conntrack6 - FILES:= \ - $(PKG_BUILD_DIR)/src/mod/common/jool_common.$(LINUX_KMOD_SUFFIX) \ - $(PKG_BUILD_DIR)/src/mod/nat64/jool.$(LINUX_KMOD_SUFFIX) \ - $(PKG_BUILD_DIR)/src/mod/siit/jool_siit.$(LINUX_KMOD_SUFFIX) - AUTOLOAD:=$(call AutoLoad,48,$(JOOL_AUTOLOAD)) -endef - -define KernelPackage/jool-netfilter/description - $(call Package/jool/Default/description) - - This package provides the kernel module for Jool with netfilter API Only. -endef - - -define Package/jool-tools-netfilter - $(call Package/jool/Default) - TITLE:=Jool userspace control programs - DEPENDS:=+libnl +libnl-genl +kmod-jool-netfilter +ethtool -endef - -define Package/jool-tools-netfilter/description - $(call Package/jool/Default/description) - - This package provides the userspace control programs for Jool. -endef - -JOOL_AUTOLOAD:= \ - jool \ - jool_siit - -NOXTABLES:=-DXTABLES_DISABLED - -define Package/jool-tools-netfilter/conffiles -/etc/config/jool -/etc/jool/jool-nat64.conf.json -/etc/jool/jool-siit.conf.json -endef - -define Package/jool-tools-netfilter/install - $(INSTALL_DIR) $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/usr/nat64/jool $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/usr/joold/joold $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/usr/siit/jool_siit $(1)/usr/bin/ - - $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_CONF) ./files/jool.config $(1)/etc/config/jool - - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) ./files/jool.init $(1)/etc/init.d/jool - - $(INSTALL_DIR) $(1)/etc/hotplug.d/net - $(INSTALL_BIN) ./files/jool-disable-fraglist-gro.sh $(1)/etc/hotplug.d/net/90-jool-disable-fraglist-gro.sh - - $(INSTALL_DIR) $(1)/etc/jool - $(INSTALL_CONF) ./files/jool-nat64.conf.json $(1)/etc/jool/jool-nat64.conf.json - $(INSTALL_CONF) ./files/jool-siit.conf.json $(1)/etc/jool/jool-siit.conf.json - $(INSTALL_DATA) ./files/readme.md $(1)/etc/jool/readme.md -endef - -$(eval $(call KernelPackage,jool-netfilter)) -$(eval $(call BuildPackage,jool-tools-netfilter)) diff --git a/openwrt/patch/packages-patches/mdio-netlink/001-mdio-netlink-rework-C45-to-work-with-net-next.patch b/openwrt/patch/packages-patches/mdio-netlink/001-mdio-netlink-rework-C45-to-work-with-net-next.patch deleted file mode 100644 index 4426c47d2..000000000 --- a/openwrt/patch/packages-patches/mdio-netlink/001-mdio-netlink-rework-C45-to-work-with-net-next.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 6cfdfd0a4120758015e99224a8271cdf4d8fd613 Mon Sep 17 00:00:00 2001 -From: Robert Marko -Date: Mon, 23 Jan 2023 11:41:14 +0100 -Subject: [PATCH] mdio-netlink: rework C45 to work with net-next - -net-next has finally completely split C22 and C45 and the old magic -macro for C45 was finally dropped, so lets rework to work on it. - -Signed-off-by: Robert Marko ---- - kernel/mdio-netlink.c | 43 ++++++++++++++++++++----------------------- - 1 file changed, 20 insertions(+), 23 deletions(-) - -diff --git a/kernel/mdio-netlink.c b/kernel/mdio-netlink.c -index d79cf95..fb8254e 100644 ---- a/kernel/mdio-netlink.c -+++ b/kernel/mdio-netlink.c -@@ -9,17 +9,6 @@ - #include - #include - --static void c45_compat_convert(int *kdev, int *kreg, int udev, int ureg) --{ -- if (!mdio_phy_id_is_c45(udev)) { -- *kdev = udev; -- *kreg = ureg; -- } else { -- *kdev = mdio_phy_id_prtad(udev); -- *kreg = MII_ADDR_C45 | (mdio_phy_id_devad(udev) << 16) | ureg; -- } --} -- - struct mdio_nl_xfer { - struct genl_info *info; - struct sk_buff *msg; -@@ -93,7 +82,6 @@ static int mdio_nl_eval(struct mdio_nl_xfer *xfer) - unsigned long timeout; - u16 regs[8] = { 0 }; - unsigned int pc; -- int dev, reg; - int ret = 0; - - timeout = jiffies + msecs_to_jiffies(xfer->timeout_ms); -@@ -110,11 +98,15 @@ static int mdio_nl_eval(struct mdio_nl_xfer *xfer) - - switch ((enum mdio_nl_op)insn->op) { - case MDIO_NL_OP_READ: -- c45_compat_convert(&dev, ®, -- __arg_ri(insn->arg0, regs), -- __arg_ri(insn->arg1, regs)); -- -- ret = __mdiobus_read(xfer->mdio, dev, reg); -+ if (mdio_phy_id_is_c45(__arg_ri(insn->arg0, regs))) -+ ret = __mdiobus_c45_read(xfer->mdio, -+ mdio_phy_id_prtad(__arg_ri(insn->arg0, regs)), -+ mdio_phy_id_devad(__arg_ri(insn->arg0, regs)), -+ __arg_ri(insn->arg1, regs)); -+ else -+ ret = __mdiobus_read(xfer->mdio, -+ __arg_ri(insn->arg0, regs), -+ __arg_ri(insn->arg1, regs)); - if (ret < 0) - goto exit; - *__arg_r(insn->arg2, regs) = ret; -@@ -122,12 +114,17 @@ static int mdio_nl_eval(struct mdio_nl_xfer *xfer) - break; - - case MDIO_NL_OP_WRITE: -- c45_compat_convert(&dev, ®, -- __arg_ri(insn->arg0, regs), -- __arg_ri(insn->arg1, regs)); -- -- ret = __mdiobus_write(xfer->mdio, dev, reg, -- __arg_ri(insn->arg2, regs)); -+ if (mdio_phy_id_is_c45(__arg_ri(insn->arg0, regs))) -+ ret = __mdiobus_c45_write(xfer->mdio, -+ mdio_phy_id_prtad(__arg_ri(insn->arg0, regs)), -+ mdio_phy_id_devad(__arg_ri(insn->arg0, regs)), -+ __arg_ri(insn->arg1, regs), -+ __arg_ri(insn->arg2, regs)); -+ else -+ ret = __mdiobus_write(xfer->mdio, -+ __arg_ri(insn->arg0, regs), -+ __arg_ri(insn->arg1, regs), -+ __arg_ri(insn->arg2, regs)); - if (ret < 0) - goto exit; - ret = 0; diff --git a/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch b/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch deleted file mode 100644 index 374ad42bd..000000000 --- a/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 95b3011f1ba7719ec9348163f986ead8c57ad997 Mon Sep 17 00:00:00 2001 -From: Antonio Quartulli -Date: Sat, 21 Jan 2023 00:25:40 +0100 -Subject: [PATCH] ovpn-dco: adapt pre/post_doit CBs to new signature - -With linux-6.2.0 the signature of pre/post_doit CBs in the netlink -family structure has been changed. - -Adapt the functions to reflect the new signature. - -Fixes: https://github.com/OpenVPN/ovpn-dco/issues/12 -Signed-off-by: Antonio Quartulli ---- - drivers/net/ovpn-dco/netlink.c | 4 ++-- - linux-compat.h | 6 ++++++ - 2 files changed, 8 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/ovpn-dco/netlink.c b/drivers/net/ovpn-dco/netlink.c -index 1a2932f..e3eb012 100644 ---- a/drivers/net/ovpn-dco/netlink.c -+++ b/drivers/net/ovpn-dco/netlink.c -@@ -148,7 +148,7 @@ ovpn_get_dev_from_attrs(struct net *net, struct nlattr **attrs) - * - * Return: 0 on success or negative error number in case of failure - */ --static int ovpn_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, -+static int ovpn_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, - struct genl_info *info) - { - struct net *net = genl_info_net(info); -@@ -169,7 +169,7 @@ static int ovpn_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, - * @skb: Netlink message with request data - * @info: receiver information - */ --static void ovpn_post_doit(const struct genl_ops *ops, struct sk_buff *skb, -+static void ovpn_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, - struct genl_info *info) - { - struct ovpn_struct *ovpn; -diff --git a/linux-compat.h b/linux-compat.h -index 8aa53f4..c0ee963 100644 ---- a/linux-compat.h -+++ b/linux-compat.h -@@ -22,6 +22,12 @@ - #endif - #endif - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) -+ -+#define genl_split_ops genl_ops -+ -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) */ -+ - #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) - - /** diff --git a/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch b/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch deleted file mode 100644 index 8d5457da1..000000000 --- a/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/drivers/net/ovpn-dco/ovpn.c b/drivers/net/ovpn-dco/ovpn.c -index 66c0191..6cc426a 100644 ---- a/drivers/net/ovpn-dco/ovpn.c -+++ b/drivers/net/ovpn-dco/ovpn.c -@@ -21,6 +21,10 @@ - #include "tcp.h" - #include "udp.h" - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,4,10) -+#include -+#endif -+ - #include - #include - diff --git a/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch b/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch deleted file mode 100644 index 862f30ee8..000000000 --- a/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch +++ /dev/null @@ -1,50 +0,0 @@ ---- a/v4l2loopback.c -+++ b/v4l2loopback.c -@@ -714,7 +714,11 @@ static int vidioc_querycap(struct file * - ->devicenr; - __u32 capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - strlcpy(cap->driver, "v4l2 loopback", sizeof(cap->driver)); -+#else -+ strscpy(cap->driver, "v4l2 loopback", sizeof(cap->driver)); -+#endif - vidioc_fill_name(cap->card, sizeof(cap->card), devnr); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:v4l2loopback-%03d", devnr); -@@ -1220,7 +1224,11 @@ static int vidioc_queryctrl(struct file - if (!cnf) - BUG(); - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - strlcpy(q->name, cnf->name, sizeof(q->name)); -+#else -+ strscpy(q->name, cnf->name, sizeof(q->name)); -+#endif - q->default_value = cnf->def; - q->type = cnf->type; - q->minimum = cnf->min; -@@ -1325,7 +1333,11 @@ static int vidioc_enum_output(struct fil - memset(outp, 0, sizeof(*outp)); - - outp->index = index; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - strlcpy(outp->name, "loopback in", sizeof(outp->name)); -+#else -+ strscpy(outp->name, "loopback in", sizeof(outp->name)); -+#endif - outp->type = V4L2_OUTPUT_TYPE_ANALOG; - outp->audioset = 0; - outp->modulator = 0; -@@ -1384,7 +1396,11 @@ static int vidioc_enum_input(struct file - memset(inp, 0, sizeof(*inp)); - - inp->index = index; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - strlcpy(inp->name, "loopback", sizeof(inp->name)); -+#else -+ strscpy(inp->name, "loopback", sizeof(inp->name)); -+#endif - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->audioset = 0; - inp->tuner = 0; diff --git a/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch b/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch deleted file mode 100644 index 18a1cae3c..000000000 --- a/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/xr_usb_serial_common-1a/xr_usb_serial_common.c -+++ b/xr_usb_serial_common-1a/xr_usb_serial_common.c -@@ -643,8 +643,13 @@ static void xr_usb_serial_tty_close(stru - tty_port_close(&xr_usb_serial->port, tty, filp); - } - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0) -+static ssize_t xr_usb_serial_tty_write(struct tty_struct *tty, -+ const unsigned char *buf, size_t count) -+#else - static int xr_usb_serial_tty_write(struct tty_struct *tty, - const unsigned char *buf, int count) -+#endif - { - struct xr_usb_serial *xr_usb_serial = tty->driver_data; - int stat; diff --git a/openwrt/patch/target-modify_for_armsr.patch b/openwrt/patch/target-modify_for_armsr.patch index 515873ad6..776b8b369 100644 --- a/openwrt/patch/target-modify_for_armsr.patch +++ b/openwrt/patch/target-modify_for_armsr.patch @@ -1,10 +1,10 @@ diff --git a/include/target.mk b/include/target.mk -index b5e3e7f..396fdf8 100644 +index d13902a..72b8059 100644 --- a/include/target.mk +++ b/include/target.mk -@@ -264,6 +264,10 @@ ifeq ($(DUMP),1) - CPU_TYPE ?= riscv64 - CPU_CFLAGS_riscv64:=-mabi=lp64d -march=rv64imafdc +@@ -294,6 +294,10 @@ ifeq ($(DUMP),1) + CPU_CFLAGS := -O2 -pipe + CPU_CFLAGS_generic:=-march=loongarch64 endif + ifeq ($(BOARD),armsr) + CPU_CFLAGS = -O3 -pipe diff --git a/openwrt/patch/target-modify_for_rockchip.patch b/openwrt/patch/target-modify_for_rockchip.patch index 938c00062..30984c376 100644 --- a/openwrt/patch/target-modify_for_rockchip.patch +++ b/openwrt/patch/target-modify_for_rockchip.patch @@ -1,10 +1,10 @@ diff --git a/include/target.mk b/include/target.mk -index b5e3e7f..d655af9 100644 +index d13902a..1a85ede 100644 --- a/include/target.mk +++ b/include/target.mk -@@ -264,6 +264,10 @@ ifeq ($(DUMP),1) - CPU_TYPE ?= riscv64 - CPU_CFLAGS_riscv64:=-mabi=lp64d -march=rv64imafdc +@@ -294,6 +294,10 @@ ifeq ($(DUMP),1) + CPU_CFLAGS := -O2 -pipe + CPU_CFLAGS_generic:=-march=loongarch64 endif + ifeq ($(BOARD),rockchip) + CPU_CFLAGS = -O3 -Wl,--gc-sections -pipe diff --git a/openwrt/patch/target-modify_for_x86_64.patch b/openwrt/patch/target-modify_for_x86_64.patch index f20d8a42b..7f1cad737 100644 --- a/openwrt/patch/target-modify_for_x86_64.patch +++ b/openwrt/patch/target-modify_for_x86_64.patch @@ -1,6 +1,8 @@ +diff --git a/include/target.mk b/include/target.mk +index d13902a..32037b6 100644 --- a/include/target.mk +++ b/include/target.mk -@@ -208,7 +208,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt +@@ -233,7 +233,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt ifeq ($(DUMP),1) BuildTarget=$(BuildTargets/DumpCurrent) diff --git a/openwrt/patch/util-linux/201-util-linux_ntfs3.patch b/openwrt/patch/util-linux/201-util-linux_ntfs3.patch deleted file mode 100644 index 04c4ebf81..000000000 --- a/openwrt/patch/util-linux/201-util-linux_ntfs3.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- a/libblkid/src/superblocks/ntfs.c -+++ b/libblkid/src/superblocks/ntfs.c -@@ -248,7 +248,7 @@ int blkid_probe_is_ntfs(blkid_probe pr) - - const struct blkid_idinfo ntfs_idinfo = - { -- .name = "ntfs", -+ .name = "ntfs3", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ntfs, - .magics = ---- a/libmount/src/utils.c -+++ b/libmount/src/utils.c -@@ -436,7 +436,7 @@ const char *mnt_statfs_get_fstype(struct statfs *vfs) - case STATFS_NCP_MAGIC: return "ncp"; - case STATFS_NFS_MAGIC: return "nfs"; - case STATFS_NILFS_MAGIC: return "nilfs2"; -- case STATFS_NTFS_MAGIC: return "ntfs"; -+ case STATFS_NTFS_MAGIC: return "ntfs3"; - case STATFS_OCFS2_MAGIC: return "ocfs2"; - case STATFS_OMFS_MAGIC: return "omfs"; - case STATFS_OPENPROMFS_MAGIC: return "openpromfs"; diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 1d02d4bdf..75cf5a456 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -2,100 +2,57 @@ # Rockchip - rkbin & u-boot rm -rf package/boot/rkbin package/boot/uboot-rockchip package/boot/arm-trusted-firmware-rockchip -if [ "$platform" = "rk3568" ]; then - git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip - git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip -else - git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip -b v2023.04 - git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip -b 0419 -fi +git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip +git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip ######## OpenWrt Patches ######## # source -if [ "$version" = "rc2" ]; then - sed -i '/mirror2.openwrt.org/a\push @mirrors, '\''https://source.cooluc.com'\'';' scripts/download.pl -else - sed -i '/@OPENWRT/a\\t\t"https://source.cooluc.com",' scripts/projectsmirrors.json -fi - -[ "$version" = "rc2" ] && generic=generic || generic=generic-24.10 +sed -i '/@OPENWRT/a\\t\t"https://source.cooluc.com",' scripts/projectsmirrors.json # tools: add llvm/clang toolchain -curl -s https://$mirror/openwrt/patch/$generic/0001-tools-add-llvm-clang-toolchain.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch | patch -p1 # tools: add upx tools -curl -s https://$mirror/openwrt/patch/$generic/0002-tools-add-upx-tools.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch | patch -p1 # rootfs: upx compression # include/rootfs.mk -curl -s https://$mirror/openwrt/patch/$generic/0003-rootfs-add-upx-compression-support.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch | patch -p1 # rootfs: add r/w (0600) permissions for UCI configuration files # include/rootfs.mk -curl -s https://$mirror/openwrt/patch/$generic/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 # rootfs: Add support for local kmod installation sources -curl -s https://$mirror/openwrt/patch/$generic/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 - -# BTF: fix failed to validate module -# config/Config-kernel.in patch -curl -s https://$mirror/openwrt/patch/$generic/0006-kernel-add-MODULE_ALLOW_BTF_MISMATCH-option.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 # kernel: Add support for llvm/clang compiler -curl -s https://$mirror/openwrt/patch/$generic/0007-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 - -# toolchain: Add libquadmath to the toolchain -curl -s https://$mirror/openwrt/patch/$generic/0008-libquadmath-Add-libquadmath-to-the-toolchain.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 # build: kernel: add out-of-tree kernel config -curl -s https://$mirror/openwrt/patch/$generic/0009-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 # kernel: linux-6.11 config -curl -s https://$mirror/openwrt/patch/$generic/0010-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 # meson: add platform variable to cross-compilation file -curl -s https://$mirror/openwrt/patch/$generic/0011-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 -if [ "$version" = "snapshots-24.10" ]; then - # kernel 6.12: add legacy cgroup v1 memory controller - curl -s https://$mirror/openwrt/patch/$generic/0012-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 - # kernel 6.12: add linux-rt support for aarch64/x86_64 - curl -s https://$mirror/openwrt/patch/$generic/0013-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 -fi +# kernel 6.12: add legacy cgroup v1 memory controller +curl -s https://$mirror/openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 -# kernel: enable Multi-Path TCP -[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/$generic/0014-kernel-enable-Multi-Path-TCP-for-SMALL_FLASH-targets.patch | patch -p1 - -# mold -if [ "$ENABLE_MOLD" = "y" ] && [ "$version" = "rc2" ]; then - curl -s https://$mirror/openwrt/patch/generic/mold/0001-build-add-support-to-use-the-mold-linker-for-package.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0002-treewide-opt-out-of-tree-wide-mold-usage.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0003-toolchain-add-mold-as-additional-linker.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0004-tools-add-mold-a-modern-linker.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0005-build-replace-SSTRIP_ARGS-with-SSTRIP_DISCARD_TRAILI.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0006-config-add-a-knob-to-use-the-mold-linker-for-package.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0007-rules-prepare-to-use-different-linkers.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/generic/mold/0008-tools-mold-update-to-2.34.1.patch | patch -p1 -fi -[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/generic-24.10/203-tools-mold-update-to-2.34.1.patch | patch -p1 +# kernel 6.12: add linux-rt support for aarch64/x86_64 +curl -s https://$mirror/openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 # attr no-mold [ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile ######## OpenWrt Patches End ######## -# dwarves: Fix a dwarf type DW_ATE_unsigned_1024 to btf encoding issue -if [ "$version" = "rc2" ]; then - mkdir -p tools/dwarves/patches - curl -s https://$mirror/openwrt/patch/openwrt-6.x/dwarves/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch > tools/dwarves/patches/100-btf_encoder-Fix-a-dwarf-type-DW_ATE_unsigned_1024-to-btf-encoding-issue.patch -fi - # dwarves 1.25 -if [ "$version" = "snapshots-24.10" ]; then - rm -rf tools/dwarves - git clone https://$github/sbwml/tools_dwarves tools/dwarves -fi +rm -rf tools/dwarves +git clone https://$github/sbwml/tools_dwarves tools/dwarves # x86 - disable intel_pstate & mitigations sed -i 's/noinitrd/noinitrd intel_pstate=disable mitigations=off/g' target/linux/x86/image/grub-efi.cfg @@ -110,7 +67,7 @@ if [ "$ENABLE_UHTTPD" != "y" ]; then sed -i 's/+uhttpd /+luci-nginx /g' feeds/luci/collections/luci-light/Makefile sed -i "s/+luci /+luci-nginx /g" feeds/luci/collections/luci-ssl-openssl/Makefile sed -i "s/+luci /+luci-nginx /g" feeds/luci/collections/luci-ssl/Makefile - if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then + if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then sed -i 's/+uhttpd +uhttpd-mod-ubus /+luci-nginx /g' feeds/packages/net/wg-installer/Makefile sed -i '/uhttpd-mod-ubus/d' feeds/luci/collections/luci-light/Makefile sed -i 's/+luci-nginx \\$/+luci-nginx/' feeds/luci/collections/luci-light/Makefile @@ -148,9 +105,6 @@ fi if [ "$ENABLE_GLIBC" = "y" ]; then # musl-libc git clone https://$gitea/sbwml/package_libs_musl-libc package/libs/musl-libc - # bump fstools version - [ "$version" = "rc2" ] && rm -rf package/system/fstools - [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/system/fstools package/system/fstools # glibc-common curl -s https://$mirror/openwrt/patch/glibc/glibc-common.patch | patch -p1 # glibc-common - locale data @@ -164,52 +118,25 @@ if [ "$ENABLE_GLIBC" = "y" ]; then sed -i "/disable-profile/d" toolchain/glibc/common.mk fi -# Mbedtls AES & GCM Crypto Extensions -if [ ! "$platform" = "x86_64" ] && [ "$version" = "rc2" ]; then - curl -s https://$mirror/openwrt/patch/mbedtls-23.05/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch > package/libs/mbedtls/patches/200-Implements-AES-and-GCM-with-ARMv8-Crypto-Extensions.patch - curl -s https://$mirror/openwrt/patch/mbedtls-23.05/mbedtls.patch | patch -p1 -fi - -if [ "$version" = "rc2" ]; then - # util-linux - ntfs3 - mkdir -p package/utils/util-linux/patches - curl -s https://$mirror/openwrt/patch/util-linux/201-util-linux_ntfs3.patch > package/utils/util-linux/patches/201-util-linux_ntfs3.patch - # fstools - enable any device with non-MTD rootfs_data volume - curl -s https://$mirror/openwrt/patch/fstools/Makefile > package/system/fstools/Makefile - sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/system/fstools/Makefile - mkdir -p package/system/fstools/patches - curl -s https://$mirror/openwrt/patch/fstools/200-use-ntfs3-instead-of-ntfs.patch > package/system/fstools/patches/200-use-ntfs3-instead-of-ntfs.patch - curl -s https://$mirror/openwrt/patch/fstools/201-fstools-set-ntfs3-utf8.patch > package/system/fstools/patches/201-fstools-set-ntfs3-utf8.patch - if [ "$ENABLE_GLIBC" = "y" ]; then - curl -s https://$mirror/openwrt/patch/fstools/glibc/0001-libblkid-tiny-add-support-for-XFS-superblock.patch > package/system/fstools/patches/0001-libblkid-tiny-add-support-for-XFS-superblock.patch - curl -s https://$mirror/openwrt/patch/fstools/glibc/0003-block-add-xfsck-support.patch > package/system/fstools/patches/0003-block-add-xfsck-support.patch - curl -s https://$mirror/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data-new-version.patch > package/system/fstools/patches/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch - else - curl -s https://$mirror/openwrt/patch/fstools/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch > package/system/fstools/patches/202-fstools-support-extroot-for-non-MTD-rootfs_data.patch - fi -else - # fstools - rm -rf package/system/fstools - git clone https://$github/sbwml/package_system_fstools -b openwrt-24.10 package/system/fstools - # util-linux - rm -rf package/utils/util-linux - git clone https://$github/sbwml/package_utils_util-linux -b openwrt-24.10 package/utils/util-linux -fi +# fstools +rm -rf package/system/fstools +git clone https://$github/sbwml/package_system_fstools -b openwrt-24.10 package/system/fstools +# util-linux +rm -rf package/utils/util-linux +git clone https://$github/sbwml/package_utils_util-linux -b openwrt-24.10 package/utils/util-linux # Shortcut Forwarding Engine git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe # dnsmasq -if [ "$version" = "snapshots-24.10" ]; then +if [ "$version" = "dev" ]; then curl -s https://$mirror/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch | patch -p1 [ "$?" -ne 0 ] && curl -s https://init2.cooluc.com/openwrt/patch/dnsmasq/dnsmasq.init > package/network/services/dnsmasq/files/dnsmasq.init fi # Patch FireWall 4 -if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then - # firewall4 - master - [ "$version" = "rc2" ] && rm -rf package/network/config/firewall4 - [ "$version" = "rc2" ] && cp -a ../master/openwrt/package/network/config/firewall4 package/network/config/firewall4 +if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then + # firewall4 sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/network/config/firewall4/Makefile mkdir -p package/network/config/firewall4/patches # fix ct status dnat @@ -249,21 +176,15 @@ git clone https://$github/sbwml/package_new_natflow package/new/natflow # Patch Luci add nft_fullcone/bcm_fullcone & shortcut-fe & natflow & ipv6-nat & custom nft command option pushd feeds/luci - curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 - [ "$version" = "snapshots-24.10" ] && { - curl -s https://$mirror/openwrt/patch/firewall4/$openwrt_version/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 - } + curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 + curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 popd # openssl - quictls -if [ "$version" = "rc2" ]; then - rm -rf package/libs/openssl - cp -a ../master/openwrt-23.05/package/libs/openssl package/libs/openssl -fi pushd package/libs/openssl/patches curl -sO https://$mirror/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch curl -sO https://$mirror/openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch @@ -335,16 +256,12 @@ git clone https://$github/sbwml/feeds_packages_net_curl feeds/packages/net/curl # Docker rm -rf feeds/luci/applications/luci-app-dockerman git clone https://$gitea/sbwml/luci-app-dockerman -b openwrt-23.05 feeds/luci/applications/luci-app-dockerman -if [ "$version" = "snapshots-24.10" ] || [ "$version" = "rc2" ]; then +if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} git clone https://$github/sbwml/packages_utils_docker feeds/packages/utils/docker git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd git clone https://$github/sbwml/packages_utils_containerd feeds/packages/utils/containerd git clone https://$github/sbwml/packages_utils_runc feeds/packages/utils/runc - [ "$version" = "rc2" ] && { - rm -rf feeds/packages/utils/docker-compose - cp -a ../master/packages/utils/docker-compose feeds/packages/utils/docker-compose - } fi sed -i '/sysctl.d/d' feeds/packages/utils/dockerd/Makefile pushd feeds/packages @@ -379,43 +296,23 @@ rm -rf feeds/{packages/net/miniupnpd,luci/applications/luci-app-upnp} git clone https://$gitea/sbwml/miniupnpd feeds/packages/net/miniupnpd -b v2.3.7 git clone https://$gitea/sbwml/luci-app-upnp feeds/luci/applications/luci-app-upnp -b main -# nginx-util - fix gcc13 -if [ "$version" = "rc2" ]; then - pushd feeds/packages - curl -s https://$mirror/openwrt/nginx/nginx-util/0001-nginx-util-fix-compilation-with-GCC13.patch | patch -p1 - curl -s https://$mirror/openwrt/nginx/nginx-util/0002-nginx-util-move-to-pcre2.patch | patch -p1 - popd -fi - # nginx - latest version rm -rf feeds/packages/net/nginx -git clone https://$github/sbwml/feeds_packages_net_nginx feeds/packages/net/nginx -b "$openwrt_version" +git clone https://$github/sbwml/feeds_packages_net_nginx feeds/packages/net/nginx -b openwrt-24.10 sed -i 's/procd_set_param stdout 1/procd_set_param stdout 0/g;s/procd_set_param stderr 1/procd_set_param stderr 0/g' feeds/packages/net/nginx/files/nginx.init # nginx - ubus sed -i 's/ubus_parallel_req 2/ubus_parallel_req 6/g' feeds/packages/net/nginx/files-luci-support/60_nginx-luci-support sed -i '/ubus_parallel_req/a\ ubus_script_timeout 300;' feeds/packages/net/nginx/files-luci-support/60_nginx-luci-support -# nginx - uwsgi timeout & enable brotli +# nginx - config curl -s https://$mirror/openwrt/nginx/luci.locations > feeds/packages/net/nginx/files-luci-support/luci.locations -curl -s https://$mirror/openwrt/nginx/${openwrt_version}-uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template - -# zstd - bump version -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/utils/zstd - cp -a ../master/packages/utils/zstd feeds/packages/utils/zstd -fi +curl -s https://$mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template # opkg mkdir -p package/system/opkg/patches curl -s https://$mirror/openwrt/patch/opkg/900-opkg-download-disable-hsts.patch > package/system/opkg/patches/900-opkg-download-disable-hsts.patch -# uwsgi - bump version -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/net/uwsgi - cp -a ../master/packages/net/uwsgi feeds/packages/net/uwsgi -fi - # uwsgi - fix timeout sed -i '$a cgi-timeout = 600' feeds/packages/net/uwsgi/files-luci-support/luci-*.ini sed -i '/limit-as/c\limit-as = 5000' feeds/packages/net/uwsgi/files-luci-support/luci-webui.ini @@ -444,24 +341,12 @@ popd # Luci diagnostics.js sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/diagnostics.js -# luci - drop ethernet port status -[ "$version" = "rc2" ] && rm -f feeds/luci/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/29_ports.js - -# luci - rollback dhcp.js -[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/luci/dhcp/openwrt-23.05-dhcp.js > feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js - # luci - disable wireless WPA3 [ "$platform" = "bcm53xx" ] && sed -i -e '/if (has_ap_sae || has_sta_sae) {/{N;N;N;N;d;}' feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js -# ppp - 2.5.0 -if [ "$version" = "rc2" ]; then - rm -rf package/network/services/ppp - git clone https://$github/sbwml/package_network_services_ppp package/network/services/ppp -fi - # odhcpd RFC-9096 mkdir -p package/network/services/odhcpd/patches -curl -s https://$mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-$openwrt_version.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch +curl -s https://$mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch pushd feeds/luci curl -s https://$mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 popd diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 3153db53f..6b8a8c56b 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -3,22 +3,12 @@ ################################################################# # autocore -if [ "$version" = "rc2" ]; then - git clone https://$github/sbwml/autocore-arm -b openwrt-23.05 package/system/autocore -else - git clone https://$github/sbwml/autocore-arm -b openwrt-24.10 package/system/autocore -fi +git clone https://$github/sbwml/autocore-arm -b openwrt-24.10 package/system/autocore # rockchip - target - r4s/r5s only rm -rf target/linux/rockchip -git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-23.05 +git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-24.10 -# x86_64 - target 6.6 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.6 > target/linux/x86/64/config-6.6 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.6 > target/linux/x86/config-6.6 -mkdir -p target/linux/x86/patches-6.6 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.6/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.6/100-fix_cs5535_clockevt.patch -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.6/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.6/103-pcengines_apu6_platform.patch # x86_64 - target 6.12 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.12 > target/linux/x86/64/config-6.12 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/config-6.12 @@ -26,8 +16,8 @@ mkdir -p target/linux/x86/patches-6.12 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.12/100-fix_cs5535_clockevt.patch curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.12/103-pcengines_apu6_platform.patch # x86_64 - target -sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.6/" target/linux/x86/Makefile -sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.12' target/linux/x86/Makefile +sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.12/" target/linux/x86/Makefile +sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network @@ -39,30 +29,30 @@ git clone https://nanopi:nanopi@$gitea/sbwml/brcmfmac-firmware-4366b-pcie packag # armsr/armv8 rm -rf target/linux/armsr -git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b openwrt-23.05 +git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b main -# kernel - 6.x -curl -s https://$mirror/tags/kernel-6.6 > include/kernel-6.6 +# kernel - 6.12 curl -s https://$mirror/tags/kernel-6.12 > include/kernel-6.12 # kenrel Vermagic sed -ie 's/^\(.\).*vermagic$/\1cp $(TOPDIR)\/.vermagic $(LINUX_DIR)\/.vermagic/' include/kernel-defaults.mk -grep HASH include/kernel-$kernel_version | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic +grep HASH include/kernel-6.12 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic # kernel generic patches -rm -rf target/linux/generic -local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-$kernel_version) -release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-$kernel_version | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') +curl -s https://$mirror/openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch | patch -p1 +local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-6.12) +release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-6.12 | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then - git clone https://$github/sbwml/target_linux_generic -b openwrt-23.05 target/linux/generic --depth=1 + git clone https://$github/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 else if [ "$(whoami)" = "runner" ]; then git_name=private - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-23.05 target/linux/generic --depth=1 + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 elif [ "$(whoami)" = "sbwml" ]; then - git clone https://$gitea/sbwml/target_linux_generic -b openwrt-23.05 target/linux/generic --depth=1 + git clone https://$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 fi fi +cp -a target/linux/generic-6.12/* target/linux/generic # bcm53xx - fix build kernel with clang [ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch target/linux/generic/hack-6.12/220-arm-gc_sections.patch @@ -100,118 +90,93 @@ pushd package/kernel/linux/modules curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/wpan.mk popd -# BBRv3 - linux-6.6/6.12 -pushd target/linux/generic/backport-"$kernel_version" - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch - [ "$version" = "snapshots-24.10" ] && curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch +# BBRv3 - linux-6.12 +pushd target/linux/generic/backport-6.12 + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch popd -# LRNG v54/56 - linux-6.6/6.12 -pushd target/linux/generic/hack-$kernel_version - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0003-LRNG-proc-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-"$kernel_version"/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch +# LRNG - 6.12 +pushd target/linux/generic/hack-6.12 + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch popd # linux-rt - i915 -if [ "$version" = "snapshots-24.10" ]; then - pushd target/linux/generic/hack-6.12 - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch - popd -fi +pushd target/linux/generic/hack-6.12 + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch + curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch +popd # linux-firmware: rtw89 / rtl8723d / rtl8821c /i915 firmware rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware -if [ "$version" = "snapshots-24.10" ]; then - # rtl8812au-ct - fix linux-6.12 - rm -rf package/kernel/rtl8812au-ct - git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct -b v6.11 - # add rtl8812au-ac - git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac -b v6.11 -else - # rtl8812au-ct - fix linux-6.6 - rm -rf package/kernel/rtl8812au-ct - git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct - # add rtl8812au-ac - git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac -fi +# rtl8812au-ct - fix linux-6.12 +rm -rf package/kernel/rtl8812au-ct +git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct -b v6.11 +# add rtl8812au-ac +git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac -b v6.11 # mt76 - 2024-10-11 rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile -[ "$version" = "snapshots-24.10" ] && { - curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch - curl -s https://$mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch -} - -# iwinfo: add mt7922 device id -if [ "$version" = "rc2" ]; then - mkdir -p package/network/utils/iwinfo/patches - curl -s https://$mirror/openwrt/patch/openwrt-6.x/iwinfo/0001-devices-add-MediaTek-MT7922-device-id.patch > package/network/utils/iwinfo/patches/0001-devices-add-MediaTek-MT7922-device-id.patch -fi - -# iwinfo: add rtl8812/14/21au devices -[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/iwinfo/0004-add-rtl8812au-devices.patch > package/network/utils/iwinfo/patches/0004-add-rtl8812au-devices.patch +curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +curl -s https://$mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch # wireless-regdb -if [ "$version" = "rc2" ]; then - rm -rf package/firmware/wireless-regdb - cp -a ../master/openwrt/package/firmware/wireless-regdb package/firmware/wireless-regdb -fi curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch # mac80211 - 6.11 rm -rf package/kernel/mac80211 -git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b $openwrt_version +git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 # ath10k-ct rm -rf package/kernel/ath10k-ct @@ -219,32 +184,17 @@ git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-c # kernel patch # btf: silence btf module warning messages -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-$kernel_version/990-btf-silence-btf-module-warning-messages.patch +curl -s https://$mirror/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-6.12/990-btf-silence-btf-module-warning-messages.patch # cpu model -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/pending-$kernel_version/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch +curl -s https://$mirror/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/hack-6.12/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch # fullcone -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-$kernel_version/952-net-conntrack-events-support-multiple-registrant.patch +curl -s https://$mirror/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-6.12/952-net-conntrack-events-support-multiple-registrant.patch # bcm-fullcone -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-$kernel_version/982-add-bcm-fullcone-support.patch -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-$kernel_version/983-add-bcm-fullcone-nft_masq-support.patch +curl -s https://$mirror/openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-6.12/982-add-bcm-fullcone-support.patch +curl -s https://$mirror/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-6.12/983-add-bcm-fullcone-nft_masq-support.patch # shortcut-fe -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-$kernel_version/601-netfilter-export-udp_get_timeouts-function.patch -curl -s https://$mirror/openwrt/patch/kernel-$kernel_version/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-$kernel_version/953-net-patch-linux-kernel-to-support-shortcut-fe.patch - -# backport - 6.8 fast-path-variables -if [ "$version" = "rc2" ] && [ "$platform" != "bcm53xx" ]; then - curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/901-v6.8-cache-enforce-cache-groups.patch > target/linux/generic/backport-6.6/901-v6.8-cache-enforce-cache-groups.patch - curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch > target/linux/generic/backport-6.6/902-v6.8-netns-ipv4-reorganize-netns_ipv4-fast-path-variables.patch - curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch > target/linux/generic/backport-6.6/903-v6.8-net-device-reorganize-net_device-fast-path-variables.patch - curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/904-v6.8-tcp-reorganize-tcp_sock-fast-path-variables.patch > target/linux/generic/backport-6.6/904-v6.8-tcp-reorganize-tcp_sock-fast-path-variables.patch - curl -s https://$mirror/openwrt/patch/kernel-6.6/backport/905-v6.8-tcp-move-tp-scaling_ratio-to-tcp_sock_read_txrx-grou.patch > target/linux/generic/backport-6.6/905-v6.8-tcp-move-tp-scaling_ratio-to-tcp_sock_read_txrx-grou.patch -fi - -# ubnt-ledbar - fix linux-6.x -if [ "$version" = "rc2" ]; then - rm -rf package/kernel/ubnt-ledbar - cp -a ../master/openwrt/package/kernel/ubnt-ledbar package/kernel/ubnt-ledbar -fi +curl -s https://$mirror/openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-6.12/601-netfilter-export-udp_get_timeouts-function.patch +curl -s https://$mirror/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.12/953-net-patch-linux-kernel-to-support-shortcut-fe.patch # RTC if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ]; then diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 92fd8cd57..7f9f13a8f 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -15,7 +15,7 @@ git clone https://$github/sbwml/default-settings package/new/default-settings git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager # luci-app-webdav -[ "$version" = "snapshots-24.10" ] && git clone https://$github/sbwml/luci-app-webdav package/new/luci-app-webdav +git clone https://$github/sbwml/luci-app-webdav package/new/luci-app-webdav # ddns - fix boot sed -i '/boot()/,+2d' feeds/packages/net/ddns-scripts/files/etc/init.d/ddns @@ -23,28 +23,15 @@ sed -i '/boot()/,+2d' feeds/packages/net/ddns-scripts/files/etc/init.d/ddns # nlbwmon - disable syslog sed -i 's/stderr 1/stderr 0/g' feeds/packages/net/nlbwmon/files/nlbwmon.init -# boost - bump version -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/libs/boost - cp -a ../master/packages/libs/boost feeds/packages/libs/boost -fi - # pcre - 8.45 -if [ "$version" = "snapshots-24.10" ]; then - mkdir -p package/libs/pcre - curl -s https://$mirror/openwrt/patch/pcre/Makefile > package/libs/pcre/Makefile - curl -s https://$mirror/openwrt/patch/pcre/Config.in > package/libs/pcre/Config.in -fi +mkdir -p package/libs/pcre +curl -s https://$mirror/openwrt/patch/pcre/Makefile > package/libs/pcre/Makefile +curl -s https://$mirror/openwrt/patch/pcre/Config.in > package/libs/pcre/Config.in # lrzsz - 0.12.20 rm -rf feeds/packages/utils/lrzsz git clone https://$github/sbwml/packages_utils_lrzsz package/new/lrzsz -# irqbalance - openwrt master -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/utils/irqbalance - cp -a ../master/packages/utils/irqbalance feeds/packages/utils/irqbalance -fi # irqbalance: disable build with numa if [ "$ENABLE_DPDK" = "y" ]; then curl -s https://$mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch @@ -52,10 +39,6 @@ if [ "$ENABLE_DPDK" = "y" ]; then fi # frpc -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/net/frp - cp -a ../master/packages/net/frp feeds/packages/net/frp -fi sed -i 's/procd_set_param stdout $stdout/procd_set_param stdout 0/g' feeds/packages/net/frp/files/frpc.init sed -i 's/procd_set_param stderr $stderr/procd_set_param stderr 0/g' feeds/packages/net/frp/files/frpc.init sed -i 's/stdout stderr //g' feeds/packages/net/frp/files/frpc.init @@ -65,8 +48,8 @@ sed -i 's/env conf_inc/env conf_inc enable/g' feeds/packages/net/frp/files/frpc. sed -i "s/'conf_inc:list(string)'/& \\\\/" feeds/packages/net/frp/files/frpc.init sed -i "/conf_inc:list/a\\\t\t\'enable:bool:0\'" feeds/packages/net/frp/files/frpc.init sed -i '/procd_open_instance/i\\t\[ "$enable" -ne 1 \] \&\& return 1\n' feeds/packages/net/frp/files/frpc.init -curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token-${openwrt_version}.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag-${openwrt_version}.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch | patch -p1 # natmap pushd feeds/luci @@ -120,10 +103,6 @@ rm -rf feeds/packages/net/alist feeds/luci/applications/luci-app-alist git clone https://$github/sbwml/openwrt-alist package/new/alist # netdata -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/admin/netdata - cp -a ../master/packages/admin/netdata feeds/packages/admin/netdata -fi sed -i 's/syslog/none/g' feeds/packages/admin/netdata/files/netdata.conf # qBittorrent @@ -134,7 +113,7 @@ git clone https://$github/UnblockNeteaseMusic/luci-app-unblockneteasemusic packa sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new/luci-app-unblockneteasemusic/root/usr/share/luci/menu.d/luci-app-unblockneteasemusic.json # Theme -git clone --depth 1 https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon -b $openwrt_version +git clone --depth 1 https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon # Mosdns git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns @@ -143,10 +122,6 @@ git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns git clone https://$github/sbwml/OpenAppFilter --depth=1 package/new/OpenAppFilter # iperf3 -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/net/iperf3 - cp -a ../master/packages/net/iperf3 feeds/packages/net/iperf3 -fi sed -i "s/D_GNU_SOURCE/D_GNU_SOURCE -funroll-loops/g" feeds/packages/net/iperf3/Makefile # nlbwmon diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index bdeaad819..9d58fa5aa 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -1,56 +1,23 @@ #!/bin/bash -e -# Fix build for linux-6.6/6.12 +# Fix build for 6.12 # cryptodev-linux mkdir -p package/kernel/cryptodev-linux/patches -if [ "$version" = "rc2" ]; then - curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.6/001-Fix-build-for-Linux-6.3-rc1.patch > package/kernel/cryptodev-linux/patches/001-Fix-build-for-Linux-6.3-rc1.patch - curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.6/002-fix-build-for-linux-6.7-rc1.patch > package/kernel/cryptodev-linux/patches/002-fix-build-for-linux-6.7-rc1.patch -else - curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch - curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch > package/kernel/cryptodev-linux/patches/0006-Exclude-unused-struct-since-Linux-6.5.patch -fi +curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch +curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch > package/kernel/cryptodev-linux/patches/0006-Exclude-unused-struct-since-Linux-6.5.patch # gpio-button-hotplug -[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.6.patch | patch -p1 curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 -# gpio-nct5104d -[ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-build-for-linux-6.6.patch | patch -p1 - -# dmx_usb_module -if [ "$version" = "rc2" ]; then - mkdir -p feeds/packages/libs/dmx_usb_module/patches - curl -s https://$mirror/openwrt/patch/packages-patches/dmx_usb_module/900-fix-linux-6.6.patch > feeds/packages/libs/dmx_usb_module/patches/900-fix-linux-6.6.patch -fi - # jool -[ "$version" = "rc2" ] && \ - curl -s https://$mirror/openwrt/patch/packages-patches/jool/Makefile > feeds/packages/net/jool/Makefile || \ - curl -s https://$mirror/openwrt/patch/packages-patches/jool/Makefile.24 > feeds/packages/net/jool/Makefile - -# mdio-netlink -if [ "$version" = "rc2" ]; then - mkdir -p feeds/packages/kernel/mdio-netlink/patches - curl -s https://$mirror/openwrt/patch/packages-patches/mdio-netlink/001-mdio-netlink-rework-C45-to-work-with-net-next.patch > feeds/packages/kernel/mdio-netlink/patches/001-mdio-netlink-rework-C45-to-work-with-net-next.patch -fi +curl -s https://$mirror/openwrt/patch/packages-patches/jool/Makefile > feeds/packages/net/jool/Makefile # ovpn-dco mkdir -p feeds/packages/kernel/ovpn-dco/patches -if [ "$version" = "rc2" ]; then - curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch > feeds/packages/kernel/ovpn-dco/patches/100-ovpn-dco-adapt-pre-post_doit-CBs-to-new-signature.patch - curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/900-fix-linux-6.6.patch > feeds/packages/kernel/ovpn-dco/patches/900-fix-linux-6.6.patch -fi curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch > feeds/packages/kernel/ovpn-dco/patches/901-fix-linux-6.11.patch curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch > feeds/packages/kernel/ovpn-dco/patches/902-fix-linux-6.12.patch -# siit -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/net/siit - cp -a ../master/packages/net/siit feeds/packages/net/siit -fi - # libpfring rm -rf feeds/packages/libs/libpfring mkdir -p feeds/packages/libs/libpfring/patches @@ -66,40 +33,23 @@ mkdir -p package/kernel/nat46/patches curl -s https://$mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch > package/kernel/nat46/patches/100-fix-build-with-kernel-6.9.patch curl -s https://$mirror/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch > package/kernel/nat46/patches/101-fix-build-with-kernel-6.12.patch -# v4l2loopback - 6.12 -if [ "$version" = "rc2" ]; then - mkdir -p feeds/packages/kernel/v4l2loopback/patches - curl -s https://$mirror/openwrt/patch/packages-patches/v4l2loopback/100-fix-build-with-linux-6.12.patch > feeds/packages/kernel/v4l2loopback/patches/100-fix-build-with-linux-6.12.patch -fi - # openvswitch -[ "$version" = "snapshots-24.10" ] && sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile +sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile # rtpengine -[ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch +curl -s https://$mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch -# ubootenv-nvram - 6.12 (openwrt-23.05.5) +# ubootenv-nvram - 6.12 mkdir -p package/kernel/ubootenv-nvram/patches curl -s https://$mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.12.patch # packages pushd feeds/packages - # xr_usb_serial_common - [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/23a3ea2d6b3779cd48d318b95a3c72cad9433d50.patch | patch -p1 - # fix linux-6.6 - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/900-fix-linux-6.6.patch > libs/xr_usb_serial_common/patches/900-fix-linux-6.6.patch - # fix linux-6.12 - [ "$version" = "snapshots-24.10" ] && curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch - # coova-chilli - [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/9975e855adcfc24939080a5e0279e0a90553347b.patch | patch -p1 - [ "$version" = "rc2" ] && curl -s https://github.com/openwrt/packages/commit/c0683d3f012096fc7b2fbe8b8dc81ea424945e9b.patch | patch -p1 + # xr_usb_serial_common linux-6.12 + curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch popd # xtables-addons -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/net/xtables-addons - cp -a ../master/packages/net/xtables-addons feeds/packages/net/xtables-addons -fi curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch > feeds/packages/net/xtables-addons/patches/302-fix-build-for-linux-6.12rc2.patch @@ -110,12 +60,7 @@ pushd feeds/telephony git clone https://$github/sbwml/feeds_telephony_libs_dahdi-linux libs/dahdi-linux popd -# routing - batman-adv -if [ "$version" = "rc2" ]; then - rm -rf feeds/routing/batman-adv - cp -a ../master/routing/batman-adv feeds/routing/batman-adv -fi -# fix build with linux-6.12 +# routing - batman-adv fix build with linux-6.12 curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch > feeds/routing/batman-adv/patches/901-fix-linux-6.12rc2-builds.patch # bcm53xx diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 17866cd12..c3272ecdc 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,11 +1,7 @@ #!/bin/bash -######################### temp fix ########################### -if [ "$version" = "snapshots-24.10" ]; then - # apk-tools - curl -s https://$mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch -fi -######################### temp fix ########################### +# apk-tools +curl -s https://$mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile @@ -14,58 +10,23 @@ sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/l sed -i '/PKG_BUILD_FLAGS/ s/$/ no-gc-sections/' package/boot/grub2/Makefile # haproxy - fix build with quictls -[ "$version" = "snapshots-24.10" ] && sed -i '/USE_QUIC_OPENSSL_COMPAT/d' feeds/packages/net/haproxy/Makefile +sed -i '/USE_QUIC_OPENSSL_COMPAT/d' feeds/packages/net/haproxy/Makefile # xdp-tools rm -rf package/network/utils/xdp-tools -git clone https://$github/sbwml/package_network_utils_xdp-tools package/network/utils/xdp-tools -b $openwrt_version - -# fix gcc13 -if [ "$USE_GCC13" = "y" ] || [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then - if [ "$version" = "rc2" ]; then - # libwebsockets - mkdir -p feeds/packages/libs/libwebsockets/patches - pushd feeds/packages/libs/libwebsockets/patches - curl -sLO https://raw.githubusercontent.com/openwrt/packages/bcd970fb4ff6029fbf612dccf6d8c2902a65e20e/libs/libwebsockets/patches/010-fix-enum-int-mismatch-openssl.patch - curl -sLO https://raw.githubusercontent.com/openwrt/packages/bcd970fb4ff6029fbf612dccf6d8c2902a65e20e/libs/libwebsockets/patches/011-fix-enum-int-mismatch-mbedtls.patch - curl -sLO https://raw.githubusercontent.com/openwrt/packages/94bd1ca8bad053a772a3ea8cb06ce59241fb9a57/libs/libwebsockets/patches/100-fix-uninitialized-variable-usage.patch - popd - fi -fi +git clone https://$github/sbwml/package_network_utils_xdp-tools package/network/utils/xdp-tools # fix gcc14 if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then # iproute2 rm -rf package/network/utils/iproute2 git clone https://$github/sbwml/package_network_utils_iproute2 package/network/utils/iproute2 - # wsdd2 - if [ "$ENABLE_GLIBC" != "y" ]; then - [ "$version" = "rc2" ] && mkdir -p feeds/packages/net/wsdd2/patches - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/wsdd2/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch > feeds/packages/net/wsdd2/patches/100-wsdd2-cast-from-pointer-to-integer-of-different-size.patch - fi # libunwind rm -rf package/libs/libunwind git clone https://$github/sbwml/package_libs_libunwind package/libs/libunwind - # mbedtls - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/mbedtls/900-tests-fix-calloc-argument-list-gcc-14-fix.patch > package/libs/mbedtls/patches/900-tests-fix-calloc-argument-list-gcc-14-fix.patch # linux-atm rm -rf package/network/utils/linux-atm git clone https://$github/sbwml/package_network_utils_linux-atm package/network/utils/linux-atm - # lsof - if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/utils/lsof - cp -a ../master/packages/utils/lsof feeds/packages/utils/lsof - fi - # screen - SCREEN_VERSION=4.9.1 - SCREEN_HASH=26cef3e3c42571c0d484ad6faf110c5c15091fbf872b06fa7aa4766c7405ac69 - sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$SCREEN_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$SCREEN_HASH/" feeds/packages/utils/screen/Makefile - rm -rf feeds/packages/utils/screen/patches && mkdir -p feeds/packages/utils/screen/patches - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/screen/900-fix-implicit-function-declaration.patch > feeds/packages/utils/screen/patches/900-fix-implicit-function-declaration.patch - # perl - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/perl/1000-fix-implicit-declaration-error.patch > feeds/packages/lang/perl/patches/1000-fix-implicit-declaration-error.patch - # grub2 - [ "$version" = "rc2" ] && curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-14/grub2/900-fix-incompatible-pointer-type.patch > package/boot/grub2/patches/900-fix-incompatible-pointer-type.patch # glibc # Added the compiler flag -Wno-implicit-function-declaration to suppress # warnings about implicit function declarations during the build process. @@ -89,18 +50,13 @@ if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then sed -i '/TARGET_LDFLAGS/d' feeds/packages/utils/shadow/Makefile sed -i 's/libxcrypt/openssl/g' feeds/packages/utils/shadow/Makefile fi - # openssh - 9.8p1 - if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/net/openssh - cp -a ../master/packages/net/openssh feeds/packages/net/openssh - fi fi # fix gcc-15 if [ "$USE_GCC15" = y ]; then # Mbedtls curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch > package/libs/mbedtls/patches/901-tests-fix-string-initialization-error-on-gcc15.patch - [ "$version" = "snapshots-24.10" ] && sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile + sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile # elfutils curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch # libwebsockets @@ -112,17 +68,9 @@ if [ "$USE_GCC15" = y ]; then fi # ksmbd luci -if [ "$version" = "rc2" ]; then - rm -rf feeds/luci/applications/luci-app-ksmbd - cp -a ../master/luci/applications/luci-app-ksmbd feeds/luci/applications/luci-app-ksmbd -fi sed -i 's/0666/0644/g;s/0777/0755/g' feeds/luci/applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js # ksmbd tools -if [ "$version" = "rc2" ]; then - rm -rf feeds/packages/net/ksmbd-tools - cp -a ../master/packages/net/ksmbd-tools feeds/packages/net/ksmbd-tools -fi sed -i 's/0666/0644/g;s/0777/0755/g' feeds/packages/net/ksmbd-tools/files/ksmbd.config.example sed -i 's/bind interfaces only = yes/bind interfaces only = no/g' feeds/packages/net/ksmbd-tools/files/ksmbd.conf.template diff --git a/tags/kernel-6.6 b/tags/kernel-6.6 deleted file mode 100644 index df3464ab4..000000000 --- a/tags/kernel-6.6 +++ /dev/null @@ -1,2 +0,0 @@ -LINUX_VERSION-6.6 = .58 -LINUX_KERNEL_HASH-6.6.58 = e7df81e588d70fab5ec3ec3bb04ac53d51f0860fc3b1ec45e0a4167a026899db diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index 8257a30dd..cb72ec981 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -3,10 +3,10 @@ ROOT="./" # LTS -KERNEL_VERSION=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | awk '{print $2}' | grep -E ^linux-6.6 | grep tar.xz | sed 's/linux-//g;s/.tar.xz//g' | tail -n 1` +KERNEL_VERSION=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | awk '{print $2}' | grep -E ^linux-6.12 | grep tar.xz | sed 's/linux-//g;s/.tar.xz//g' | tail -n 1` KERNEL_HASH=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | grep linux-$KERNEL_VERSION | grep tar.xz | awk '{print $1}'` TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` [ -z $TAG ] && TAG="" || TAG=.$TAG -echo "LINUX_VERSION-6.6 = $TAG -LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.6 +echo "LINUX_VERSION-6.12 = $TAG +LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.12 diff --git a/tags/openwrt-tag.sh b/tags/openwrt-tag.sh index 023846b4b..0f7e8c7db 100755 --- a/tags/openwrt-tag.sh +++ b/tags/openwrt-tag.sh @@ -8,5 +8,5 @@ else cat tags.json | jq . > jq.json 2>&1 fi -grep name jq.json | grep v23 | head -1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g' | sed 's/v//g' > v23 +grep name jq.json | grep v24 | head -1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g' | sed 's/v//g' > v24 rm -f tags.json jq.json diff --git a/tags/v23 b/tags/v23 deleted file mode 100644 index 769d17cf7..000000000 --- a/tags/v23 +++ /dev/null @@ -1 +0,0 @@ -23.05.5 diff --git a/tags/v24 b/tags/v24 new file mode 100644 index 000000000..e69de29bb From 277f7c5630f2933bfc7f26aae6eba2fc0c997655 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 00:48:29 +0800 Subject: [PATCH 114/425] node: use packages-24.10 branch Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 7f9f13a8f..6467f7fad 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -6,7 +6,7 @@ git clone https://$github/sbwml/packages_lang_golang -b 23.x feeds/packages/lang # node - prebuilt rm -rf feeds/packages/lang/node -git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages/lang/node +git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages/lang/node -b packages-24.10 # default settings git clone https://$github/sbwml/default-settings package/new/default-settings From 45327916f95454a19b7ea6e7d7d1093e5e55dfbc Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 01:42:23 +0800 Subject: [PATCH 115/425] dpck/numactl: bump to latest version dpdk: v24.07 numactl: v2.0.19 Signed-off-by: sbwml --- openwrt/build.sh | 6 ++++++ openwrt/generic/config-dpdk | 4 ++++ openwrt/patch/dpdk/dpdk/Makefile | 5 ++--- .../patches/010-dpdk_arm_build_platform_fix.patch | 4 ++-- ...r8125-add-r8125-ethernet-poll-mode-driver.patch | 4 ++-- openwrt/patch/dpdk/numactl/Makefile | 6 ++---- openwrt/scripts/00-prepare_base.sh | 14 ++++++-------- openwrt/scripts/02-prepare_package.sh | 6 ++---- 8 files changed, 26 insertions(+), 23 deletions(-) create mode 100644 openwrt/generic/config-dpdk diff --git a/openwrt/build.sh b/openwrt/build.sh index 31b048393..a0bd2508e 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -419,6 +419,8 @@ if [ "$platform" = "x86_64" ]; then # driver firmware cp -a bin/packages/x86_64/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/x86_64/base/*natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/*numa*.ipk $kmodpkg_name/ || true bash kmod-sign $kmodpkg_name tar zcf x86_64-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -458,6 +460,8 @@ elif [ "$platform" = "armv8" ]; then # driver firmware cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true bash kmod-sign $kmodpkg_name tar zcf armv8-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -521,6 +525,8 @@ else # driver firmware cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true bash kmod-sign $kmodpkg_name tar zcf aarch64-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name diff --git a/openwrt/generic/config-dpdk b/openwrt/generic/config-dpdk new file mode 100644 index 000000000..21f3d34d6 --- /dev/null +++ b/openwrt/generic/config-dpdk @@ -0,0 +1,4 @@ + +# DPDK +CONFIG_PACKAGE_dpdk-tools=y +CONFIG_PACKAGE_numactl=m diff --git a/openwrt/patch/dpdk/dpdk/Makefile b/openwrt/patch/dpdk/dpdk/Makefile index f92a757dd..8b6f3d6fb 100644 --- a/openwrt/patch/dpdk/dpdk/Makefile +++ b/openwrt/patch/dpdk/dpdk/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dpdk -PKG_VERSION:=24.03 +PKG_VERSION:=24.07 PKG_RELEASE:=1 PKG_SOURCE_URL:=https://codeload.github.com/DPDK/dpdk/tar.gz/v$(PKG_VERSION)? PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_HASH:=1dcbddec31ea0abd1bb8fe9bed2187272fb8d719443332b5d6c36162c42120f8 +PKG_HASH:=f6963d4219019da6f05103ef91c38568f382a628dfda0aad1ffb0f6cd078b345 PKG_MAINTAINER:=Zbynek Kocur PKG_LICENSE:=BSD-3-Clause @@ -196,7 +196,6 @@ define Build/InstallDev $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libdpdk*.pc $(1)/usr/lib/pkgconfig/ endef - define Package/libdpdk/install $(INSTALL_DIR) $(1)/usr/lib $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/librte_*.so.* $(1)/usr/lib/ diff --git a/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch b/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch index e30009985..b0eb3686b 100644 --- a/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch +++ b/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch @@ -1,6 +1,6 @@ --- a/config/arm/meson.build +++ b/config/arm/meson.build -@@ -699,8 +699,10 @@ if dpdk_conf.get('RTE_ARCH_32') +@@ -718,8 +718,10 @@ if dpdk_conf.get('RTE_ARCH_32') if meson.is_cross_build() update_flags = true soc = meson.get_cross_property('platform', '') @@ -13,7 +13,7 @@ endif soc_config = socs.get(soc, {'not_supported': true}) flags_common = [] -@@ -754,8 +756,10 @@ else +@@ -773,8 +775,10 @@ else else # cross build soc = meson.get_cross_property('platform', '') diff --git a/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch b/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch index 8386f9357..8c59c9053 100644 --- a/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch +++ b/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch @@ -66,7 +66,7 @@ Signed-off-by: Howard Wang --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -1062,6 +1062,11 @@ F: drivers/net/memif/ +@@ -1076,6 +1076,11 @@ F: drivers/net/memif/ F: doc/guides/nics/memif.rst F: doc/guides/nics/features/memif.ini @@ -139,7 +139,7 @@ Signed-off-by: Howard Wang +* Jumbo frames supported --- a/drivers/net/meson.build +++ b/drivers/net/meson.build -@@ -52,6 +52,7 @@ drivers = [ +@@ -53,6 +53,7 @@ drivers = [ 'pfe', 'qede', 'ring', diff --git a/openwrt/patch/dpdk/numactl/Makefile b/openwrt/patch/dpdk/numactl/Makefile index 82ae3cb9b..7bda113aa 100644 --- a/openwrt/patch/dpdk/numactl/Makefile +++ b/openwrt/patch/dpdk/numactl/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=numactl -PKG_VERSION:=2.0.18 +PKG_VERSION:=2.0.19 PKG_RELEASE:=1 PKG_SOURCE_URL:=https://codeload.github.com/numactl/numactl/tar.gz/v$(PKG_VERSION)? PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_HASH:=8cd6c13f3096e9c2293c1d732f56e2aa37a7ada1a98deed3fac7bd6da1aaaaf6 +PKG_HASH:=8b84ffdebfa0d730fb2fc71bb7ec96bb2d38bf76fb67246fde416a68e04125e4 PKG_MAINTAINER:=Zbynek Kocur PKG_LICENSE:=GPL-2.0-or-later @@ -54,7 +54,6 @@ define Package/libnuma/description Incompatible changes will use new symbol version numbers. endef - define Build/InstallDev $(INSTALL_DIR) $(1)/usr/include $(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/ @@ -66,7 +65,6 @@ define Build/InstallDev $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/numa.pc $(1)/usr/lib/pkgconfig/ endef - define Package/numactl/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/bin diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 75cf5a456..5a5a2e511 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -92,14 +92,12 @@ else fi # DPDK & NUMACTL -if [ "$ENABLE_DPDK" = "y" ]; then - mkdir -p package/new/{dpdk/patches,numactl} - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Makefile > package/new/dpdk/Makefile - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Config.in > package/new/dpdk/Config.in - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch > package/new/dpdk/patches/010-dpdk_arm_build_platform_fix.patch - curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch > package/new/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch - curl -s https://$mirror/openwrt/patch/dpdk/numactl/Makefile > package/new/numactl/Makefile -fi +mkdir -p package/new/{dpdk/patches,numactl} +curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Makefile > package/new/dpdk/Makefile +curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Config.in > package/new/dpdk/Config.in +curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch > package/new/dpdk/patches/010-dpdk_arm_build_platform_fix.patch +curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch > package/new/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch +curl -s https://$mirror/openwrt/patch/dpdk/numactl/Makefile > package/new/numactl/Makefile # IF USE GLIBC if [ "$ENABLE_GLIBC" = "y" ]; then diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 6467f7fad..635037800 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -33,10 +33,8 @@ rm -rf feeds/packages/utils/lrzsz git clone https://$github/sbwml/packages_utils_lrzsz package/new/lrzsz # irqbalance: disable build with numa -if [ "$ENABLE_DPDK" = "y" ]; then - curl -s https://$mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch - sed -i '/-Dcapng=disabled/i\\t-Dnuma=disabled \\' feeds/packages/utils/irqbalance/Makefile -fi +curl -s https://$mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch +sed -i '/-Dcapng=disabled/i\\t-Dnuma=disabled \\' feeds/packages/utils/irqbalance/Makefile # frpc sed -i 's/procd_set_param stdout $stdout/procd_set_param stdout 0/g' feeds/packages/net/frp/files/frpc.init From d1c1a75fd55c5f3eddb8c6f1d15f18fb266a9494 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 02:54:12 +0800 Subject: [PATCH 116/425] sync openwrt-24.10 kernel modules Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/can.mk | 16 +- openwrt/patch/openwrt-6.x/modules/crypto.mk | 14 +- openwrt/patch/openwrt-6.x/modules/fs.mk | 19 +- .../patch/openwrt-6.x/modules/gpio-cascade.mk | 20 - openwrt/patch/openwrt-6.x/modules/gpio.mk | 139 ++++++ openwrt/patch/openwrt-6.x/modules/hwmon.mk | 2 +- openwrt/patch/openwrt-6.x/modules/leds.mk | 3 +- openwrt/patch/openwrt-6.x/modules/lib.mk | 33 +- .../patch/openwrt-6.x/modules/netdevices.mk | 322 +++++++++---- .../patch/openwrt-6.x/modules/netfilter.mk | 28 +- .../patch/openwrt-6.x/modules/netsupport.mk | 4 +- openwrt/patch/openwrt-6.x/modules/other.mk | 451 ++++-------------- openwrt/patch/openwrt-6.x/modules/rtc.mk | 255 ++++++++++ openwrt/patch/openwrt-6.x/modules/sound.mk | 2 +- openwrt/patch/openwrt-6.x/modules/usb.mk | 12 +- openwrt/patch/openwrt-6.x/modules/video.mk | 88 ++-- openwrt/patch/openwrt-6.x/modules/virt.mk | 2 +- openwrt/scripts/01-prepare_base-mainline.sh | 3 +- 18 files changed, 830 insertions(+), 583 deletions(-) delete mode 100644 openwrt/patch/openwrt-6.x/modules/gpio-cascade.mk create mode 100644 openwrt/patch/openwrt-6.x/modules/gpio.mk create mode 100644 openwrt/patch/openwrt-6.x/modules/rtc.mk diff --git a/openwrt/patch/openwrt-6.x/modules/can.mk b/openwrt/patch/openwrt-6.x/modules/can.mk index 603976ef5..c86d02d8d 100644 --- a/openwrt/patch/openwrt-6.x/modules/can.mk +++ b/openwrt/patch/openwrt-6.x/modules/can.mk @@ -120,9 +120,7 @@ $(eval $(call KernelPackage,can-c-can-platform)) define KernelPackage/can-flexcan TITLE:=Support for Freescale FLEXCAN based chips KCONFIG:=CONFIG_CAN_FLEXCAN - FILES:= \ - $(LINUX_DIR)/drivers/net/can/flexcan.ko@lt5.17 \ - $(LINUX_DIR)/drivers/net/can/flexcan/flexcan.ko@ge5.17 + FILES:=$(LINUX_DIR)/drivers/net/can/flexcan/flexcan.ko AUTOLOAD:=$(call AutoProbe,flexcan) $(call AddDepends/can,@TARGET_imx) endef @@ -185,9 +183,7 @@ $(eval $(call KernelPackage,can-raw)) define KernelPackage/can-slcan TITLE:=Serial / USB serial CAN Adaptors (slcan) KCONFIG:=CONFIG_CAN_SLCAN - FILES:= \ - $(LINUX_DIR)/drivers/net/can/slcan.ko@lt6.0 \ - $(LINUX_DIR)/drivers/net/can/slcan/slcan.ko@ge6.0 + FILES:=$(LINUX_DIR)/drivers/net/can/slcan/slcan.ko AUTOLOAD:=$(call AutoProbe,slcan) $(call AddDepends/can) endef @@ -235,12 +231,8 @@ $(eval $(call KernelPackage,can-usb-ems)) define KernelPackage/can-usb-esd TITLE:=ESD USB/2 CAN/USB interface - KCONFIG:= \ - CONFIG_CAN_ESD_USB2@lt6.0 \ - CONFIG_CAN_ESD_USB@ge6.0 - FILES:= \ - $(LINUX_DIR)/drivers/net/can/usb/esd_usb2.ko@lt6.0 \ - $(LINUX_DIR)/drivers/net/can/usb/esd_usb.ko@ge6.0 + KCONFIG:=CONFIG_CAN_ESD_USB + FILES:=$(LINUX_DIR)/drivers/net/can/usb/esd_usb.ko AUTOLOAD:=$(call AutoProbe,esd_usb2 esd_usb) $(call AddDepends/can,+kmod-usb-core) endef diff --git a/openwrt/patch/openwrt-6.x/modules/crypto.mk b/openwrt/patch/openwrt-6.x/modules/crypto.mk index 4f42eb357..ce2216354 100644 --- a/openwrt/patch/openwrt-6.x/modules/crypto.mk +++ b/openwrt/patch/openwrt-6.x/modules/crypto.mk @@ -39,11 +39,8 @@ define KernelPackage/crypto-aead TITLE:=CryptoAPI AEAD support KCONFIG:= \ CONFIG_CRYPTO_AEAD \ - CONFIG_CRYPTO_AEAD2 \ - CONFIG_CRYPTO_GENIV@lt6.6 - FILES:= \ - $(LINUX_DIR)/crypto/aead.ko \ - $(LINUX_DIR)/crypto/geniv.ko@lt6.6 + CONFIG_CRYPTO_AEAD2 + FILES:=$(LINUX_DIR)/crypto/aead.ko AUTOLOAD:=$(call AutoLoad,09,aead,1) $(call AddDepends/crypto, +kmod-crypto-null) endef @@ -305,9 +302,7 @@ define KernelPackage/crypto-gf128 KCONFIG:= \ CONFIG_CRYPTO_GF128MUL \ CONFIG_CRYPTO_LIB_GF128MUL - FILES:= \ - $(LINUX_DIR)/crypto/gf128mul.ko@lt6.2 \ - $(LINUX_DIR)/lib/crypto/gf128mul.ko@ge6.2 + FILES:=$(LINUX_DIR)/lib/crypto/gf128mul.ko AUTOLOAD:=$(call AutoLoad,09,gf128mul) $(call AddDepends/crypto) endef @@ -863,8 +858,7 @@ define KernelPackage/crypto-rsa KCONFIG:= CONFIG_CRYPTO_RSA HIDDEN:=1 FILES:= \ - $(LINUX_DIR)/lib/mpi/mpi.ko@lt6.5 \ - $(LINUX_DIR)/lib/crypto/mpi/mpi.ko@ge6.5 \ + $(LINUX_DIR)/lib/crypto/mpi/mpi.ko \ $(LINUX_DIR)/crypto/akcipher.ko \ $(LINUX_DIR)/crypto/rsa_generic.ko AUTOLOAD:=$(call AutoLoad,10,rsa_generic) diff --git a/openwrt/patch/openwrt-6.x/modules/fs.mk b/openwrt/patch/openwrt-6.x/modules/fs.mk index c4930e7f2..1f0a87bb2 100644 --- a/openwrt/patch/openwrt-6.x/modules/fs.mk +++ b/openwrt/patch/openwrt-6.x/modules/fs.mk @@ -89,13 +89,10 @@ define KernelPackage/fs-smbfs-common HIDDEN:=1 DEPENDS:=+kmod-fs-netfs +kmod-nls-ucs2-utils KCONFIG:=\ - CONFIG_SMBFS_COMMON@lt6.1 \ - CONFIG_SMBFS@ge6.1 + CONFIG_SMBFS FILES:= \ - $(LINUX_DIR)/fs/smbfs_common/cifs_arc4.ko@lt6.1 \ - $(LINUX_DIR)/fs/smbfs_common/cifs_md4.ko@lt6.1 \ - $(LINUX_DIR)/fs/smb/common/cifs_arc4.ko@ge6.1 \ - $(LINUX_DIR)/fs/smb/common/cifs_md4.ko@ge6.1 + $(LINUX_DIR)/fs/smb/common/cifs_arc4.ko \ + $(LINUX_DIR)/fs/smb/common/cifs_md4.ko endef define KernelPackage/fs-smbfs-common/description @@ -113,8 +110,7 @@ define KernelPackage/fs-cifs CONFIG_CIFS_DFS_UPCALL=n \ CONFIG_CIFS_UPCALL=n FILES:= \ - $(LINUX_DIR)/fs/cifs/cifs.ko@lt6.1 \ - $(LINUX_DIR)/fs/smb/client/cifs.ko@ge6.1 + $(LINUX_DIR)/fs/smb/client/cifs.ko AUTOLOAD:=$(call AutoLoad,30,cifs) $(call AddDepends/nls) DEPENDS+= \ @@ -276,8 +272,8 @@ define KernelPackage/fs-fscache CONFIG_CACHEFILES \ CONFIG_CACHEFILES_DEBUG=n \ CONFIG_CACHEFILES_HISTOGRAM=n \ - CONFIG_CACHEFILES_ERROR_INJECTION=n@ge5.17 \ - CONFIG_CACHEFILES_ONDEMAND=n@ge5.19 + CONFIG_CACHEFILES_ERROR_INJECTION=n \ + CONFIG_CACHEFILES_ONDEMAND=n FILES:= \ $(LINUX_DIR)/fs/fscache/fscache.ko \ $(LINUX_DIR)/fs/cachefiles/cachefiles.ko @@ -380,8 +376,7 @@ define KernelPackage/fs-ksmbd CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=n \ CONFIG_SMB_SERVER_KERBEROS5=n FILES:= \ - $(LINUX_DIR)/fs/ksmbd/ksmbd.ko@lt6.1 \ - $(LINUX_DIR)/fs/smb/server/ksmbd.ko@ge6.1 + $(LINUX_DIR)/fs/smb/server/ksmbd.ko AUTOLOAD:=$(call AutoLoad,41,ksmbd) endef diff --git a/openwrt/patch/openwrt-6.x/modules/gpio-cascade.mk b/openwrt/patch/openwrt-6.x/modules/gpio-cascade.mk deleted file mode 100644 index 3a559f19e..000000000 --- a/openwrt/patch/openwrt-6.x/modules/gpio-cascade.mk +++ /dev/null @@ -1,20 +0,0 @@ -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -MENU_TITLE:=GPIO support - -define KernelPackage/gpio-cascade - SUBMENU:=$(MENU_TITLE) - TITLE:=Generic GPIO cascade - KCONFIG:=CONFIG_GPIO_CASCADE - DEPENDS:=@GPIO_SUPPORT +kmod-mux-core - FILES:=$(LINUX_DIR)/drivers/gpio/gpio-cascade.ko - AUTOLOAD:=$(call AutoLoad,29,gpio-cascade,1) -endef - -define KernelPackage/gpio-cascade/description - Kernel module for Generic GPIO cascade -endef - -$(eval $(call KernelPackage,gpio-cascade)) diff --git a/openwrt/patch/openwrt-6.x/modules/gpio.mk b/openwrt/patch/openwrt-6.x/modules/gpio.mk new file mode 100644 index 000000000..fc6ab66ba --- /dev/null +++ b/openwrt/patch/openwrt-6.x/modules/gpio.mk @@ -0,0 +1,139 @@ +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +GPIO_MENU:=GPIO support + +define KernelPackage/gpio-amd-fch + SUBMENU:=$(GPIO_MENU) + DEPENDS:=@GPIO_SUPPORT @TARGET_x86 + TITLE:=GPIO support for AMD Fusion Controller Hub (G-series SOCs) + KCONFIG:=CONFIG_GPIO_AMD_FCH + FILES:=$(LINUX_DIR)/drivers/gpio/gpio-amd-fch.ko + AUTOLOAD:=$(call AutoLoad,25,gpio-amd-fch,1) +endef + +define KernelPackage/gpio-amd-fch/description + This option enables driver for GPIO on AMDs Fusion Controller Hub, + as found on G-series SOCs (eg. GX-412TC) +endef + +$(eval $(call KernelPackage,gpio-amd-fch)) + + +define KernelPackage/gpio-beeper + SUBMENU:=$(GPIO_MENU) + TITLE:=GPIO beeper support + DEPENDS:=+kmod-input-core + KCONFIG:= \ + CONFIG_INPUT_MISC=y \ + CONFIG_INPUT_GPIO_BEEPER + FILES:= \ + $(LINUX_DIR)/drivers/input/misc/gpio-beeper.ko + AUTOLOAD:=$(call AutoLoad,50,gpio-beeper) +endef + +define KernelPackage/gpio-beeper/description + This enables playing beeps through an GPIO-connected buzzer +endef + +$(eval $(call KernelPackage,gpio-beeper)) + + +define KernelPackage/gpio-cascade + SUBMENU:=$(GPIO_MENU) + TITLE:=Generic GPIO cascade + KCONFIG:=CONFIG_GPIO_CASCADE + DEPENDS:=@GPIO_SUPPORT +kmod-mux-core + FILES:=$(LINUX_DIR)/drivers/gpio/gpio-cascade.ko + AUTOLOAD:=$(call AutoLoad,29,gpio-cascade,1) +endef + +define KernelPackage/gpio-cascade/description + Kernel module for Generic GPIO cascade +endef + +$(eval $(call KernelPackage,gpio-cascade)) + + +define KernelPackage/gpio-f7188x + SUBMENU:=$(GPIO_MENU) + TITLE:=Fintek F718xx/F818xx GPIO Support + DEPENDS:=@GPIO_SUPPORT @TARGET_x86 + KCONFIG:=CONFIG_GPIO_F7188X + FILES:=$(LINUX_DIR)/drivers/gpio/gpio-f7188x.ko + AUTOLOAD:=$(call AutoProbe,gpio-f7188x) +endef + +define KernelPackage/gpio-f7188x/description + Kernel module for the GPIOs found on many Fintek Super-IO chips. +endef + +$(eval $(call KernelPackage,gpio-f7188x)) + + +define KernelPackage/gpio-it87 + SUBMENU:=$(GPIO_MENU) + DEPENDS:=@GPIO_SUPPORT @TARGET_x86 + TITLE:=GPIO support for IT87xx Super I/O chips + KCONFIG:=CONFIG_GPIO_IT87 + FILES:=$(LINUX_DIR)/drivers/gpio/gpio-it87.ko + AUTOLOAD:=$(call AutoLoad,25,gpio-it87,1) +endef + +define KernelPackage/gpio-it87/description + This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and + supports the IT8761E, IT8613, IT8620E, and IT8628E Super I/O chips as + well. +endef + +$(eval $(call KernelPackage,gpio-it87)) + + +define KernelPackage/gpio-nxp-74hc164 + SUBMENU:=$(GPIO_MENU) + TITLE:=NXP 74HC164 GPIO expander support + KCONFIG:=CONFIG_GPIO_74X164 + FILES:=$(LINUX_DIR)/drivers/gpio/gpio-74x164.ko + AUTOLOAD:=$(call AutoProbe,gpio-74x164) +endef + +define KernelPackage/gpio-nxp-74hc164/description + Kernel module for NXP 74HC164 GPIO expander +endef + +$(eval $(call KernelPackage,gpio-nxp-74hc164)) + + +define KernelPackage/gpio-pca953x + SUBMENU:=$(GPIO_MENU) + DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core +kmod-regmap-i2c + TITLE:=PCA95xx, TCA64xx, and MAX7310 I/O ports + KCONFIG:=CONFIG_GPIO_PCA953X \ + CONFIG_GPIO_PCA953X_IRQ=y + FILES:=$(LINUX_DIR)/drivers/gpio/gpio-pca953x.ko + AUTOLOAD:=$(call AutoLoad,55,gpio-pca953x) +endef + +define KernelPackage/gpio-pca953x/description + Kernel module for MAX731{0,2,3,5}, PCA6107, PCA953{4-9}, PCA955{4-7}, + PCA957{4,5} and TCA64{08,16} I2C GPIO expanders +endef + +$(eval $(call KernelPackage,gpio-pca953x)) + + +define KernelPackage/gpio-pcf857x + SUBMENU:=$(GPIO_MENU) + DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core + TITLE:=PCX857x, PCA967x and MAX732X I2C GPIO expanders + KCONFIG:=CONFIG_GPIO_PCF857X + FILES:=$(LINUX_DIR)/drivers/gpio/gpio-pcf857x.ko + AUTOLOAD:=$(call AutoLoad,55,gpio-pcf857x) +endef + +define KernelPackage/gpio-pcf857x/description + Kernel module for PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders +endef + +$(eval $(call KernelPackage,gpio-pcf857x)) diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index d862d5f9e..6978c5df9 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -53,7 +53,7 @@ define KernelPackage/hwmon-adt7410 $(LINUX_DIR)/drivers/hwmon/adt7x10.ko \ $(LINUX_DIR)/drivers/hwmon/adt7410.ko AUTOLOAD:=$(call AutoLoad,60,adt7x10 adt7410) - $(call AddDepends/hwmon,+kmod-i2c-core +!LINUX_5_15:kmod-regmap-core) + $(call AddDepends/hwmon,+kmod-i2c-core +kmod-regmap-core) endef define KernelPackage/hwmon-adt7410/description diff --git a/openwrt/patch/openwrt-6.x/modules/leds.mk b/openwrt/patch/openwrt-6.x/modules/leds.mk index 60465a8ad..8b24cb0ef 100644 --- a/openwrt/patch/openwrt-6.x/modules/leds.mk +++ b/openwrt/patch/openwrt-6.x/modules/leds.mk @@ -150,8 +150,9 @@ $(eval $(call KernelPackage,leds-apu)) define KernelPackage/leds-mlxcpld SUBMENU:=$(LEDS_MENU) TITLE:=LED support for the Mellanox boards - FILES:=$(LINUX_DIR)/drivers/leds/leds-mlxcpld.ko + DEPENDS:=@TARGET_x86 KCONFIG:=CONFIG_LEDS_MLXCPLD + FILES:=$(LINUX_DIR)/drivers/leds/leds-mlxcpld.ko AUTOLOAD:=$(call AutoProbe,leds-mlxcpld) endef diff --git a/openwrt/patch/openwrt-6.x/modules/lib.mk b/openwrt/patch/openwrt-6.x/modules/lib.mk index 8f0821590..011da30e4 100644 --- a/openwrt/patch/openwrt-6.x/modules/lib.mk +++ b/openwrt/patch/openwrt-6.x/modules/lib.mk @@ -143,7 +143,7 @@ define KernelPackage/lib-zstd CONFIG_ZSTD_DECOMPRESS FILES:= \ $(LINUX_DIR)/crypto/zstd.ko \ - $(LINUX_DIR)/lib/zstd/zstd_common.ko@ge6.1 \ + $(LINUX_DIR)/lib/zstd/zstd_common.ko \ $(LINUX_DIR)/lib/zstd/zstd_compress.ko \ $(LINUX_DIR)/lib/zstd/zstd_decompress.ko AUTOLOAD:=$(call AutoProbe,zstd zstd_compress zstd_decompress) @@ -397,3 +397,34 @@ endef $(eval $(call KernelPackage,libwx)) + +define KernelPackage/libie + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Intel Ethernet library + DEPENDS:=@LINUX_6_12 + KCONFIG:=CONFIG_LIBIE + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie.ko + AUTOLOAD:=$(call AutoLoad,15,libie,1) +endef + +define KernelPackage/libie/description + Intel Ethernet library +endef + +$(eval $(call KernelPackage,libie)) + + +define KernelPackage/libeth + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Intel Ethernet common library + DEPENDS:=@LINUX_6_12 + KCONFIG:=CONFIG_LIBETH + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libeth/libeth.ko + AUTOLOAD:=$(call AutoLoad,15,libeth,1) +endef + +define KernelPackage/libeth/description +endef + +$(eval $(call KernelPackage,libeth)) + diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index e7ca46d44..811f1cdb9 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -33,6 +33,33 @@ endef $(eval $(call KernelPackage,skge)) +define KernelPackage/ag71xx + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Atheros AR7XXX/AR9XXX ethernet mac support + DEPENDS:=@PCI_SUPPORT||TARGET_ath79 +kmod-phylink +kmod-mdio-devres +kmod-net-selftests + KCONFIG:=CONFIG_AG71XX + FILES:=$(LINUX_DIR)/drivers/net/ethernet/atheros/ag71xx.ko + AUTOLOAD:=$(call AutoLoad,50,ag71xx,1) +endef + +$(eval $(call KernelPackage,ag71xx)) + + +define KernelPackage/ag71xx-legacy + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Downstream Atheros AR7XXX/AR9XXX ethernet mac support + DEPENDS:=@TARGET_ath79 +kmod-libphy +kmod-mdio-devres + KCONFIG:=CONFIG_AG71XX_LEGACY \ + CONFIG_AG71XX_LEGACY_DEBUG=n \ + CONFIG_AG71XX_LEGACY_DEBUG_FS=y + FILES:=$(LINUX_DIR)/drivers/net/ethernet/atheros/ag71xx/ag71xx_legacy.ko \ + $(LINUX_DIR)/drivers/net/ethernet/atheros/ag71xx/ag71xx_legacy_mdio.ko + AUTOLOAD:=$(call AutoLoad,50,ag71xx-legacy ag71xx-legacy-mdio,1) +endef + +$(eval $(call KernelPackage,ag71xx-legacy)) + + define KernelPackage/alx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Qualcomm Atheros AR816x/AR817x PCI-E Ethernet Network Driver @@ -96,7 +123,8 @@ $(eval $(call KernelPackage,atl1e)) define KernelPackage/libphy SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=PHY library - KCONFIG:=CONFIG_PHYLIB + KCONFIG:=CONFIG_PHYLIB \ + CONFIG_PHYLIB_LEDS=y FILES:=$(LINUX_DIR)/drivers/net/phy/libphy.ko AUTOLOAD:=$(call AutoLoad,15,libphy,1) endef @@ -108,37 +136,6 @@ endef $(eval $(call KernelPackage,libphy)) -define KernelPackage/libie - SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Intel Ethernet library - DEPENDS:=@LINUX_6_12 - KCONFIG:=CONFIG_LIBIE - FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie.ko - AUTOLOAD:=$(call AutoLoad,15,libie,1) -endef - -define KernelPackage/libie/description - Intel Ethernet library -endef - -$(eval $(call KernelPackage,libie)) - - -define KernelPackage/libeth - SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Intel Ethernet common library - DEPENDS:=@LINUX_6_12 - KCONFIG:=CONFIG_LIBETH - FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libeth/libeth.ko - AUTOLOAD:=$(call AutoLoad,15,libeth,1) -endef - -define KernelPackage/libeth/description -endef - -$(eval $(call KernelPackage,libeth)) - - define KernelPackage/phylink SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Model for MAC to optional PHY connection @@ -173,7 +170,7 @@ $(eval $(call KernelPackage,mii)) define KernelPackage/mdio-devres SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Supports MDIO device registration - DEPENDS:=+kmod-libphy +(TARGET_armsr||TARGET_bcm27xx_bcm2708||TARGET_malta||TARGET_tegra):kmod-of-mdio + DEPENDS:=+kmod-libphy +(TARGET_armsr||TARGET_bcm27xx_bcm2708||TARGET_loongarch64||TARGET_malta||TARGET_tegra):kmod-of-mdio KCONFIG:=CONFIG_MDIO_DEVRES HIDDEN:=1 FILES:=$(LINUX_DIR)/drivers/net/phy/mdio_devres.ko @@ -190,7 +187,7 @@ $(eval $(call KernelPackage,mdio-devres)) define KernelPackage/mdio-gpio SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:= Supports GPIO lib-based MDIO busses - DEPENDS:=+kmod-libphy @GPIO_SUPPORT +(TARGET_armsr||TARGET_bcm27xx_bcm2708||TARGET_malta||TARGET_tegra):kmod-of-mdio + DEPENDS:=+kmod-libphy @GPIO_SUPPORT +(TARGET_armsr||TARGET_bcm27xx_bcm2708||TARGET_loongarch64||TARGET_malta||TARGET_tegra):kmod-of-mdio KCONFIG:= \ CONFIG_MDIO_BITBANG \ CONFIG_MDIO_GPIO @@ -255,6 +252,19 @@ endef $(eval $(call KernelPackage,phylib-broadcom)) +define KernelPackage/phylib-qcom + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Qualcomm Ethernet PHY library + KCONFIG:=CONFIG_QCOM_NET_PHYLIB + HIDDEN:=1 + DEPENDS:=+kmod-libphy + FILES:=$(LINUX_DIR)/drivers/net/phy/qcom/qcom-phy-lib.ko + AUTOLOAD:=$(call AutoLoad,17,qcom-phy-lib) +endef + +$(eval $(call KernelPackage,phylib-qcom)) + + define KernelPackage/phy-amd SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=AMD PHY driver @@ -271,6 +281,18 @@ endef $(eval $(call KernelPackage,phy-amd)) +define KernelPackage/phy-at803x + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Qualcomm Atheros 8337 internal PHY + KCONFIG:=CONFIG_AT803X_PHY + DEPENDS:=+kmod-phylib-qcom + FILES:=$(LINUX_DIR)/drivers/net/phy/qcom/at803x.ko + AUTOLOAD:=$(call AutoLoad,18,at803x,1) +endef + +$(eval $(call KernelPackage,phy-at803x)) + + define KernelPackage/phy-ax88796b SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Asix PHY driver @@ -321,6 +343,37 @@ endef $(eval $(call KernelPackage,phy-bcm84881)) +define KernelPackage/phy-intel-xway + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Intel XWAY PHYs + KCONFIG:=CONFIG_INTEL_XWAY_PHY + DEPENDS:=+kmod-libphy + FILES:=$(LINUX_DIR)/drivers/net/phy/intel-xway.ko + AUTOLOAD:=$(call AutoLoad,18,intel-xway,1) +endef + +define KernelPackage/phy-intel-xway/description + Supports the Intel XWAY (former Lantiq) 11G and 22E PHYs. + These PHYs are marked as standalone chips under the names + PEF 7061, PEF 7071 and PEF 7072 or integrated into the Intel + SoCs xRX200, xRX300, xRX330, xRX350 and xRX550. +endef + +$(eval $(call KernelPackage,phy-intel-xway)) + + +define KernelPackage/phy-qca83xx + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Qualcomm Atheros QCA833x PHY driver + KCONFIG:=CONFIG_QCA83XX_PHY + DEPENDS:=+kmod-phylib-qcom + FILES:=$(LINUX_DIR)/drivers/net/phy/qcom/qca83xx.ko + AUTOLOAD:=$(call AutoLoad,18,qca83xx,1) +endef + +$(eval $(call KernelPackage,phy-qca83xx)) + + define KernelPackage/phy-marvell SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Marvell Gigabit Ethernet PHY driver @@ -374,6 +427,23 @@ endef $(eval $(call KernelPackage,phy-marvell-10g)) + +define KernelPackage/phy-micrel + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Micrel PHYs + KCONFIG:=CONFIG_MICREL_PHY + DEPENDS:=+kmod-libphy +kmod-ptp + FILES:=$(LINUX_DIR)/drivers/net/phy/micrel.ko + AUTOLOAD:=$(call AutoLoad,18,micrel,1) +endef + +define KernelPackage/phy-micrel/description + Supports the KSZ9021, VSC8201, KS8001 PHYs. +endef + +$(eval $(call KernelPackage,phy-micrel)) + + define KernelPackage/phy-realtek SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Realtek Ethernet PHY driver @@ -406,10 +476,26 @@ endef $(eval $(call KernelPackage,phy-smsc)) +define KernelPackage/phy-vitesse + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Vitesse PHYs + KCONFIG:=CONFIG_VITESSE_PHY + DEPENDS:=+kmod-libphy + FILES:=$(LINUX_DIR)/drivers/net/phy/vitesse.ko + AUTOLOAD:=$(call AutoLoad,18,vitesse,1) +endef + +define KernelPackage/phy-vitesse/description + Currently supports the vsc8244 +endef + +$(eval $(call KernelPackage,phy-vitesse)) + + define KernelPackage/phy-airoha-en8811h SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Airoha EN8811H 2.5G Ethernet PHY - DEPENDS:=+airoha-en8811h-firmware +kmod-libphy @!LINUX_5_15 + DEPENDS:=+airoha-en8811h-firmware +kmod-libphy KCONFIG:=CONFIG_AIR_EN8811H_PHY FILES:= \ $(LINUX_DIR)/drivers/net/phy/air_en8811h.ko @@ -438,13 +524,65 @@ endef $(eval $(call KernelPackage,phy-aquantia)) +define KernelPackage/dsa + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Distributed Switch Architecture support + DEPENDS:=+kmod-mdio-devres +kmod-net-selftests +kmod-phylink + KCONFIG:=CONFIG_NET_DSA + FILES:=$(LINUX_DIR)/net/dsa/dsa_core.ko +endef + +define KernelPackage/dsa/description + Kernel module support for Distributed Switch Architecture +endef + +$(eval $(call KernelPackage,dsa)) + + +define KernelPackage/dsa-b53 + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Broadcom BCM53xx managed switch DSA support + DEPENDS:=+kmod-dsa + KCONFIG:=CONFIG_B53 \ + CONFIG_NET_DSA_TAG_BRCM \ + CONFIG_NET_DSA_TAG_BRCM_LEGACY \ + CONFIG_NET_DSA_TAG_BRCM_PREPEND + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/b53/b53_common.ko \ + $(LINUX_DIR)/net/dsa/tag_brcm.ko + AUTOLOAD:=$(call AutoProbe,b53_common) +endef + +define KernelPackage/dsa-b53/description + Broadcom BCM53xx managed switch support +endef + +$(eval $(call KernelPackage,dsa-b53)) + + +define KernelPackage/dsa-b53-mdio + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=B53 MDIO connected switch DSA driver + DEPENDS:=+kmod-dsa-b53 + KCONFIG:=CONFIG_B53_MDIO_DRIVER + FILES:=$(LINUX_DIR)/drivers/net/dsa/b53/b53_mdio.ko + AUTOLOAD:=$(call AutoProbe,b53_mdio) +endef + +define KernelPackage/dsa-b53-mdio/description + B53 MDIO connected switch driver +endef + +$(eval $(call KernelPackage,dsa-b53-mdio)) + + define KernelPackage/dsa-tag-dsa SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Marvell DSA type DSA and EDSA taggers + DEPENDS:=+kmod-dsa KCONFIG:= CONFIG_NET_DSA_TAG_DSA_COMMON \ CONFIG_NET_DSA_TAG_DSA \ - CONFIG_NET_DSA_TAG_EDSA \ - CONFIG_NET_DSA=y + CONFIG_NET_DSA_TAG_EDSA FILES:=$(LINUX_DIR)/net/dsa/tag_dsa.ko AUTOLOAD:=$(call AutoLoad,40,tag_dsa,1) endef @@ -458,10 +596,10 @@ $(eval $(call KernelPackage,dsa-tag-dsa)) define KernelPackage/dsa-mv88e6xxx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Marvell MV88E6XXX DSA Switch - DEPENDS:=+kmod-ptp +kmod-phy-marvell +kmod-dsa-tag-dsa + DEPENDS:=+kmod-dsa +kmod-ptp +kmod-phy-marvell +kmod-dsa-tag-dsa KCONFIG:=CONFIG_NET_DSA_MV88E6XXX \ - CONFIG_NET_DSA_MV88E6XXX_PTP=y \ - CONFIG_NET_DSA=y + CONFIG_NET_DSA_MV88E6XXX_LEDS=y \ + CONFIG_NET_DSA_MV88E6XXX_PTP=y FILES:=$(LINUX_DIR)/drivers/net/dsa/mv88e6xxx/mv88e6xxx.ko AUTOLOAD:=$(call AutoLoad,41,mv88e6xxx,1) endef @@ -472,12 +610,32 @@ endef $(eval $(call KernelPackage,dsa-mv88e6xxx)) +define KernelPackage/dsa-qca8k + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Qualcomm Atheros QCA8xxx switch family DSA support + DEPENDS:=+kmod-dsa +kmod-regmap-core + KCONFIG:= \ + CONFIG_NET_DSA_QCA8K \ + CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT=y \ + CONFIG_NET_DSA_TAG_QCA + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/qca/qca8k.ko \ + $(LINUX_DIR)/net/dsa/tag_qca.ko + AUTOLOAD:=$(call AutoLoad,42,qca8k,1) +endef + +define KernelPackage/dsa-qca8k/description + DSA based kernel modules for the Qualcomm Atheros QCA8xxx switch family +endef + +$(eval $(call KernelPackage,dsa-qca8k)) define KernelPackage/swconfig SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=switch configuration API DEPENDS:=+kmod-libphy - KCONFIG:=CONFIG_SWCONFIG + KCONFIG:=CONFIG_SWCONFIG \ + CONFIG_SWCONFIG_LEDS=y FILES:=$(LINUX_DIR)/drivers/net/phy/swconfig.ko AUTOLOAD:=$(call AutoLoad,41,swconfig) endef @@ -488,36 +646,6 @@ endef $(eval $(call KernelPackage,swconfig)) -define KernelPackage/switch-bcm53xx - SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Broadcom bcm53xx switch support - DEPENDS:=+kmod-swconfig - KCONFIG:=CONFIG_SWCONFIG_B53 - FILES:=$(LINUX_DIR)/drivers/net/phy/b53/b53_common.ko - AUTOLOAD:=$(call AutoLoad,42,b53_common) -endef - -define KernelPackage/switch-bcm53xx/description - Broadcom bcm53xx switch support -endef - -$(eval $(call KernelPackage,switch-bcm53xx)) - -define KernelPackage/switch-bcm53xx-mdio - SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Broadcom bcm53xx switch MDIO support - DEPENDS:=+kmod-switch-bcm53xx - KCONFIG:=CONFIG_SWCONFIG_B53_PHY_DRIVER - FILES:=$(LINUX_DIR)/drivers/net/phy/b53/b53_mdio.ko - AUTOLOAD:=$(call AutoLoad,42,b53_mdio) -endef - -define KernelPackage/switch-bcm53xx-mdio/description - Broadcom bcm53xx switch MDIO support -endef - -$(eval $(call KernelPackage,switch-bcm53xx-mdio)) - define KernelPackage/switch-ip17xx SUBMENU:=$(NETWORK_DEVICES_MENU) @@ -554,7 +682,7 @@ $(eval $(call KernelPackage,switch-rtl8306)) define KernelPackage/switch-rtl8366-smi SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Realtek RTL8366 SMI switch interface support - DEPENDS:=@GPIO_SUPPORT +kmod-swconfig +(TARGET_armsr||TARGET_bcm27xx_bcm2708||TARGET_malta||TARGET_tegra):kmod-of-mdio + DEPENDS:=@GPIO_SUPPORT +kmod-swconfig +(TARGET_armsr||TARGET_bcm27xx_bcm2708||TARGET_loongarch64||TARGET_malta||TARGET_tegra):kmod-of-mdio KCONFIG:=CONFIG_RTL8366_SMI FILES:=$(LINUX_DIR)/drivers/net/phy/rtl8366_smi.ko AUTOLOAD:=$(call AutoLoad,42,rtl8366_smi,1) @@ -635,7 +763,8 @@ define KernelPackage/switch-ar8xxx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Atheros AR8216/8327 switch support DEPENDS:=+kmod-swconfig +kmod-mdio-devres - KCONFIG:=CONFIG_AR8216_PHY + KCONFIG:=CONFIG_AR8216_PHY \ + CONFIG_AR8216_PHY_LEDS=y FILES:=$(LINUX_DIR)/drivers/net/phy/ar8xxx.ko AUTOLOAD:=$(call AutoLoad,43,ar8xxx,1) endef @@ -681,6 +810,23 @@ endef $(eval $(call KernelPackage,r6040)) +define KernelPackage/rmnet + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=RmNet MAP support + KCONFIG:=CONFIG_RMNET + FILES:=$(LINUX_DIR)/drivers/net/ethernet/qualcomm/rmnet/rmnet.ko + AUTOLOAD:=$(call AutoLoad,30,rmnet) +endef + +define KernelPackage/rmnet/description + Kernel support for RMNET module which is used for handling data in the + multiplexing and aggregation protocol (MAP) format in the embedded data + path. RMNET devices can be attached to any IP mode physical device. +endef + +$(eval $(call KernelPackage,rmnet)) + + define KernelPackage/niu SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Sun Neptune 10Gbit Ethernet support @@ -810,7 +956,7 @@ define KernelPackage/r8169 DEPENDS:=@PCI_SUPPORT +kmod-mii +r8169-firmware +kmod-phy-realtek +kmod-mdio-devres KCONFIG:= \ CONFIG_R8169 \ - CONFIG_R8169_LEDS=y@ge6.6 + CONFIG_R8169_LEDS=y FILES:=$(LINUX_DIR)/drivers/net/ethernet/realtek/r8169.ko AUTOLOAD:=$(call AutoProbe,r8169) endef @@ -1412,7 +1558,7 @@ define KernelPackage/mlx4-core CONFIG_MLX4_CORE=y \ CONFIG_MLX4_CORE_GEN2=y \ CONFIG_MLX4_DEBUG=n - AUTOLOAD:=$(call AutoProbe,mlx4_core mlx4_en) + AUTOLOAD:=$(call AutoLoad,36,mlx4_core mlx4_en,1) endef define KernelPackage/mlx4-core/description @@ -1443,7 +1589,7 @@ define KernelPackage/mlx5-core CONFIG_MLX5_TC_CT=n \ CONFIG_MLX5_TLS=n \ CONFIG_MLX5_VFIO_PCI=n - AUTOLOAD:=$(call AutoProbe,mlx5_core) + AUTOLOAD:=$(call AutoLoad,36,mlx5_core,1) endef define KernelPackage/mlx5-core/description @@ -1507,7 +1653,7 @@ $(eval $(call KernelPackage,mlxsw-i2c)) define KernelPackage/mlxsw-minimal SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Mellanox Technologies minimal I2C support - DEPENDS:=+kmod-mlxsw-core +kmod-mlxsw-i2c + DEPENDS:=+kmod-mlxsw-i2c FILES:=$(LINUX_DIR)/drivers/net/ethernet/mellanox/mlxsw/mlxsw_minimal.ko KCONFIG:=CONFIG_MLXSW_MINIMAL AUTOLOAD:=$(call AutoProbe,mlxsw_minimal) @@ -1541,20 +1687,14 @@ define KernelPackage/mlxsw-spectrum SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Mellanox Technologies Spectrum family support DEPENDS:= \ - +kmod-mlxsw-core +kmod-mlxsw-pci +kmod-lib-objagg +kmod-lib-parman \ + +kmod-mlxsw-pci +kmod-lib-objagg +kmod-lib-parman \ +kmod-ip6-tunnel +kmod-ptp +kmod-sched-act-sample +kmod-vxlan FILES:=$(LINUX_DIR)/drivers/net/ethernet/mellanox/mlxsw/mlxsw_spectrum.ko KCONFIG:= \ CONFIG_MLXSW_SPECTRUM \ - CONFIG_NET_SWITCHDEV=y \ CONFIG_MLXSW_SPECTRUM_DCB=y \ - CONFIG_DCB=y \ - CONFIG_AMD_XGBE_DCB=n \ - CONFIG_IXGBE_DCB=n \ - CONFIG_I40E_DCB=n \ - CONFIG_QLCNIC_DCB=n \ - CONFIG_FSL_DPAA2_ETH_DCB=n \ - CONFIG_FSL_DPAA2_SWITCH=n + CONFIG_NET_SWITCHDEV=y \ + CONFIG_DCB=y AUTOLOAD:=$(call AutoProbe,mlxsw_spectrum) endef @@ -1637,7 +1777,7 @@ $(eval $(call KernelPackage,pcs-xpcs)) define KernelPackage/stmmac-core SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Synopsis Ethernet Controller core (NXP,STMMicro,others) - DEPENDS:=@TARGET_x86_64||TARGET_armsr_armv8 +kmod-pcs-xpcs +kmod-of-mdio +kmod-ptp + DEPENDS:=@TARGET_x86_64||TARGET_armsr +kmod-pcs-xpcs +kmod-of-mdio +kmod-ptp KCONFIG:=CONFIG_STMMAC_ETH \ CONFIG_STMMAC_SELFTESTS=n \ CONFIG_STMMAC_PLATFORM \ @@ -1658,7 +1798,7 @@ define KernelPackage/igc DEPENDS:=@PCI_SUPPORT +kmod-ptp KCONFIG:=CONFIG_IGC FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/igc/igc.ko - AUTOLOAD:=$(call AutoProbe,igc) + AUTOLOAD:=$(call AutoLoad,34,igc,1) endef define KernelPackage/igc/description @@ -1711,7 +1851,7 @@ define KernelPackage/wwan TITLE:=WWAN Driver Core KCONFIG:= \ CONFIG_WWAN \ - CONFIG_WWAN_DEBUGFS=y@ge5.17 + CONFIG_WWAN_DEBUGFS=y FILES:=$(LINUX_DIR)/drivers/net/wwan/wwan.ko AUTOLOAD:=$(call AutoProbe,wwan) endef @@ -1774,7 +1914,7 @@ $(eval $(call KernelPackage,mhi-wwan-mbim)) define KernelPackage/mtk-t7xx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=MediaTek T7xx 5G modem - DEPENDS:=@!LINUX_5_15 @PCI_SUPPORT +kmod-wwan + DEPENDS:=@PCI_SUPPORT +kmod-wwan KCONFIG:=CONFIG_MTK_T7XX FILES:=$(LINUX_DIR)/drivers/net/wwan/t7xx/mtk_t7xx.ko AUTOLOAD:=$(call AutoProbe,mtk_t7xx) @@ -1806,7 +1946,7 @@ $(eval $(call KernelPackage,atlantic)) define KernelPackage/lan743x SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Microchip LAN743x PCI Express Gigabit Ethernet NIC - DEPENDS:=@PCI_SUPPORT +kmod-ptp +kmod-mdio-devres +!LINUX_6_1:kmod-fixed-phy + DEPENDS:=@PCI_SUPPORT +kmod-ptp +kmod-mdio-devres +kmod-fixed-phy KCONFIG:=CONFIG_LAN743X FILES:=$(LINUX_DIR)/drivers/net/ethernet/microchip/lan743x.ko AUTOLOAD:=$(call AutoProbe,lan743x) diff --git a/openwrt/patch/openwrt-6.x/modules/netfilter.mk b/openwrt/patch/openwrt-6.x/modules/netfilter.mk index 8bf2be585..cf66bd8cd 100644 --- a/openwrt/patch/openwrt-6.x/modules/netfilter.mk +++ b/openwrt/patch/openwrt-6.x/modules/netfilter.mk @@ -818,27 +818,6 @@ endef $(eval $(call KernelPackage,ipt-cluster)) -define KernelPackage/ipt-clusterip - TITLE:=Module for CLUSTERIP - KCONFIG:=$(KCONFIG_IPT_CLUSTERIP) - FILES:=$(foreach mod,$(IPT_CLUSTERIP-m),$(LINUX_DIR)/net/$(mod).ko) - AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_CLUSTERIP-m))) - $(call AddDepends/ipt,+kmod-nf-conntrack @LINUX_5_15||LINUX_6_1) -endef - -define KernelPackage/ipt-clusterip/description - Netfilter (IPv4-only) module for CLUSTERIP - The CLUSTERIP target allows you to build load-balancing clusters of - network servers without having a dedicated load-balancing - router/server/switch. - - To use it also enable iptables-mod-clusterip - - see `iptables -j CLUSTERIP --help` for more information. -endef - -$(eval $(call KernelPackage,ipt-clusterip)) - define KernelPackage/ipt-extra TITLE:=Extra modules @@ -1197,15 +1176,11 @@ define KernelPackage/nft-offload DEPENDS:=@IPV6 +kmod-nf-flow +kmod-nft-nat KCONFIG:= \ CONFIG_NF_FLOW_TABLE_INET \ - CONFIG_NF_FLOW_TABLE_IPV4@lt5.17 \ - CONFIG_NF_FLOW_TABLE_IPV6@lt5.17 \ CONFIG_NFT_FLOW_OFFLOAD FILES:= \ $(LINUX_DIR)/net/netfilter/nf_flow_table_inet.ko \ - $(LINUX_DIR)/net/ipv4/netfilter/nf_flow_table_ipv4.ko@lt5.17 \ - $(LINUX_DIR)/net/ipv6/netfilter/nf_flow_table_ipv6.ko@lt5.17 \ $(LINUX_DIR)/net/netfilter/nft_flow_offload.ko - AUTOLOAD:=$(call AutoProbe,nf_flow_table_inet nf_flow_table_ipv4@lt5.17 nf_flow_table_ipv6@lt5.17 nft_flow_offload) + AUTOLOAD:=$(call AutoProbe,nf_flow_table_inet nft_flow_offload) endef $(eval $(call KernelPackage,nft-offload)) @@ -1217,6 +1192,7 @@ define KernelPackage/nft-netdev DEPENDS:=+kmod-nft-core KCONFIG:= \ CONFIG_NETFILTER_INGRESS=y \ + CONFIG_NETFILTER_EGRESS=y \ CONFIG_NF_TABLES_NETDEV \ CONFIG_NF_DUP_NETDEV \ CONFIG_NFT_DUP_NETDEV \ diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index e536dd298..1e2591571 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -1362,7 +1362,7 @@ define KernelPackage/9pnet KCONFIG:= \ CONFIG_NET_9P \ CONFIG_NET_9P_DEBUG=n \ - CONFIG_NET_9P_FD=n@ge5.17 + CONFIG_NET_9P_FD=n FILES:= \ $(LINUX_DIR)/net/9p/9pnet.ko AUTOLOAD:=$(call AutoLoad,29,9pnet) @@ -1504,10 +1504,12 @@ define KernelPackage/inet-mptcp-diag FILES:=$(LINUX_DIR)/net/mptcp/mptcp_diag.ko AUTOLOAD:=$(call AutoProbe,mptcp_diag) endef + define KernelPackage/inet-mptcp-diag/description Support for INET (MultiPath TCP) socket monitoring interface used by native Linux tools such as ss. endef + $(eval $(call KernelPackage,inet-mptcp-diag)) diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index 24db3420b..c77aee327 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -58,7 +58,7 @@ define KernelPackage/bluetooth $(LINUX_DIR)/drivers/bluetooth/btusb.ko \ $(LINUX_DIR)/drivers/bluetooth/btintel.ko \ $(LINUX_DIR)/drivers/bluetooth/btrtl.ko \ - $(LINUX_DIR)/drivers/bluetooth/btmtk.ko@ge5.17 + $(LINUX_DIR)/drivers/bluetooth/btmtk.ko AUTOLOAD:=$(call AutoProbe,bluetooth rfcomm bnep hidp hci_uart btusb) endef @@ -228,22 +228,6 @@ endef $(eval $(call KernelPackage,google-firmware)) -define KernelPackage/gpio-f7188x - SUBMENU:=$(OTHER_MENU) - TITLE:=Fintek F718xx/F818xx GPIO Support - DEPENDS:=@GPIO_SUPPORT @TARGET_x86 - KCONFIG:=CONFIG_GPIO_F7188X - FILES:=$(LINUX_DIR)/drivers/gpio/gpio-f7188x.ko - AUTOLOAD:=$(call AutoProbe,gpio-f7188x) -endef - -define KernelPackage/gpio-f7188x/description - Kernel module for the GPIOs found on many Fintek Super-IO chips. -endef - -$(eval $(call KernelPackage,gpio-f7188x)) - - define KernelPackage/lkdtm SUBMENU:=$(OTHER_MENU) TITLE:=Linux Kernel Dump Test Tool Module @@ -260,6 +244,92 @@ endef $(eval $(call KernelPackage,lkdtm)) +define KernelPackage/mlx_wdt + SUBMENU:=$(OTHER_MENU) + TITLE:=Mellanox Watchdog + DEPENDS:=@TARGET_x86 +kmod-regmap-core + KCONFIG:= \ + CONFIG_MELLANOX_PLATFORM=y \ + CONFIG_MLX_WDT + FILES:=$(LINUX_DIR)/drivers/watchdog/mlx_wdt.ko + AUTOLOAD:=$(call AutoProbe,mlx_wdt) +endef + +define KernelPackage/mlx_wdt/description + This is the driver for the hardware watchdog on Mellanox systems. + This driver can be used together with the watchdog daemon. + It can also watch your kernel to make sure it doesn't freeze, + and if it does, it reboots your system after a certain amount of + time. +endef + +$(eval $(call KernelPackage,mlx_wdt)) + + +define KernelPackage/mlxreg + SUBMENU:=$(OTHER_MENU) + TITLE:=Mellanox platform register access + DEPENDS:=@TARGET_x86 +kmod-i2c-mux-mlxcpld + KCONFIG:= \ + CONFIG_MELLANOX_PLATFORM=y \ + CONFIG_MLX_PLATFORM \ + CONFIG_MLXREG_HOTPLUG \ + CONFIG_MLXREG_IO \ + CONFIG_SENSORS_MLXREG_FAN \ + CONFIG_LEDS_MLXREG + FILES:= \ + $(LINUX_DIR)/drivers/platform/x86/mlx-platform.ko \ + $(LINUX_DIR)/drivers/platform/mellanox/mlxreg-hotplug.ko \ + $(LINUX_DIR)/drivers/platform/mellanox/mlxreg-io.ko \ + $(LINUX_DIR)/drivers/hwmon/mlxreg-fan.ko \ + $(LINUX_DIR)/drivers/leds/leds-mlxreg.ko + AUTOLOAD:=$(call AutoProbe,mlx-platform mlxreg-hotplug mlxreg-io mlxreg-fan leds-mlxreg) +endef + +define KernelPackage/mlxreg/description + Allows access to Mellanox programmable device register + space through sysfs interface. The sets of registers for sysfs access + are defined per system type bases and include the registers related + to system resets operation, system reset causes monitoring and some + kinds of mux selection. +endef + +$(eval $(call KernelPackage,mlxreg)) + + +define KernelPackage/mlxreg-lc + SUBMENU:=$(OTHER_MENU) + TITLE:=Mellanox line card platform support + DEPENDS:=kmod-mlxreg +kmod-regmap-i2c + KCONFIG:=CONFIG_MLXREG_LC + FILES:=$(LINUX_DIR)/drivers/platform/mellanox/mlxreg-lc.ko + AUTOLOAD:=$(call AutoProbe,mlxreg-lc) +endef + +define KernelPackage/mlxreg-lc/description + Provides support for the Mellanox MSN4800-XX line cards, + which are the part of MSN4800 Ethernet modular switch systems. +endef + +$(eval $(call KernelPackage,mlxreg-lc)) + + +define KernelPackage/mlxreg-sn2201 + SUBMENU:=$(OTHER_MENU) + TITLE:=Nvidia SN2201 platform support + DEPENDS:=kmod-mlxreg +kmod-regmap-i2c + KCONFIG:=CONFIG_NVSW_SN2201 + FILES:=$(LINUX_DIR)/drivers/platform/mellanox/nvsw-sn2201.ko + AUTOLOAD:=$(call AutoProbe,nvsw-sn2201) +endef + +define KernelPackage/mlxreg-sn2201/description + Provides support for the Nvidia SN2201 platform. +endef + +$(eval $(call KernelPackage,mlxreg-sn2201)) + + define KernelPackage/pinctrl-mcp23s08 SUBMENU:=$(OTHER_MENU) TITLE:=Microchip MCP23xxx I/O expander @@ -312,87 +382,6 @@ endef $(eval $(call KernelPackage,pinctrl-mcp23s08-spi)) -define KernelPackage/gpio-nxp-74hc164 - SUBMENU:=$(OTHER_MENU) - TITLE:=NXP 74HC164 GPIO expander support - KCONFIG:=CONFIG_GPIO_74X164 - FILES:=$(LINUX_DIR)/drivers/gpio/gpio-74x164.ko - AUTOLOAD:=$(call AutoProbe,gpio-74x164) -endef - -define KernelPackage/gpio-nxp-74hc164/description - Kernel module for NXP 74HC164 GPIO expander -endef - -$(eval $(call KernelPackage,gpio-nxp-74hc164)) - -define KernelPackage/gpio-pca953x - SUBMENU:=$(OTHER_MENU) - DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core +kmod-regmap-i2c - TITLE:=PCA95xx, TCA64xx, and MAX7310 I/O ports - KCONFIG:=CONFIG_GPIO_PCA953X - FILES:=$(LINUX_DIR)/drivers/gpio/gpio-pca953x.ko - AUTOLOAD:=$(call AutoLoad,55,gpio-pca953x) -endef - -define KernelPackage/gpio-pca953x/description - Kernel module for MAX731{0,2,3,5}, PCA6107, PCA953{4-9}, PCA955{4-7}, - PCA957{4,5} and TCA64{08,16} I2C GPIO expanders -endef - -$(eval $(call KernelPackage,gpio-pca953x)) - -define KernelPackage/gpio-pcf857x - SUBMENU:=$(OTHER_MENU) - DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core - TITLE:=PCX857x, PCA967x and MAX732X I2C GPIO expanders - KCONFIG:=CONFIG_GPIO_PCF857X - FILES:=$(LINUX_DIR)/drivers/gpio/gpio-pcf857x.ko - AUTOLOAD:=$(call AutoLoad,55,gpio-pcf857x) -endef - -define KernelPackage/gpio-pcf857x/description - Kernel module for PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders -endef - -$(eval $(call KernelPackage,gpio-pcf857x)) - - -define KernelPackage/gpio-it87 - SUBMENU:=$(OTHER_MENU) - DEPENDS:=@GPIO_SUPPORT @TARGET_x86 - TITLE:=GPIO support for IT87xx Super I/O chips - KCONFIG:=CONFIG_GPIO_IT87 - FILES:=$(LINUX_DIR)/drivers/gpio/gpio-it87.ko - AUTOLOAD:=$(call AutoLoad,25,gpio-it87,1) -endef - -define KernelPackage/gpio-it87/description - This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and - supports the IT8761E, IT8613, IT8620E, and IT8628E Super I/O chips as - well. -endef - -$(eval $(call KernelPackage,gpio-it87)) - - -define KernelPackage/gpio-amd-fch - SUBMENU:=$(OTHER_MENU) - DEPENDS:=@GPIO_SUPPORT @TARGET_x86 - TITLE:=GPIO support for AMD Fusion Controller Hub (G-series SOCs) - KCONFIG:=CONFIG_GPIO_AMD_FCH - FILES:=$(LINUX_DIR)/drivers/gpio/gpio-amd-fch.ko - AUTOLOAD:=$(call AutoLoad,25,gpio-amd-fch,1) -endef - -define KernelPackage/gpio-amd-fch/description - This option enables driver for GPIO on AMDs Fusion Controller Hub, - as found on G-series SOCs (eg. GX-412TC) -endef - -$(eval $(call KernelPackage,gpio-amd-fch)) - - define KernelPackage/ppdev SUBMENU:=$(OTHER_MENU) TITLE:=Parallel port support @@ -595,253 +584,6 @@ endef $(eval $(call KernelPackage,mfd)) -define KernelPackage/rtc-ds1307 - SUBMENU:=$(OTHER_MENU) - TITLE:=Dallas/Maxim DS1307 (and compatible) RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core +kmod-regmap-i2c +kmod-hwmon-core - KCONFIG:=CONFIG_RTC_DRV_DS1307 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1307.ko - AUTOLOAD:=$(call AutoProbe,rtc-ds1307) -endef - -define KernelPackage/rtc-ds1307/description - Kernel module for Dallas/Maxim DS1307/DS1337/DS1338/DS1340/DS1388/DS3231, - Epson RX-8025 and various other compatible RTC chips connected via I2C. -endef - -$(eval $(call KernelPackage,rtc-ds1307)) - - -define KernelPackage/rtc-ds1374 - SUBMENU:=$(OTHER_MENU) - TITLE:=Dallas/Maxim DS1374 RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_DS1374 \ - CONFIG_RTC_DRV_DS1374_WDT=n \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1374.ko - AUTOLOAD:=$(call AutoProbe,rtc-ds1374) -endef - -define KernelPackage/rtc-ds1374/description - Kernel module for Dallas/Maxim DS1374. -endef - -$(eval $(call KernelPackage,rtc-ds1374)) - - -define KernelPackage/rtc-ds1672 - SUBMENU:=$(OTHER_MENU) - TITLE:=Dallas/Maxim DS1672 RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_DS1672 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1672.ko - AUTOLOAD:=$(call AutoProbe,rtc-ds1672) -endef - -define KernelPackage/rtc-ds1672/description - Kernel module for Dallas/Maxim DS1672 RTC. -endef - -$(eval $(call KernelPackage,rtc-ds1672)) - - -define KernelPackage/rtc-em3027 - SUBMENU:=$(OTHER_MENU) - TITLE:=Microelectronic EM3027 RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_EM3027 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-em3027.ko - AUTOLOAD:=$(call AutoProbe,rtc-em3027) -endef - -define KernelPackage/rtc-em3027/description - Kernel module for Microelectronic EM3027 RTC. -endef - -$(eval $(call KernelPackage,rtc-em3027)) - - -define KernelPackage/rtc-isl1208 - SUBMENU:=$(OTHER_MENU) - TITLE:=Intersil ISL1208 RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_ISL1208 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-isl1208.ko - AUTOLOAD:=$(call AutoProbe,rtc-isl1208) -endef - -define KernelPackage/rtc-isl1208/description - Kernel module for Intersil ISL1208 RTC. -endef - -$(eval $(call KernelPackage,rtc-isl1208)) - - -define KernelPackage/rtc-mv - SUBMENU:=$(OTHER_MENU) - TITLE:=Marvell SoC RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - KCONFIG:=CONFIG_RTC_DRV_MV \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-mv.ko - AUTOLOAD:=$(call AutoProbe,rtc-mv) -endef - -define KernelPackage/rtc-mv/description - Kernel module for Marvell SoC RTC. -endef - -$(eval $(call KernelPackage,rtc-mv)) - - -define KernelPackage/rtc-pcf8563 - SUBMENU:=$(OTHER_MENU) - TITLE:=Philips PCF8563/Epson RTC8564 RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_PCF8563 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf8563.ko - AUTOLOAD:=$(call AutoProbe,rtc-pcf8563) -endef - -define KernelPackage/rtc-pcf8563/description - Kernel module for Philips PCF8563 RTC chip. - The Epson RTC8564 should work as well. -endef - -$(eval $(call KernelPackage,rtc-pcf8563)) - - -define KernelPackage/rtc-pcf2123 - SUBMENU:=$(OTHER_MENU) - TITLE:=Philips PCF2123 RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-regmap-spi - KCONFIG:=CONFIG_RTC_DRV_PCF2123 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf2123.ko - AUTOLOAD:=$(call AutoProbe,rtc-pcf2123) -endef - -define KernelPackage/rtc-pcf2123/description - Kernel module for Philips PCF2123 RTC chip -endef - -$(eval $(call KernelPackage,rtc-pcf2123)) - -define KernelPackage/rtc-pcf2127 - SUBMENU:=$(OTHER_MENU) - TITLE:=NXP PCF2127 and PCF2129 RTC support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core +kmod-regmap-spi - KCONFIG:=CONFIG_RTC_DRV_PCF2127 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf2127.ko - AUTOLOAD:=$(call AutoProbe,rtc-pcf2127) -endef - -define KernelPackage/rtc-pcf2127/description - Kernel module for NXP PCF2127 and PCF2129 RTC chip -endef - -$(eval $(call KernelPackage,rtc-pcf2127)) - -define KernelPackage/rtc-r7301 - SUBMENU:=$(OTHER_MENU) - TITLE:=Epson RTC7301 support - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-regmap-mmio - KCONFIG:=CONFIG_RTC_DRV_R7301 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-r7301.ko - AUTOLOAD:=$(call AutoProbe,rtc-r7301) -endef - -define KernelPackage/rtc-r7301/description - Kernel module for Epson RTC7301 RTC chip -endef - -$(eval $(call KernelPackage,rtc-r7301)) - -define KernelPackage/rtc-rs5c372a - SUBMENU:=$(OTHER_MENU) - TITLE:=Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_RS5C372 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-rs5c372.ko - AUTOLOAD:=$(call AutoLoad,50,rtc-rs5c372,1) -endef - -define KernelPackage/rtc-rs5c372a/description - Kernel module for Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A RTC on chip module -endef - -$(eval $(call KernelPackage,rtc-rs5c372a)) - -define KernelPackage/rtc-rx8025 - SUBMENU:=$(OTHER_MENU) - TITLE:=Epson RX-8025 / RX-8035 - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_RX8025 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-rx8025.ko - AUTOLOAD:=$(call AutoLoad,50,rtc-rx8025,1) -endef - -define KernelPackage/rtc-rx8025/description - Kernel module for Epson RX-8025 and RX-8035 I2C RTC chip -endef - -$(eval $(call KernelPackage,rtc-rx8025)) - -define KernelPackage/rtc-s35390a - SUBMENU:=$(OTHER_MENU) - TITLE:=Seico S-35390A - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_S35390A \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-s35390a.ko - AUTOLOAD:=$(call AutoLoad,50,rtc-s35390a,1) -endef - -define KernelPackage/rtc-s35390a/description - Kernel module for Seiko Instruments S-35390A I2C RTC chip -endef - -$(eval $(call KernelPackage,rtc-s35390a)) - -define KernelPackage/rtc-x1205 - SUBMENU:=$(OTHER_MENU) - TITLE:=Xicor Intersil X1205 - DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core - KCONFIG:=CONFIG_RTC_DRV_X1205 \ - CONFIG_RTC_CLASS=y - FILES:=$(LINUX_DIR)/drivers/rtc/rtc-x1205.ko - AUTOLOAD:=$(call AutoProbe,rtc-x1205) -endef - -define KernelPackage/rtc-x1205/description - Kernel module for Xicor Intersil X1205 I2C RTC chip -endef - -$(eval $(call KernelPackage,rtc-x1205)) - define KernelPackage/mtdtests SUBMENU:=$(OTHER_MENU) TITLE:=MTD subsystem tests @@ -1239,25 +981,6 @@ endef $(eval $(call KernelPackage,thermal)) -define KernelPackage/gpio-beeper - SUBMENU:=$(OTHER_MENU) - TITLE:=GPIO beeper support - DEPENDS:=+kmod-input-core - KCONFIG:= \ - CONFIG_INPUT_MISC=y \ - CONFIG_INPUT_GPIO_BEEPER - FILES:= \ - $(LINUX_DIR)/drivers/input/misc/gpio-beeper.ko - AUTOLOAD:=$(call AutoLoad,50,gpio-beeper) -endef - -define KernelPackage/gpio-beeper/description - This enables playing beeps through an GPIO-connected buzzer -endef - -$(eval $(call KernelPackage,gpio-beeper)) - - define KernelPackage/echo SUBMENU:=$(OTHER_MENU) TITLE:=Line Echo Canceller diff --git a/openwrt/patch/openwrt-6.x/modules/rtc.mk b/openwrt/patch/openwrt-6.x/modules/rtc.mk new file mode 100644 index 000000000..3658e8598 --- /dev/null +++ b/openwrt/patch/openwrt-6.x/modules/rtc.mk @@ -0,0 +1,255 @@ +# +# Copyright (C) 2006-2024 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +RTC_MENU:=RTC Real-Time Clock Support + +define KernelPackage/rtc-ds1307 + SUBMENU:=$(RTC_MENU) + TITLE:=Dallas/Maxim DS1307 (and compatible) RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core +kmod-regmap-i2c +kmod-hwmon-core + KCONFIG:=CONFIG_RTC_DRV_DS1307 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1307.ko + AUTOLOAD:=$(call AutoProbe,rtc-ds1307) +endef + +define KernelPackage/rtc-ds1307/description + Kernel module for Dallas/Maxim DS1307/DS1337/DS1338/DS1340/DS1388/DS3231, + Epson RX-8025 and various other compatible RTC chips connected via I2C. +endef + +$(eval $(call KernelPackage,rtc-ds1307)) + + +define KernelPackage/rtc-ds1374 + SUBMENU:=$(RTC_MENU) + TITLE:=Dallas/Maxim DS1374 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_DS1374 \ + CONFIG_RTC_DRV_DS1374_WDT=n \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1374.ko + AUTOLOAD:=$(call AutoProbe,rtc-ds1374) +endef + +define KernelPackage/rtc-ds1374/description + Kernel module for Dallas/Maxim DS1374. +endef + +$(eval $(call KernelPackage,rtc-ds1374)) + + +define KernelPackage/rtc-ds1672 + SUBMENU:=$(RTC_MENU) + TITLE:=Dallas/Maxim DS1672 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_DS1672 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1672.ko + AUTOLOAD:=$(call AutoProbe,rtc-ds1672) +endef + +define KernelPackage/rtc-ds1672/description + Kernel module for Dallas/Maxim DS1672 RTC. +endef + +$(eval $(call KernelPackage,rtc-ds1672)) + + +define KernelPackage/rtc-em3027 + SUBMENU:=$(RTC_MENU) + TITLE:=Microelectronic EM3027 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_EM3027 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-em3027.ko + AUTOLOAD:=$(call AutoProbe,rtc-em3027) +endef + +define KernelPackage/rtc-em3027/description + Kernel module for Microelectronic EM3027 RTC. +endef + +$(eval $(call KernelPackage,rtc-em3027)) + + +define KernelPackage/rtc-isl1208 + SUBMENU:=$(RTC_MENU) + TITLE:=Intersil ISL1208 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_ISL1208 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-isl1208.ko + AUTOLOAD:=$(call AutoProbe,rtc-isl1208) +endef + +define KernelPackage/rtc-isl1208/description + Kernel module for Intersil ISL1208 RTC. +endef + +$(eval $(call KernelPackage,rtc-isl1208)) + + +define KernelPackage/rtc-mv + SUBMENU:=$(RTC_MENU) + TITLE:=Marvell SoC RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + KCONFIG:=CONFIG_RTC_DRV_MV \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-mv.ko + AUTOLOAD:=$(call AutoProbe,rtc-mv) +endef + +define KernelPackage/rtc-mv/description + Kernel module for Marvell SoC RTC. +endef + +$(eval $(call KernelPackage,rtc-mv)) + + +define KernelPackage/rtc-pcf8563 + SUBMENU:=$(RTC_MENU) + TITLE:=Philips PCF8563/Epson RTC8564 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_PCF8563 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf8563.ko + AUTOLOAD:=$(call AutoProbe,rtc-pcf8563) +endef + +define KernelPackage/rtc-pcf8563/description + Kernel module for Philips PCF8563 RTC chip. + The Epson RTC8564 should work as well. +endef + +$(eval $(call KernelPackage,rtc-pcf8563)) + + +define KernelPackage/rtc-pcf2123 + SUBMENU:=$(RTC_MENU) + TITLE:=Philips PCF2123 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-regmap-spi + KCONFIG:=CONFIG_RTC_DRV_PCF2123 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf2123.ko + AUTOLOAD:=$(call AutoProbe,rtc-pcf2123) +endef + +define KernelPackage/rtc-pcf2123/description + Kernel module for Philips PCF2123 RTC chip +endef + +$(eval $(call KernelPackage,rtc-pcf2123)) + +define KernelPackage/rtc-pcf2127 + SUBMENU:=$(RTC_MENU) + TITLE:=NXP PCF2127 and PCF2129 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core +kmod-regmap-spi + KCONFIG:=CONFIG_RTC_DRV_PCF2127 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf2127.ko + AUTOLOAD:=$(call AutoProbe,rtc-pcf2127) +endef + +define KernelPackage/rtc-pcf2127/description + Kernel module for NXP PCF2127 and PCF2129 RTC chip +endef + +$(eval $(call KernelPackage,rtc-pcf2127)) + +define KernelPackage/rtc-r7301 + SUBMENU:=$(RTC_MENU) + TITLE:=Epson RTC7301 support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-regmap-mmio + KCONFIG:=CONFIG_RTC_DRV_R7301 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-r7301.ko + AUTOLOAD:=$(call AutoProbe,rtc-r7301) +endef + +define KernelPackage/rtc-r7301/description + Kernel module for Epson RTC7301 RTC chip +endef + +$(eval $(call KernelPackage,rtc-r7301)) + +define KernelPackage/rtc-rs5c372a + SUBMENU:=$(RTC_MENU) + TITLE:=Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_RS5C372 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-rs5c372.ko + AUTOLOAD:=$(call AutoLoad,50,rtc-rs5c372,1) +endef + +define KernelPackage/rtc-rs5c372a/description + Kernel module for Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A RTC on chip module +endef + +$(eval $(call KernelPackage,rtc-rs5c372a)) + +define KernelPackage/rtc-rx8025 + SUBMENU:=$(RTC_MENU) + TITLE:=Epson RX-8025 / RX-8035 + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_RX8025 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-rx8025.ko + AUTOLOAD:=$(call AutoLoad,50,rtc-rx8025,1) +endef + +define KernelPackage/rtc-rx8025/description + Kernel module for Epson RX-8025 and RX-8035 I2C RTC chip +endef + +$(eval $(call KernelPackage,rtc-rx8025)) + +define KernelPackage/rtc-s35390a + SUBMENU:=$(RTC_MENU) + TITLE:=Seico S-35390A + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_S35390A \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-s35390a.ko + AUTOLOAD:=$(call AutoLoad,50,rtc-s35390a,1) +endef + +define KernelPackage/rtc-s35390a/description + Kernel module for Seiko Instruments S-35390A I2C RTC chip +endef + +$(eval $(call KernelPackage,rtc-s35390a)) + +define KernelPackage/rtc-x1205 + SUBMENU:=$(RTC_MENU) + TITLE:=Xicor Intersil X1205 + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_X1205 \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-x1205.ko + AUTOLOAD:=$(call AutoProbe,rtc-x1205) +endef + +define KernelPackage/rtc-x1205/description + Kernel module for Xicor Intersil X1205 I2C RTC chip +endef + +$(eval $(call KernelPackage,rtc-x1205)) diff --git a/openwrt/patch/openwrt-6.x/modules/sound.mk b/openwrt/patch/openwrt-6.x/modules/sound.mk index e8d86809a..15f2ddcce 100644 --- a/openwrt/patch/openwrt-6.x/modules/sound.mk +++ b/openwrt/patch/openwrt-6.x/modules/sound.mk @@ -379,7 +379,7 @@ define KernelPackage/sound-hda-codec-realtek CONFIG_SND_HDA_CODEC_REALTEK FILES:= \ $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-realtek.ko \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-scodec-component.ko@ge6.11 + $(LINUX_DIR)/sound/pci/hda/snd-hda-scodec-component.ko@ge6.12 AUTOLOAD:=$(call AutoProbe,snd-hda-codec-realtek) $(call AddDepends/sound,kmod-sound-hda-core) endef diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index 24ae03668..458c8c4ba 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -272,13 +272,13 @@ $(eval $(call KernelPackage,usb-uhci,1)) define KernelPackage/usb-ohci TITLE:=Support for OHCI controllers DEPENDS:= \ + +TARGET_ath79:kmod-phy-ath79-usb \ +TARGET_bcm53xx:kmod-usb-bcma \ +TARGET_bcm47xx:kmod-usb-bcma \ +TARGET_bcm47xx:kmod-usb-ssb KCONFIG:= \ CONFIG_USB_OHCI \ CONFIG_USB_OHCI_HCD \ - CONFIG_USB_OHCI_ATH79=y \ CONFIG_USB_OHCI_HCD_AT91=y \ CONFIG_USB_OHCI_BCM63XX=y \ CONFIG_USB_OCTEON_OHCI=y \ @@ -572,7 +572,6 @@ $(eval $(call KernelPackage,usb-wdm)) define KernelPackage/usb-audio TITLE:=Support for USB audio devices KCONFIG:= \ - CONFIG_USB_AUDIO \ CONFIG_SND_USB=y \ CONFIG_SND_USB_AUDIO $(call AddDepends/usb) @@ -1200,7 +1199,7 @@ define KernelPackage/usb-net-asix TITLE:=Kernel module for USB-to-Ethernet Asix convertors DEPENDS:= \ +kmod-libphy +kmod-net-selftests +kmod-mdio-devres +kmod-phy-ax88796b \ - +LINUX_6_1:kmod-phylink +kmod-phylink + +kmod-phylink KCONFIG:=CONFIG_USB_NET_AX8817X FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/asix.ko AUTOLOAD:=$(call AutoProbe,asix) @@ -1328,7 +1327,7 @@ $(eval $(call KernelPackage,usb-net-smsc75xx)) define KernelPackage/usb-net-smsc95xx TITLE:=SMSC LAN95XX based USB 2.0 10/100 ethernet devices - DEPENDS:=+kmod-libphy +kmod-phy-smsc +!LINUX_5_15:kmod-net-selftests + DEPENDS:=+kmod-libphy +kmod-phy-smsc +kmod-net-selftests KCONFIG:=CONFIG_USB_NET_SMSC95XX FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/smsc95xx.ko AUTOLOAD:=$(call AutoProbe,smsc95xx) @@ -1793,6 +1792,7 @@ define KernelPackage/usb3 +TARGET_ramips_mt7621:kmod-usb-xhci-mtk \ +TARGET_mediatek:kmod-usb-xhci-mtk \ +TARGET_apm821xx_nand:kmod-usb-xhci-pci-renesas \ + +TARGET_lantiq_xrx200:kmod-usb-xhci-pci-renesas \ +TARGET_mvebu_cortexa9:kmod-usb-xhci-pci-renesas KCONFIG:= \ CONFIG_USB_PCI=y \ @@ -1845,9 +1845,7 @@ $(eval $(call KernelPackage,usb-roles)) define KernelPackage/usb-xhci-hcd TITLE:=xHCI HCD (USB 3.0) support - KCONFIG:= \ - CONFIG_USB_XHCI_HCD \ - CONFIG_USB_XHCI_HCD_DEBUGGING=n + KCONFIG:= CONFIG_USB_XHCI_HCD HIDDEN:=1 FILES:=$(LINUX_DIR)/drivers/usb/host/xhci-hcd.ko AUTOLOAD:=$(call AutoLoad,54,xhci-hcd,1) diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index 4f2fb23b8..009f74654 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -19,19 +19,23 @@ V4L2_MEM2MEM_DIR=platform define KernelPackage/acpi-video SUBMENU:=$(VIDEO_MENU) TITLE:=ACPI Extensions For Display Adapters - DEPENDS:=@TARGET_x86 +kmod-backlight + DEPENDS:=@TARGET_x86||TARGET_loongarch64 +kmod-backlight HIDDEN:=1 - KCONFIG:=CONFIG_ACPI_VIDEO \ - CONFIG_ACPI_WMI - FILES:=$(LINUX_DIR)/drivers/acpi/video.ko \ - $(LINUX_DIR)/drivers/platform/x86/wmi.ko - AUTOLOAD:=$(call AutoProbe,wmi video) + KCONFIG:=CONFIG_ACPI_VIDEO + FILES:=$(LINUX_DIR)/drivers/acpi/video.ko + AUTOLOAD:=$(call AutoProbe,video) endef define KernelPackage/acpi-video/description Kernel support for integrated graphics devices. endef +define KernelPackage/acpi-video/x86 + KCONFIG+=CONFIG_ACPI_WMI + FILES+=$(LINUX_DIR)/drivers/platform/x86/wmi.ko + AUTOLOAD:=$(call AutoProbe,wmi video) +endef + $(eval $(call KernelPackage,acpi-video)) define KernelPackage/backlight @@ -102,8 +106,8 @@ define KernelPackage/fb CONFIG_VT_CONSOLE=y \ CONFIG_VT_HW_CONSOLE_BINDING=y FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb.ko \ - $(LINUX_DIR)/drivers/video/fbdev/core/fb_io_fops.ko@lt6.11 \ - $(LINUX_DIR)/lib/fonts/font.ko + $(LINUX_DIR)/lib/fonts/font.ko \ + $(LINUX_DIR)/drivers/video/fbdev/core/fb_io_fops.ko@lt6.12 AUTOLOAD:=$(call AutoLoad,06,fb font) endef @@ -112,7 +116,7 @@ define KernelPackage/fb/description endef define KernelPackage/fb/x86 - FILES+=$(LINUX_DIR)/arch/x86/video/fbdev.ko@lt6.11 + FILES+=$(LINUX_DIR)/arch/x86/video/fbdev.ko@lt6.12 AUTOLOAD:=$(call AutoLoad,06,fbdev fb font) endef @@ -171,8 +175,8 @@ define KernelPackage/fb-sys-fops TITLE:=Framebuffer software sys ops support DEPENDS:=+kmod-fb KCONFIG:= \ - CONFIG_FB_SYS_FOPS@lt6.11 \ - CONFIG_FB_SYSMEM_FOPS@ge6.11 + CONFIG_FB_SYS_FOPS@lt6.12 \ + CONFIG_FB_SYSMEM_FOPS@ge6.12 FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb_sys_fops.ko AUTOLOAD:=$(call AutoLoad,07,fb_sys_fops) endef @@ -406,7 +410,7 @@ $(eval $(call KernelPackage,drm-suballoc-helper)) define KernelPackage/drm-amdgpu SUBMENU:=$(VIDEO_MENU) TITLE:=AMDGPU DRM support - DEPENDS:=@TARGET_x86 @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-ttm \ + DEPENDS:=@TARGET_x86||TARGET_loongarch64 @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-ttm \ +kmod-drm-ttm-helper +kmod-drm-kms-helper +kmod-i2c-algo-bit +amdgpu-firmware \ +kmod-drm-display-helper +kmod-drm-buddy +kmod-acpi-video \ +kmod-drm-exec +kmod-drm-suballoc-helper @@ -417,7 +421,7 @@ define KernelPackage/drm-amdgpu CONFIG_DEBUG_KERNEL_DC=n FILES:=$(LINUX_DIR)/drivers/gpu/drm/amd/amdgpu/amdgpu.ko \ $(LINUX_DIR)/drivers/gpu/drm/scheduler/gpu-sched.ko \ - $(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko@ge6.5 + $(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko AUTOLOAD:=$(call AutoProbe,amdgpu) endef @@ -425,6 +429,13 @@ define KernelPackage/drm-amdgpu/description Direct Rendering Manager (DRM) support for AMDGPU Cards endef +define KernelPackage/drm-amdgpu/loongarch64 + KCONFIG+=CONFIG_DRM_AMDGPU_USERPTR=y \ + CONFIG_DRM_AMD_DC=y \ + CONFIG_DRM_AMD_DC_FP=y \ + CONFIG_DRM_AMD_DC_SI=y +endef + $(eval $(call KernelPackage,drm-amdgpu)) @@ -447,9 +458,8 @@ define KernelPackage/drm-imx CONFIG_DRM_IMX_LDB=n \ CONFIG_DRM_IMX_HDMI=n FILES:= \ - $(LINUX_DIR)/drivers/gpu/drm/imx/imxdrm.ko@lt6.6 \ - $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/imxdrm.ko@ge6.6 \ - $(LINUX_DIR)/drivers/gpu/drm/drm_dma_helper.ko@ge6.1 \ + $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/imxdrm.ko \ + $(LINUX_DIR)/drivers/gpu/drm/drm_dma_helper.ko \ $(LINUX_DIR)/drivers/gpu/ipu-v3/imx-ipu-v3.ko AUTOLOAD:=$(call AutoLoad,08,imxdrm imx-ipu-v3 imx-ipuv3-crtc) endef @@ -470,8 +480,7 @@ define KernelPackage/drm-imx-hdmi FILES:= \ $(LINUX_DIR)/drivers/gpu/drm/bridge/synopsys/dw-hdmi.ko \ $(LINUX_DIR)/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.ko \ - $(LINUX_DIR)/drivers/gpu/drm/imx/dw_hdmi-imx.ko@lt6.6 \ - $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.ko@ge6.6 + $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.ko AUTOLOAD:=$(call AutoLoad,08,dw-hdmi dw-hdmi-ahb-audio.ko dw_hdmi-imx) endef @@ -495,10 +504,9 @@ define KernelPackage/drm-imx-ldb CONFIG_DRM_PANEL_LVDS=n \ CONFIG_DRM_PANEL_S6E8AA0=n \ CONFIG_DRM_PANEL_SITRONIX_ST7789V=n - FILES:=$(LINUX_DIR)/drivers/gpu/drm/imx/imx-ldb.ko@lt6.6 \ - $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/imx-ldb.ko@ge6.6 \ - $(LINUX_DIR)/drivers/gpu/drm/panel/panel-simple.ko \ - $(LINUX_DIR)/drivers/gpu/drm/drm_dp_aux_bus.ko@lt6.1 + FILES:= \ + $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/imx-ldb.ko \ + $(LINUX_DIR)/drivers/gpu/drm/panel/panel-simple.ko AUTOLOAD:=$(call AutoLoad,08,imx-ldb) endef @@ -597,7 +605,7 @@ define KernelPackage/video-core CONFIG_MEDIA_CAMERA_SUPPORT=y \ CONFIG_VIDEO_DEV \ CONFIG_V4L_PLATFORM_DRIVERS=y \ - CONFIG_MEDIA_PLATFORM_DRIVERS=y@ge6.1 + CONFIG_MEDIA_PLATFORM_DRIVERS=y FILES:= \ $(LINUX_DIR)/drivers/media/$(V4L2_DIR)/videodev.ko AUTOLOAD:=$(call AutoLoad,60,videodev) @@ -652,7 +660,7 @@ $(eval $(call KernelPackage,video-videobuf2)) define KernelPackage/video-cpia2 TITLE:=CPIA2 video driver - DEPENDS:=@USB_SUPPORT +kmod-usb-core @LINUX_5_15 + DEPENDS:=@USB_SUPPORT KCONFIG:=CONFIG_VIDEO_CPIA2 FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/cpia2/cpia2.ko AUTOLOAD:=$(call AutoProbe,cpia2) @@ -687,10 +695,10 @@ $(eval $(call KernelPackage,video-pwc)) define KernelPackage/video-uvc TITLE:=USB Video Class (UVC) support DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-video-videobuf2 +kmod-input-core - KCONFIG:= CONFIG_USB_VIDEO_CLASS CONFIG_UVC_COMMON@ge6.3 + KCONFIG:= CONFIG_USB_VIDEO_CLASS CONFIG_UVC_COMMON FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/uvc/uvcvideo.ko \ - $(LINUX_DIR)/drivers/media/common/uvc.ko@ge6.3 - AUTOLOAD:=$(call AutoProbe,uvc@ge6.3 uvcvideo) + $(LINUX_DIR)/drivers/media/common/uvc.ko + AUTOLOAD:=$(call AutoProbe,uvc uvcvideo) $(call AddDepends/camera) endef @@ -860,6 +868,21 @@ endef $(eval $(call KernelPackage,video-gspca-pac207)) +define KernelPackage/video-gspca-pac7302 + TITLE:=pac7302 webcam support + KCONFIG:=CONFIG_USB_GSPCA_PAC7302 + FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_pac7302.ko + AUTOLOAD:=$(call AutoProbe,gspca_pac7302) + $(call AddDepends/camera-gspca) +endef + +define KernelPackage/video-gspca-pac7302/description + The Pixart PAC7302 USB Camera Driver (pac7302) kernel module +endef + +$(eval $(call KernelPackage,video-gspca-pac7302)) + + define KernelPackage/video-gspca-pac7311 TITLE:=pac7311 webcam support KCONFIG:=CONFIG_USB_GSPCA_PAC7311 @@ -1295,15 +1318,13 @@ $(eval $(call KernelPackage,video-dma-sg)) define KernelPackage/video-coda TITLE:=i.MX VPU support - DEPENDS:=@(TARGET_imx&&!TARGET_imx_cortexa7) +kmod-video-mem2mem +kmod-video-dma-contig + DEPENDS:=@(TARGET_imx&&TARGET_imx_cortexa9) +kmod-video-mem2mem +kmod-video-dma-contig KCONFIG:= \ CONFIG_VIDEO_CODA \ CONFIG_VIDEO_IMX_VDOA FILES:= \ - $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/coda/coda-vpu.ko@lt6.1 \ - $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/chips-media/coda-vpu.ko@ge6.1 \ - $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/coda/imx-vdoa.ko@lt6.1 \ - $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/chips-media/imx-vdoa.ko@ge6.1 \ + $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/chips-media/coda-vpu.ko \ + $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/chips-media/imx-vdoa.ko \ $(LINUX_DIR)/drivers/media/$(V4L2_DIR)/v4l2-jpeg.ko AUTOLOAD:=$(call AutoProbe,coda-vpu imx-vdoa v4l2-jpeg) $(call AddDepends/video) @@ -1319,8 +1340,7 @@ define KernelPackage/video-pxp TITLE:=i.MX PXP support DEPENDS:=@TARGET_imx +kmod-video-mem2mem +kmod-video-dma-contig KCONFIG:= CONFIG_VIDEO_IMX_PXP - FILES:= $(LINUX_DIR)/drivers/media/$(V4L2_MEM2MEM_DIR)/imx-pxp.ko@lt6.1 \ - $(LINUX_DIR)/drivers/media/platform/nxp/imx-pxp.ko@ge6.1 + FILES:= $(LINUX_DIR)/drivers/media/platform/nxp/imx-pxp.ko AUTOLOAD:=$(call AutoProbe,imx-pxp) $(call AddDepends/video) endef diff --git a/openwrt/patch/openwrt-6.x/modules/virt.mk b/openwrt/patch/openwrt-6.x/modules/virt.mk index 8f4445c52..88137df6b 100644 --- a/openwrt/patch/openwrt-6.x/modules/virt.mk +++ b/openwrt/patch/openwrt-6.x/modules/virt.mk @@ -22,7 +22,7 @@ define KernelPackage/kvm-x86 KCONFIG:=\ CONFIG_KVM \ CONFIG_KVM_MMU_AUDIT=n \ - CONFIG_KVM_SMM=y@ge6.6 \ + CONFIG_KVM_SMM=y \ CONFIG_VIRTUALIZATION=y FILES:= $(LINUX_DIR)/arch/$(LINUX_KARCH)/kvm/kvm.ko AUTOLOAD:=$(call AutoProbe,kvm.ko) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 6b8a8c56b..3d3d615dc 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -67,7 +67,7 @@ pushd package/kernel/linux/modules curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/crypto.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/firewire.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/fs.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/gpio-cascade.mk + curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/gpio.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/hwmon.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/i2c.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/iio.mk @@ -81,6 +81,7 @@ pushd package/kernel/linux/modules curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/nls.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/other.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/pcmcia.mk + curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/rtc.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/sound.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/spi.mk curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/usb.mk From 6a6628343b64c99e617384625968aed384196f83 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 05:36:23 +0800 Subject: [PATCH 117/425] openwrt-24.10: fix toolchain caches Signed-off-by: sbwml --- openwrt/build.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index a0bd2508e..0c3f50090 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -108,13 +108,13 @@ fi # gcc14 & 15 if [ "$USE_GCC13" = y ]; then - export USE_GCC14=y gcc_version=13 + export USE_GCC13=y gcc_version=13 elif [ "$USE_GCC14" = y ]; then export USE_GCC14=y gcc_version=14 elif [ "$USE_GCC15" = y ]; then export USE_GCC15=y gcc_version=15 else - export gcc_version=13 + export USE_GCC13=y gcc_version=13 fi [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y @@ -331,8 +331,8 @@ if [ "$ENABLE_LOCAL_KMOD" = "y" ]; then fi # gcc15 patches +[ "$(whoami)" = "runner" ] && group "patching toolchain" curl -s https://$mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 - # gcc config [ "$USE_GCC13" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc13 >> .config [ "$USE_GCC14" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc14 >> .config @@ -355,7 +355,7 @@ if [ "$BUILD_FAST" = "y" ]; then if [ "$PLATFORM_ID" = "platform:el9" ]; then TOOLCHAIN_URL="http://127.0.0.1:8080" else - TOOLCHAIN_URL=https://"$github_proxy"github.com/sbwml/openwrt_caches/releases/download/${openwrt_version} + TOOLCHAIN_URL=https://"$github_proxy"github.com/sbwml/openwrt_caches/releases/download/openwrt-24.10 fi curl -L ${TOOLCHAIN_URL}/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}.tar.zst -o toolchain.tar.zst $CURL_BAR echo -e "\n${GREEN_COLOR}Process Toolchain ...${RES}" From cf1f5667c5fbcc1d534ac8f74384697bd4d5aaf6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 08:19:38 +0800 Subject: [PATCH 118/425] modules: fix `kmod-lan743x` depends Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/netdevices.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index 811f1cdb9..7d1129c99 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -1946,7 +1946,7 @@ $(eval $(call KernelPackage,atlantic)) define KernelPackage/lan743x SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Microchip LAN743x PCI Express Gigabit Ethernet NIC - DEPENDS:=@PCI_SUPPORT +kmod-ptp +kmod-mdio-devres +kmod-fixed-phy + DEPENDS:=@PCI_SUPPORT +kmod-ptp +kmod-mdio-devres +kmod-fixed-phy +kmod-phylink KCONFIG:=CONFIG_LAN743X FILES:=$(LINUX_DIR)/drivers/net/ethernet/microchip/lan743x.ko AUTOLOAD:=$(call AutoProbe,lan743x) From 7e8ec4f76b9b37bb32aedac9af724484175972ee Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 09:12:24 +0800 Subject: [PATCH 119/425] gcc15: add ccache Signed-off-by: sbwml --- openwrt/build.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 0c3f50090..e430a4386 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -345,6 +345,14 @@ curl -s https://$mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-suppor # not all kmod [ "$NO_KMOD" = "y" ] && sed -i '/CONFIG_ALL_KMODS=y/d; /CONFIG_ALL_NONSHARED=y/d' .config +# ccache +if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then + echo "CONFIG_CCACHE=y" >> .config + [ "$(whoami)" = "runner" ] && echo "CONFIG_CCACHE_DIR=\"/builder/.ccache\"" >> .config + [ "$(whoami)" = "sbwml" ] && echo "CONFIG_CCACHE_DIR=\"/home/sbwml/.ccache\"" >> .config + tools_suffix="_ccache" +fi + # Toolchain Cache if [ "$BUILD_FAST" = "y" ]; then [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl @@ -357,7 +365,7 @@ if [ "$BUILD_FAST" = "y" ]; then else TOOLCHAIN_URL=https://"$github_proxy"github.com/sbwml/openwrt_caches/releases/download/openwrt-24.10 fi - curl -L ${TOOLCHAIN_URL}/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}.tar.zst -o toolchain.tar.zst $CURL_BAR + curl -L ${TOOLCHAIN_URL}/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}${tools_suffix}.tar.zst -o toolchain.tar.zst $CURL_BAR echo -e "\n${GREEN_COLOR}Process Toolchain ...${RES}" tar -I "zstd" -xf toolchain.tar.zst rm -f toolchain.tar.zst @@ -382,7 +390,7 @@ if [ "$BUILD_TOOLCHAIN" = "y" ]; then rm -f dl/clang-* mkdir -p toolchain-cache [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl - tar -I "zstd -19 -T$(nproc --all)" -cf toolchain-cache/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}.tar.zst ./{build_dir,dl,staging_dir,tmp} + tar -I "zstd -19 -T$(nproc --all)" -cf toolchain-cache/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}${tools_suffix}.tar.zst ./{build_dir,dl,staging_dir,tmp} echo -e "\n${GREEN_COLOR} Build success! ${RES}" exit 0 else From d0158bf354d7b1643143c5b6c0af7126545e3a29 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 09:13:22 +0800 Subject: [PATCH 120/425] openwrt-24.10: drop obsolete changes Signed-off-by: sbwml --- ...ss-output-TCP-BBRv3-diag-information.patch | 158 ++++++++++++++++++ ...roduce-the-ecn_low-per-route-feature.patch | 114 +++++++++++++ ...ow-if-tcp_info-tcpi_options-TCPI_OPT.patch | 52 ++++++ .../100-macremapper-fix-clang-build.patch | 2 +- openwrt/scripts/01-prepare_base-mainline.sh | 5 + openwrt/scripts/05-fix-source.sh | 6 - 6 files changed, 330 insertions(+), 7 deletions(-) create mode 100644 openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch create mode 100644 openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch create mode 100644 openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch diff --git a/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch b/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch new file mode 100644 index 000000000..c63673d7f --- /dev/null +++ b/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch @@ -0,0 +1,158 @@ +From ca7f11ebc4d4a99ccfd44be8555d505b26996c12 Mon Sep 17 00:00:00 2001 +From: Arjun Roy +Date: Mon, 25 Jul 2022 12:49:35 -0400 +Subject: [PATCH 2/2] ss: output TCP BBRv3 diag information + +Add logic for printing diag information for TCP BBRv3 congestion +control. This commit leaves in place the support for printing the +earlier TCP BBRv1 congestion control information. + +Both BBRv1 and BBRv3 are using the same enum value. The BBRv3 struct +starts with the same data as BBRv1, so it is is backward-compatible +with BBRv1, to allow lder ss binaries to print basic information for +BBRv3. We use the size of the returned data and the version field to +check the version of the data. + +Signed-off-by: Arjun Roy +Signed-off-by: Neal Cardwell +Signed-off-by: David Morley +--- + include/uapi/linux/inet_diag.h | 23 ++++++++++++ + misc/ss.c | 66 +++++++++++++++++++++++++++++++++- + 2 files changed, 88 insertions(+), 1 deletion(-) + +--- a/include/uapi/linux/inet_diag.h ++++ b/include/uapi/linux/inet_diag.h +@@ -229,6 +229,29 @@ struct tcp_bbr_info { + __u32 bbr_min_rtt; /* min-filtered RTT in uSec */ + __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */ + __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */ ++ __u32 bbr_bw_hi_lsb; /* lower 32 bits of bw_hi */ ++ __u32 bbr_bw_hi_msb; /* upper 32 bits of bw_hi */ ++ __u32 bbr_bw_lo_lsb; /* lower 32 bits of bw_lo */ ++ __u32 bbr_bw_lo_msb; /* upper 32 bits of bw_lo */ ++ __u8 bbr_mode; /* current bbr_mode in state machine */ ++ __u8 bbr_phase; /* current state machine phase */ ++ __u8 unused1; /* alignment padding; not used yet */ ++ __u8 bbr_version; /* BBR algorithm version */ ++ __u32 bbr_inflight_lo; /* lower short-term data volume bound */ ++ __u32 bbr_inflight_hi; /* higher long-term data volume bound */ ++ __u32 bbr_extra_acked; /* max excess packets ACKed in epoch */ ++}; ++ ++/* TCP BBR congestion control bbr_phase as reported in netlink/ss stats. */ ++enum tcp_bbr_phase { ++ BBR_PHASE_INVALID = 0, ++ BBR_PHASE_STARTUP = 1, ++ BBR_PHASE_DRAIN = 2, ++ BBR_PHASE_PROBE_RTT = 3, ++ BBR_PHASE_PROBE_BW_UP = 4, ++ BBR_PHASE_PROBE_BW_DOWN = 5, ++ BBR_PHASE_PROBE_BW_CRUISE = 6, ++ BBR_PHASE_PROBE_BW_REFILL = 7, + }; + + union tcp_cc_info { +--- a/misc/ss.c ++++ b/misc/ss.c +@@ -895,6 +895,7 @@ struct tcpstat { + bool app_limited; + struct dctcpstat *dctcp; + struct tcp_bbr_info *bbr_info; ++ unsigned int bbr_info_len; + }; + + /* SCTP assocs share the same inode number with their parent endpoint. So if we +@@ -2597,6 +2598,29 @@ static void sctp_stats_print(struct sctp + out(" fraginl:%d", s->sctpi_s_frag_interleave); + } + ++static const char* bbr_phase_to_str(enum tcp_bbr_phase phase) ++{ ++ switch (phase) { ++ case BBR_PHASE_STARTUP: ++ return "STARTUP"; ++ case BBR_PHASE_DRAIN: ++ return "DRAIN"; ++ case BBR_PHASE_PROBE_RTT: ++ return "PROBE_RTT"; ++ case BBR_PHASE_PROBE_BW_UP: ++ return "PROBE_BW_UP"; ++ case BBR_PHASE_PROBE_BW_DOWN: ++ return "PROBE_BW_DOWN"; ++ case BBR_PHASE_PROBE_BW_CRUISE: ++ return "PROBE_BW_CRUISE"; ++ case BBR_PHASE_PROBE_BW_REFILL: ++ return "PROBE_BW_REFILL"; ++ case BBR_PHASE_INVALID: ++ default: ++ return "INVALID"; ++ } ++} ++ + static void tcp_stats_print(struct tcpstat *s) + { + char b1[64]; +@@ -2672,7 +2696,14 @@ static void tcp_stats_print(struct tcpst + } + + if (s->bbr_info) { +- __u64 bw; ++ /* All versions of the BBR algorithm use the INET_DIAG_BBRINFO ++ * enum value. Later versions of the tcp_bbr_info struct are ++ * backward-compatible with earlier versions, to allow older ss ++ * binaries to print basic information for newer versions of ++ * the algorithm. We use the size of the returned tcp_bbr_info ++ * struct to decide how much to print. ++ */ ++ __u64 bw, bw_hi, bw_lo; + + bw = s->bbr_info->bbr_bw_hi; + bw <<= 32; +@@ -2687,6 +2718,38 @@ static void tcp_stats_print(struct tcpst + if (s->bbr_info->bbr_cwnd_gain) + out(",cwnd_gain:%g", + (double)s->bbr_info->bbr_cwnd_gain / 256.0); ++ ++ if (s->bbr_info_len >= ++ (offsetof(struct tcp_bbr_info, bbr_extra_acked) + ++ sizeof(__u32))) { ++ ++ bw_hi = s->bbr_info->bbr_bw_hi_msb; ++ bw_hi <<= 32; ++ bw_hi |= s->bbr_info->bbr_bw_hi_lsb; ++ ++ bw_lo = s->bbr_info->bbr_bw_lo_msb; ++ bw_lo <<= 32; ++ bw_lo |= s->bbr_info->bbr_bw_lo_lsb; ++ ++ out(",version:%u", s->bbr_info->bbr_version); ++ if (bw_hi != ~0UL) ++ out(",bw_hi:%sbps", sprint_bw(b1, bw_hi * 8.0)); ++ if (bw_lo != ~0UL) ++ out(",bw_lo:%sbps", sprint_bw(b1, bw_lo * 8.0)); ++ if (s->bbr_info->bbr_inflight_hi != ~0U) ++ out(",inflight_hi:%u", ++ s->bbr_info->bbr_inflight_hi); ++ if (s->bbr_info->bbr_inflight_lo != ~0U) ++ out(",inflight_lo:%u", ++ s->bbr_info->bbr_inflight_lo); ++ out(",extra_acked:%u", s->bbr_info->bbr_extra_acked); ++ out(",mode:%d", (int)s->bbr_info->bbr_mode); ++ out(",phase:%s", ++ bbr_phase_to_str( ++ (enum tcp_bbr_phase) ++ s->bbr_info->bbr_phase)); ++ } ++ + out(")"); + } + +@@ -3174,6 +3237,7 @@ static void tcp_show_info(const struct n + s.bbr_info = calloc(1, sizeof(*s.bbr_info)); + if (s.bbr_info && bbr_info) + memcpy(s.bbr_info, bbr_info, len); ++ s.bbr_info_len = len; + } + + if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) { diff --git a/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch b/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch new file mode 100644 index 000000000..80b9b7132 --- /dev/null +++ b/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch @@ -0,0 +1,114 @@ +From 537b1b761e1d0036923adba7a80d3655cfff095d Mon Sep 17 00:00:00 2001 +From: David Morley +Date: Fri, 21 Jul 2023 09:20:46 +0000 +Subject: [PATCH 1/2] ip: introduce the ecn_low per-route feature + +Add a a new "ecn_low" feature that administrators can add to a +particular ip route. The ecn_low feature indicates that the given +destination network is a low-latency ECN environment, meaning both +that ECN CE marks are applied by the network using a low-latency +marking threshold and also that TCP endpoints provide precise +per-data-segment ECN feedback in ACKs (where the ACK ECE flag echoes +the received CE status of all newly-acknowledged data segments). This +ecn_low feature indication can be used by congestion control +algorithms to decide how to interpret ECN signals over the given +destination network. + +Signed-off-by: David Morley +Signed-off-by: Neal Cardwell +--- + include/uapi/linux/rtnetlink.h | 4 +++- + ip/iproute.c | 8 +++++++- + man/man8/ip-route.8.in | 19 ++++++++++++++----- + 3 files changed, 24 insertions(+), 7 deletions(-) + +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -508,12 +508,14 @@ enum { + #define RTAX_FEATURE_TIMESTAMP (1 << 2) /* unused */ + #define RTAX_FEATURE_ALLFRAG (1 << 3) /* unused */ + #define RTAX_FEATURE_TCP_USEC_TS (1 << 4) ++#define RTAX_FEATURE_ECN_LOW (1 << 5) + + #define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | \ + RTAX_FEATURE_SACK | \ + RTAX_FEATURE_TIMESTAMP | \ + RTAX_FEATURE_ALLFRAG | \ +- RTAX_FEATURE_TCP_USEC_TS) ++ RTAX_FEATURE_TCP_USEC_TS | \ ++ RTAX_FEATURE_ECN_LOW) + + struct rta_session { + __u8 proto; +--- a/ip/iproute.c ++++ b/ip/iproute.c +@@ -97,7 +97,7 @@ static void usage(void) + "PREF := [ low | medium | high ]\n" + "TIME := NUMBER[s|ms]\n" + "BOOL := [1|0]\n" +- "FEATURES := ecn\n" ++ "FEATURES := [ ecn | ecn_low ]\n" + "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 | xfrm ]\n" + "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR | XFRMINFO ]\n" + "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n" +@@ -373,6 +373,10 @@ static void print_rtax_features(FILE *fp + print_null(PRINT_ANY, "ecn", "ecn ", NULL); + features &= ~RTAX_FEATURE_ECN; + } ++ if (features & RTAX_FEATURE_ECN_LOW) { ++ print_null(PRINT_ANY, "ecn_low", "ecn_low ", NULL); ++ features &= ~RTAX_FEATURE_ECN_LOW; ++ } + + if (features & RTAX_FEATURE_TCP_USEC_TS) { + print_null(PRINT_ANY, "tcp_usec_ts", "tcp_usec_ts ", NULL); +@@ -1381,6 +1385,8 @@ static int iproute_modify(int cmd, unsig + features |= RTAX_FEATURE_ECN; + else if (strcmp(*argv, "tcp_usec_ts") == 0) + features |= RTAX_FEATURE_TCP_USEC_TS; ++ else if (strcmp(*argv, "ecn_low") == 0) ++ features |= RTAX_FEATURE_ECN_LOW; + else + invarg("\"features\" value not valid\n", *argv); + break; +--- a/man/man8/ip-route.8.in ++++ b/man/man8/ip-route.8.in +@@ -184,7 +184,7 @@ throw " | " unreachable " | " prohibit " + + .ti -8 + .IR FEATURES " := [ " +-.BR ecn " | ]" ++.BR ecn " | " ecn_low " ] " + + .ti -8 + .IR PREF " := [ " +@@ -556,16 +556,25 @@ The default value is zero, meaning to us + + .TP + .BI features " FEATURES " (Linux 3.18+ only) +-Enable or disable per-route features. Only available feature at this +-time is +-.B ecn +-to enable explicit congestion notification when initiating connections to the ++Enable or disable per-route features. Available features include: ++ ++.BI ecn ++- to enable explicit congestion notification when initiating connections to the + given destination network. + When responding to a connection request from the given network, ecn will + also be used even if the + .B net.ipv4.tcp_ecn + sysctl is set to 0. + ++.BI ecn_low ++- to indicate that the given destination network is a low-latency ECN ++environment, meaning both that ECN CE marks are applied by the network using a ++low-latency marking threshold and also that TCP endpoints provide precise ++per-data-segment ECN feedback in ACKs (where the ACK ECE flag echoes the ++received CE status of all newly-acknowledged data segments). This ecn_low ++feature indication can be used by congestion control algorithms to decide how ++to interpret ECN signals over the given destination network (Linux 6.7+ only). ++ + .TP + .BI quickack " BOOL " "(Linux 3.11+ only)" + Enable or disable quick ack for connections to this destination. diff --git a/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch b/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch new file mode 100644 index 000000000..91b9fe69c --- /dev/null +++ b/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch @@ -0,0 +1,52 @@ +From 107339d7f48c95ae8a7461150e143fc53b08fea9 Mon Sep 17 00:00:00 2001 +From: Neal Cardwell +Date: Sun, 23 Jul 2023 23:33:21 -0400 +Subject: [PATCH] ss: display "ecn_low" if tcp_info tcpi_options + TCPI_OPT_ECN_LOW bit is set + +Display "ecn_low" if the TCPI_OPT_ECN_LOW bit is set in the +tcpi_options field in tcp_info. + +Signed-off-by: Neal Cardwell +--- + include/uapi/linux/tcp.h | 1 + + misc/ss.c | 4 ++++ + 2 files changed, 5 insertions(+) + +--- a/include/uapi/linux/tcp.h ++++ b/include/uapi/linux/tcp.h +@@ -178,6 +178,7 @@ enum tcp_fastopen_client_fail { + #define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */ + #define TCPI_OPT_SYN_DATA 32 /* SYN-ACK acked data in SYN sent or rcvd */ + #define TCPI_OPT_USEC_TS 64 /* usec timestamps */ ++#define TCPI_OPT_ECN_LOW 64 /* Low-latency ECN configured at init */ + + /* + * Sender's congestion state indicating normal or abnormal situations +--- a/misc/ss.c ++++ b/misc/ss.c +@@ -890,6 +890,7 @@ struct tcpstat { + bool has_sack_opt; + bool has_ecn_opt; + bool has_ecnseen_opt; ++ bool has_ecn_low_opt; + bool has_fastopen_opt; + bool has_wscale_opt; + bool app_limited; +@@ -2635,6 +2636,8 @@ static void tcp_stats_print(struct tcpst + out(" ecn"); + if (s->has_ecnseen_opt) + out(" ecnseen"); ++ if (s->has_ecn_low_opt) ++ out(" ecn_low"); + if (s->has_fastopen_opt) + out(" fastopen"); + if (s->cong_alg[0]) +@@ -3161,6 +3164,7 @@ static void tcp_show_info(const struct n + s.has_sack_opt = TCPI_HAS_OPT(info, TCPI_OPT_SACK); + s.has_ecn_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN); + s.has_ecnseen_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN); ++ s.has_ecn_low_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_LOW); + s.has_fastopen_opt = TCPI_HAS_OPT(info, TCPI_OPT_SYN_DATA); + } + diff --git a/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch b/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch index 597b5de79..08de7946a 100644 --- a/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch +++ b/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch @@ -1,6 +1,6 @@ --- a/feeds/packages/kernel/macremapper/Makefile +++ b/feeds/packages/kernel/macremapper/Makefile -@@ -39,4 +39,13 @@ endef +@@ -38,4 +38,13 @@ endef MAKE_FLAGS += KERNEL_SRC=$(LINUX_DIR) ARCH=$(LINUX_KARCH) MAKE_PATH:=kernelmod diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 3d3d615dc..7a58276cb 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -155,6 +155,11 @@ pushd target/linux/generic/hack-6.12 curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch popd +# iproute2 - bbr3 +curl -s https://init2.cooluc.com/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch > package/network/utils/iproute2/patches/900-ss-output-TCP-BBRv3-diag-information.patch +curl -s https://init2.cooluc.com/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch > package/network/utils/iproute2/patches/901-ip-introduce-the-ecn_low-per-route-feature.patch +curl -s https://init2.cooluc.com/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch > package/network/utils/iproute2/patches/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch + # linux-firmware: rtw89 / rtl8723d / rtl8821c /i915 firmware rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index c3272ecdc..252f974e5 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -18,12 +18,6 @@ git clone https://$github/sbwml/package_network_utils_xdp-tools package/network/ # fix gcc14 if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then - # iproute2 - rm -rf package/network/utils/iproute2 - git clone https://$github/sbwml/package_network_utils_iproute2 package/network/utils/iproute2 - # libunwind - rm -rf package/libs/libunwind - git clone https://$github/sbwml/package_libs_libunwind package/libs/libunwind # linux-atm rm -rf package/network/utils/linux-atm git clone https://$github/sbwml/package_network_utils_linux-atm package/network/utils/linux-atm From a81c05e5afca9ad3d0589951566667367726f370 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 14:41:15 +0800 Subject: [PATCH 121/425] llvm/clang using system variable * Avoid unnecessary `tools/clang` build time` Signed-off-by: sbwml --- .github/workflows/build-release.yml | 3 + openwrt/build.sh | 6 -- .../0001-tools-add-llvm-clang-toolchain.patch | 89 ------------------- ...s.patch => 0001-tools-add-upx-tools.patch} | 8 +- ...-rootfs-add-upx-compression-support.patch} | 4 +- ...rmissions-for-UCI-configuration-fil.patch} | 4 +- ...t-for-local-kmod-installation-sourc.patch} | 4 +- ...Add-support-for-llvm-clang-compiler.patch} | 4 +- ...ernel-add-out-of-tree-kernel-config.patch} | 4 +- ...rnel-add-miss-config-for-linux-6.11.patch} | 4 +- ...m-variable-to-cross-compilation-fil.patch} | 4 +- ...-legacy-cgroup-v1-memory-controller.patch} | 4 +- ...EEMPT_RT-support-for-aarch64-x86_64.patch} | 4 +- openwrt/scripts/00-prepare_base.sh | 52 +++-------- 14 files changed, 36 insertions(+), 158 deletions(-) delete mode 100644 openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch rename openwrt/patch/generic-24.10/{0002-tools-add-upx-tools.patch => 0001-tools-add-upx-tools.patch} (89%) rename openwrt/patch/generic-24.10/{0003-rootfs-add-upx-compression-support.patch => 0002-rootfs-add-upx-compression-support.patch} (89%) rename openwrt/patch/generic-24.10/{0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch => 0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch} (83%) rename openwrt/patch/generic-24.10/{0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch => 0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch} (92%) rename openwrt/patch/generic-24.10/{0006-kernel-Add-support-for-llvm-clang-compiler.patch => 0005-kernel-Add-support-for-llvm-clang-compiler.patch} (94%) rename openwrt/patch/generic-24.10/{0007-build-kernel-add-out-of-tree-kernel-config.patch => 0006-build-kernel-add-out-of-tree-kernel-config.patch} (97%) rename openwrt/patch/generic-24.10/{0008-include-kernel-add-miss-config-for-linux-6.11.patch => 0007-include-kernel-add-miss-config-for-linux-6.11.patch} (86%) rename openwrt/patch/generic-24.10/{0009-meson-add-platform-variable-to-cross-compilation-fil.patch => 0008-meson-add-platform-variable-to-cross-compilation-fil.patch} (89%) rename openwrt/patch/generic-24.10/{0010-kernel-add-legacy-cgroup-v1-memory-controller.patch => 0009-kernel-add-legacy-cgroup-v1-memory-controller.patch} (89%) rename openwrt/patch/generic-24.10/{0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch => 0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch} (90%) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index ab31cba49..68a30d902 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -67,6 +67,9 @@ jobs: - name: Build System Setup uses: sbwml/actions@openwrt-build-setup + - name: Install LLVM + uses: sbwml/actions@install-llvm + - name: Compile OpenWrt working-directory: /builder id: compile diff --git a/openwrt/build.sh b/openwrt/build.sh index e430a4386..b4b03eb84 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -386,18 +386,12 @@ fi if [ "$BUILD_TOOLCHAIN" = "y" ]; then echo -e "\r\n${GREEN_COLOR}Building Toolchain ...${RES}\r\n" make -j$cores toolchain/compile || make -j$cores toolchain/compile V=s || exit 1 - make tools/clang/clean - rm -f dl/clang-* mkdir -p toolchain-cache [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl tar -I "zstd -19 -T$(nproc --all)" -cf toolchain-cache/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}${tools_suffix}.tar.zst ./{build_dir,dl,staging_dir,tmp} echo -e "\n${GREEN_COLOR} Build success! ${RES}" exit 0 else - if [ "$BUILD_FAST" = "y" ]; then - echo -e "\r\n${GREEN_COLOR}Building tools/clang ...${RES}\r\n" - make tools/clang/compile -j$cores - fi echo -e "\r\n${GREEN_COLOR}Building OpenWrt ...${RES}\r\n" sed -i "/BUILD_DATE/d" package/base-files/files/usr/lib/os-release sed -i "/BUILD_ID/aBUILD_DATE=\"$CURRENT_DATE\"" package/base-files/files/usr/lib/os-release diff --git a/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch b/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch deleted file mode 100644 index 50bf16244..000000000 --- a/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch +++ /dev/null @@ -1,89 +0,0 @@ -From a18334ecf9c643badcb33c034b59ea6c9c8fb323 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Fri, 4 Oct 2024 10:35:57 +0800 -Subject: [PATCH 01/11] tools: add llvm/clang toolchain - -Signed-off-by: sbwml ---- - tools/Makefile | 7 +++++++ - tools/clang/Makefile | 43 +++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 50 insertions(+) - create mode 100644 tools/clang/Makefile - -diff --git a/tools/Makefile b/tools/Makefile -index b16c5d9..7937334 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -29,6 +29,12 @@ endif - ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),) - BUILD_LZO_TOOLS = y - endif -+ifeq ($(CONFIG_KERNEL_CC),clang) -+ BUILD_CLANG_HOST = y -+endif -+ifeq ($(CONFIG_BPF_TOOLCHAIN_HOST),y) -+ BUILD_CLANG_HOST = y -+endif - - tools-y += autoconf - tools-y += autoconf-archive -@@ -70,6 +76,7 @@ tools-y += util-linux - tools-y += xz - tools-y += zip - tools-y += zlib -+tools-$(if $(BUILD_CLANG_HOST),y) += clang - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS),y) += liblzo - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_B43_TOOLS),y) += b43-tools - tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_BZIP2_TOOLS),y) += bzip2 -diff --git a/tools/clang/Makefile b/tools/clang/Makefile -new file mode 100644 -index 0000000..2557a1d ---- /dev/null -+++ b/tools/clang/Makefile -@@ -0,0 +1,43 @@ -+# -+# Copyright (C) 2006-2017 OpenWrt.org -+# -+# This is free software, licensed under the GNU General Public License v2. -+# See /LICENSE for more information. -+# -+ -+include $(TOPDIR)/rules.mk -+ -+PKG_NAME:=clang -+PKG_VERSION:=19.0.1 -+ -+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz -+PKG_SOURCE_URL:=https://github.com/sbwml/openwrt-llvm-toolchain/releases/download/$(PKG_VERSION)/ -+PKG_HASH:=a73c5ec6d62e0f47fd3cf25e3904b5818b18695b7302a9b404e411f2085110a3 -+ -+PKG_MAINTAINER:=sbwml -+PKG_LICENSE:=Apache-2.0 -+PKG_LICENSE_FILES:=LICENSE -+ -+include $(INCLUDE_DIR)/host-build.mk -+ -+define Host/Prepare -+ $(TAR) --strip-components=1 -C $(HOST_BUILD_DIR) -xf $(DL_DIR)/$(PKG_NAME)-$(PKG_VERSION)-x86_64-unknown-linux-gnu.tar.xz -+endef -+ -+define Host/Compile -+endef -+ -+define Host/Install -+ $(CP) -a $(HOST_BUILD_DIR)/{bin,include,lib} $(STAGING_DIR_HOST)/ -+ $(RM) -rf $(HOST_BUILD_DIR)/{bin,include,lib,libexec,share} -+endef -+ -+define Host/Uninstall -+ ( \ -+ rm -rf $(STAGING_DIR_HOST)/bin/{*clang*,dsymutil,find-all-symbols,*lld*,llc,lli,llvm*,merge-fdata,opt,perf2bolt,wasm-ld} ; \ -+ rm -rf $(STAGING_DIR_HOST)/include/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,c++,clang*,i386-unknown-linux-gnu,i686-unknown-linux-musl,lld,llvm*,mach-o,polly,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ -+ rm -rf $(STAGING_DIR_HOST)/lib/{aarch64-unknown-linux-musl,arm-unknown-linux-musleabihf,bfd-plugins,clang,cmake,i386-unknown-linux-gnu,i686-unknown-linux-musl,libbolt*,libfindAllSymbols.a,liblld*,*LLVM*,libPolly*,libRemarks.so,libxml2*,x86_64-unknown-linux-gnu,x86_64-unknown-linux-musl} ; \ -+ ) -+endef -+ -+$(eval $(call HostBuild)) --- -2.43.5 - diff --git a/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch b/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch similarity index 89% rename from openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch rename to openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch index 135f86d2a..75c737245 100644 --- a/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch +++ b/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch @@ -1,7 +1,7 @@ -From a715edcd605ac305c60eace1e093abc5bf6d72c5 Mon Sep 17 00:00:00 2001 +From 64bdd05856306c921523395f6c150d796eaa0c02 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:39:25 +0800 -Subject: [PATCH 02/11] tools: add upx tools +Subject: [PATCH 01/10] tools: add upx tools Signed-off-by: sbwml --- @@ -11,10 +11,10 @@ Signed-off-by: sbwml create mode 100644 tools/upx/Makefile diff --git a/tools/Makefile b/tools/Makefile -index 7937334..0ab5956 100644 +index b16c5d9..702184a 100644 --- a/tools/Makefile +++ b/tools/Makefile -@@ -72,6 +72,7 @@ tools-y += pkgconf +@@ -66,6 +66,7 @@ tools-y += pkgconf tools-y += quilt tools-y += squashfs4 tools-y += sstrip diff --git a/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch b/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch similarity index 89% rename from openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch rename to openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch index d735e4ed7..3e874886c 100644 --- a/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch +++ b/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch @@ -1,7 +1,7 @@ -From c0843979a428633598583cd8d53a073d59a24e95 Mon Sep 17 00:00:00 2001 +From 7cd01d84de61e8642db1c4f8599630290e3997d0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:46:49 +0800 -Subject: [PATCH 03/11] rootfs: add upx compression support +Subject: [PATCH 02/10] rootfs: add upx compression support * When the upx_list.txt file exists in the source code root directory, it will be compressed by upx. diff --git a/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch b/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch similarity index 83% rename from openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch rename to openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch index 7e315f0c2..72b5d4f73 100644 --- a/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch +++ b/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch @@ -1,7 +1,7 @@ -From 1595c68c698a95ee4fceb3b4b4d22a70b73ead15 Mon Sep 17 00:00:00 2001 +From abe248ebdb46aa4635487ddf7819772cf22ca03b Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:47:41 +0800 -Subject: [PATCH 04/11] rootfs: add r/w permissions for UCI configuration files +Subject: [PATCH 03/10] rootfs: add r/w permissions for UCI configuration files Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch b/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch similarity index 92% rename from openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch rename to openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch index 39235e841..2a1ddb365 100644 --- a/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch +++ b/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch @@ -1,7 +1,7 @@ -From 38185cc7f8f6a6168fba302ba7268e7739b8c6be Mon Sep 17 00:00:00 2001 +From b6042a29a66bba6044982aab6c5f241ef45b10b4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:48:29 +0800 -Subject: [PATCH 05/11] rootfs: Add support for local kmod installation sources +Subject: [PATCH 04/10] rootfs: Add support for local kmod installation sources * CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES=y diff --git a/openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch similarity index 94% rename from openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch rename to openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch index 0fd11fad2..4acd62c52 100644 --- a/openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch +++ b/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch @@ -1,7 +1,7 @@ -From dc1e35a7a4710a328b792d7b57e9eee961687eae Mon Sep 17 00:00:00 2001 +From 9b309149f1f96a2163bba1191fcb28f23bbdf162 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:51:22 +0800 -Subject: [PATCH 06/11] kernel: Add support for llvm/clang compiler +Subject: [PATCH 05/10] kernel: Add support for llvm/clang compiler Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch similarity index 97% rename from openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch rename to openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch index df0be8928..8861d78a9 100644 --- a/openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch +++ b/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch @@ -1,7 +1,7 @@ -From 6c430896b7113c79b80106dff806fa1a196bbd57 Mon Sep 17 00:00:00 2001 +From 4142f36de61a4e5074d07e4562e9895874b88459 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:56:57 +0800 -Subject: [PATCH 07/11] build: kernel: add out-of-tree kernel config +Subject: [PATCH 06/10] build: kernel: add out-of-tree kernel config Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch similarity index 86% rename from openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch rename to openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch index d8f0bf94d..fbdec2ea2 100644 --- a/openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch +++ b/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch @@ -1,7 +1,7 @@ -From f1e4ddedeaae1b7bd8fb7e748f911c5d6b43cd92 Mon Sep 17 00:00:00 2001 +From 20ef2e23f6a2a4f4c7f6242486eca8c2b42d49c4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:29 +0800 -Subject: [PATCH 08/11] include: kernel: add miss config for linux-6.11 +Subject: [PATCH 07/10] include: kernel: add miss config for linux-6.11 Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch b/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch similarity index 89% rename from openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch rename to openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch index dfa928e0c..475b2af88 100644 --- a/openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch +++ b/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch @@ -1,7 +1,7 @@ -From 1826695bc17e5573fe137bf3576ed6a8ca49f3d4 Mon Sep 17 00:00:00 2001 +From 67ebaba62cc4036ba6d2c8f064b0f40f30acdade Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:54 +0800 -Subject: [PATCH 09/11] meson: add platform variable to cross-compilation file +Subject: [PATCH 08/10] meson: add platform variable to cross-compilation file Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch b/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch similarity index 89% rename from openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch rename to openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch index 0ef0acae3..a3679445f 100644 --- a/openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch +++ b/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch @@ -1,7 +1,7 @@ -From 1a29c74ae624f54ea9314f7ec1e629cdaa4a72e5 Mon Sep 17 00:00:00 2001 +From 8c80f36391472bb37848c1485b588dec2ab19a2c Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 21:40:05 +0800 -Subject: [PATCH 10/11] kernel: add legacy cgroup v1 memory controller +Subject: [PATCH 09/10] kernel: add legacy cgroup v1 memory controller Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch b/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch similarity index 90% rename from openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch rename to openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch index 3d73a0333..1ceff0cb8 100644 --- a/openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch +++ b/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch @@ -1,7 +1,7 @@ -From fccdd7ad134c215ddeed58239781db7666410b2a Mon Sep 17 00:00:00 2001 +From 8576944e698d42b96205e85fff003bd162c0f9c3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 12 Oct 2024 08:36:46 +0800 -Subject: [PATCH 11/11] kernel: add PREEMPT_RT support for aarch64/x86_64 +Subject: [PATCH 10/10] kernel: add PREEMPT_RT support for aarch64/x86_64 Signed-off-by: sbwml --- diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 5a5a2e511..a8e39c190 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -5,51 +5,21 @@ rm -rf package/boot/rkbin package/boot/uboot-rockchip package/boot/arm-trusted-f git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip -######## OpenWrt Patches ######## - -# source -sed -i '/@OPENWRT/a\\t\t"https://source.cooluc.com",' scripts/projectsmirrors.json - -# tools: add llvm/clang toolchain -curl -s https://$mirror/openwrt/patch/generic-24.10/0001-tools-add-llvm-clang-toolchain.patch | patch -p1 - -# tools: add upx tools -curl -s https://$mirror/openwrt/patch/generic-24.10/0002-tools-add-upx-tools.patch | patch -p1 - -# rootfs: upx compression -# include/rootfs.mk -curl -s https://$mirror/openwrt/patch/generic-24.10/0003-rootfs-add-upx-compression-support.patch | patch -p1 - -# rootfs: add r/w (0600) permissions for UCI configuration files -# include/rootfs.mk -curl -s https://$mirror/openwrt/patch/generic-24.10/0004-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 - -# rootfs: Add support for local kmod installation sources -curl -s https://$mirror/openwrt/patch/generic-24.10/0005-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 - -# kernel: Add support for llvm/clang compiler -curl -s https://$mirror/openwrt/patch/generic-24.10/0006-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 - -# build: kernel: add out-of-tree kernel config -curl -s https://$mirror/openwrt/patch/generic-24.10/0007-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 - -# kernel: linux-6.11 config -curl -s https://$mirror/openwrt/patch/generic-24.10/0008-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 - -# meson: add platform variable to cross-compilation file -curl -s https://$mirror/openwrt/patch/generic-24.10/0009-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 - -# kernel 6.12: add legacy cgroup v1 memory controller -curl -s https://$mirror/openwrt/patch/generic-24.10/0010-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 - -# kernel 6.12: add linux-rt support for aarch64/x86_64 -curl -s https://$mirror/openwrt/patch/generic-24.10/0011-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 +# patch source +curl -s https://$mirror/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 # attr no-mold [ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile -######## OpenWrt Patches End ######## - # dwarves 1.25 rm -rf tools/dwarves git clone https://$github/sbwml/tools_dwarves tools/dwarves From f20e58a3ea1a0e10628b95296067b0da9aac0272 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 19:16:19 +0800 Subject: [PATCH 122/425] kernel: clang: add ccache support Signed-off-by: sbwml --- openwrt/build.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index b4b03eb84..be831e5cd 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -311,7 +311,11 @@ export ENABLE_LTO=$ENABLE_LTO # kernel - CLANG + LTO; Allow CONFIG_KERNEL_CC=clang / clang-18 / clang-xx if [ "$KERNEL_CLANG_LTO" = "y" ]; then echo '# Kernel - CLANG LTO' >> .config - echo 'CONFIG_KERNEL_CC="clang"' >> .config + if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then + echo 'CONFIG_KERNEL_CC="ccache clang"' >> .config + else + echo 'CONFIG_KERNEL_CC="clang"' >> .config + fi echo 'CONFIG_EXTRA_OPTIMIZATION=""' >> .config echo '# CONFIG_PACKAGE_kselftests-bpf is not set' >> .config fi From 23959d0c4fe2f0aac12b0043f7cd047ac6cb5d3c Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 19:20:02 +0800 Subject: [PATCH 123/425] build.sh: fixed version date to improve kernel build cache hit rate Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index be831e5cd..eb8e677a7 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -176,7 +176,7 @@ git clone https://$github/immortalwrt/packages master/immortalwrt_packages --dep if [ -d openwrt ]; then cd openwrt - [ "$1" = "rc2" ] && echo "$CURRENT_DATE" > version.date + echo "1730409337" > version.date # OpenWrt v24.10: set branch defaults curl -Os https://$mirror/openwrt/patch/key.tar.gz && tar zxf key.tar.gz && rm -f key.tar.gz else echo -e "${RED_COLOR}Failed to download source code${RES}" From 6d703c1faf6d819c55ec689c3d3e019cf07fd664 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 8 Nov 2024 21:09:17 +0800 Subject: [PATCH 124/425] macremapper: fix build with ccache Signed-off-by: sbwml --- .../clang/macremapper/100-macremapper-fix-clang-build.patch | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch b/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch index 08de7946a..28f35166b 100644 --- a/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch +++ b/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch @@ -1,9 +1,11 @@ --- a/feeds/packages/kernel/macremapper/Makefile +++ b/feeds/packages/kernel/macremapper/Makefile -@@ -38,4 +38,13 @@ endef +@@ -38,4 +38,15 @@ endef MAKE_FLAGS += KERNEL_SRC=$(LINUX_DIR) ARCH=$(LINUX_KARCH) MAKE_PATH:=kernelmod ++KERNEL_CC:= $(filter-out ccache,$(KERNEL_CC)) ++ +ifneq (,$(findstring clang,$(KERNEL_CC))) + ifneq (,$(filter clang-%,$(KERNEL_CC))) + LLVM:=-$(subst clang-,,$(KERNEL_CC)) From 60487f3ed6c3cae635a59ae250923a55087bc1f3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 9 Nov 2024 11:44:31 +0800 Subject: [PATCH 125/425] ci: add ccache support (gcc-15) Signed-off-by: sbwml --- .github/workflows/build-release.yml | 87 ++++++++++++++++++++++++++--- README.md | 22 ++++---- openwrt/build.sh | 1 + 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 68a30d902..8da854fbd 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,15 +17,24 @@ on: version: description: 'Select the build version' required: true - default: 'snapshot' + default: 'snapshot-24.10' type: choice options: # - 'release' - - 'snapshot' + - 'snapshot-24.10' + ccache: + description: 'Enable ccache (Use Cache to speed up next build)' + type: boolean + default: false + lan_addr: + description: 'Setting default LAN address' + required: true + default: '10.0.0.1' + type: string build_options: description: 'Build options (separate multiple options with spaces)' required: false - default: 'BUILD_FAST=y ENABLE_BPF=y ENABLE_LTO=y ENABLE_LRNG=y ENABLE_MOLD=y KERNEL_CLANG_LTO=y USE_GCC14=y' + default: 'BUILD_FAST=y ENABLE_BPF=y ENABLE_LTO=y ENABLE_LRNG=y ENABLE_MOLD=y KERNEL_CLANG_LTO=y' type: string jobs: @@ -42,7 +51,7 @@ jobs: sudo timedatectl set-timezone 'Asia/Shanghai' git config --global user.name 'actions' git config --global user.email 'action@github.com' - echo WORKDIR="/builder" >> "$GITHUB_ENV" + echo build_dir="/builder" >> "$GITHUB_ENV" [ "${{ github.event.inputs.version }}" = release ] && echo build_version="rc2" >> "$GITHUB_ENV" || echo build_version="dev" >> "$GITHUB_ENV" - name: Show system @@ -70,13 +79,36 @@ jobs: - name: Install LLVM uses: sbwml/actions@install-llvm + - name: Restore Cached + if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device != 'armv8' && github.event.inputs.device != 'nanopi-r4s' }} + uses: actions/cache/restore@v4 + with: + path: /builder/.ccache + key: openwrt-24.10-${{ github.event.inputs.device }}-ccache + + - name: Restore Cached (releases) + if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device == 'armv8' || github.event.inputs.device == 'nanopi-r4s' }} + continue-on-error: true + working-directory: /builder + run: | + wget -q https://github.com/${{ github.repository }}/releases/download/ccache/${{ github.event.inputs.device }}.tar.00 || true + wget -q https://github.com/${{ github.repository }}/releases/download/ccache/${{ github.event.inputs.device }}.tar.01 || true + cat ${{ github.event.inputs.device }}.tar.* | tar -xf - || true + rm -rf ${{ github.event.inputs.device }}.tar.* || true + cache_size=$(du -sb .ccache | awk '{print $1}') + cache_size_mb=$(echo "scale=0; ${cache_size} / (1024 * 1024)" | bc) + echo "Cache Size: ~${cache_size_mb} MB (${cache_size} B)" + echo "Cache restored successfully" + echo "Cache restored from key: ${{ github.event.inputs.device }}" + - name: Compile OpenWrt working-directory: /builder id: compile continue-on-error: true run: | export GITHUB_REPO=${{ github.repository }} - export ${{ github.event.inputs.build_options }} + export ${{ github.event.inputs.build_options }} LAN=${{ github.event.inputs.lan_addr }} USE_GCC15=y + [ ${{ github.event.inputs.ccache }} = 'true' ] && export ENABLE_CCACHE=y bash <(curl -sS https://raw.githubusercontent.com/${{ github.repository }}/master/openwrt/build.sh) ${{ env.build_version }} ${{ github.event.inputs.device }} cd openwrt if [ "${{ github.event.inputs.version }}" = release ]; then @@ -93,6 +125,47 @@ jobs: cd openwrt make V=s + - name: Delete Cached + if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device != 'armv8' && github.event.inputs.device != 'nanopi-r4s' }} + continue-on-error: true + working-directory: /builder + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + run: | + gh cache delete openwrt-24.10-${{ github.event.inputs.device }}-ccache || true + + - name: Save Cached + if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device != 'armv8' && github.event.inputs.device != 'nanopi-r4s' }} + continue-on-error: true + uses: actions/cache/save@v4 + with: + path: /builder/.ccache + key: openwrt-24.10-${{ github.event.inputs.device }}-ccache + + - name: Create ccache tar files + if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device == 'armv8' || github.event.inputs.device == 'nanopi-r4s' }} + continue-on-error: true + working-directory: /builder + run: | + mkdir -p ccache + tar cf - .ccache | split -d -b 1800m - ccache/${{ github.event.inputs.device }}.tar. + + - name: Upload Cached (releases - ccache) + if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device == 'armv8' || github.event.inputs.device == 'nanopi-r4s' }} + continue-on-error: true + uses: ncipollo/release-action@v1.14.0 + with: + name: ccache + allowUpdates: true + tag: ccache + commit: master + replacesArtifacts: true + prerelease: true + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: | + ${{ env.build_dir }}/ccache/* + - name: Prepare Firmware Files working-directory: /builder run: | @@ -130,7 +203,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: ${{ github.event.inputs.device }}-openwrt-${{ env.latest_release }} - path: ${{ env.WORKDIR }}/rom/* + path: ${{ env.build_dir }}/rom/* - name: Create release continue-on-error: true @@ -142,4 +215,4 @@ jobs: commit: master replacesArtifacts: true token: ${{ secrets.GITHUB_TOKEN }} - artifacts: ${{ env.WORKDIR }}/rom/* + artifacts: ${{ env.build_dir }}/rom/* diff --git a/README.md b/README.md index 54358c295..4ed6c10a6 100644 --- a/README.md +++ b/README.md @@ -147,23 +147,23 @@ export NO_KMOD=y --------------- -## 构建 OpenWrt 23.05 最新 Releases +## 构建 OpenWrt 24.10 最新 Releases ### nanopi-r4s ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r4s ``` ### nanopi-r5s/r5c ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r5s ``` ### x86_64 ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 x86_64 ``` @@ -212,21 +212,21 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 ### 三、在本地 Linux 执行基于你自己仓库的构建脚本,即可编译所需固件 -#### nanopi-r4s openwrt-23.05 +#### nanopi-r4s openwrt-24.10 ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/master/openwrt/build.sh) rc2 nanopi-r4s ``` -#### nanopi-r5s/r5c openwrt-23.05 +#### nanopi-r5s/r5c openwrt-24.10 ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/master/openwrt/build.sh) rc2 nanopi-r5s ``` -#### x86_64 openwrt-23.05 +#### x86_64 openwrt-24.10 ```shell -# linux-6.6 +# linux-6.12 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/master/openwrt/build.sh) rc2 x86_64 ``` @@ -244,4 +244,4 @@ bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_scri - 在工作流运行的列表上方,单击“**Run workflow**”按钮,选择要构建的设备固件并运行工作流。 - ![image](https://github.com/user-attachments/assets/0c2eb064-a130-47b3-a5a3-1e9a9bb6f50d) + ![image](https://github.com/user-attachments/assets/3eae2e9f-efe6-48ad-8e9d-39c176fcd71c) diff --git a/openwrt/build.sh b/openwrt/build.sh index eb8e677a7..d309336cc 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -160,6 +160,7 @@ echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" [ "$ENABLE_LRNG" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_LRNG: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_LRNG:${RES} ${RED_COLOR}false${RES}" [ "$ENABLE_LOCAL_KMOD" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_LOCAL_KMOD: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_LOCAL_KMOD: false${RES}" [ "$BUILD_FAST" = "y" ] && echo -e "${GREEN_COLOR}BUILD_FAST: true${RES}" || echo -e "${GREEN_COLOR}BUILD_FAST:${RES} ${YELLOW_COLOR}false${RES}" +[ "$ENABLE_CCACHE" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_CCACHE: true${RES}" || echo -e "${YELLOW_COLOR}ENABLE_CCACHE:${RES} ${YELLOW_COLOR}false${RES}" [ "$MINIMAL_BUILD" = "y" ] && echo -e "${GREEN_COLOR}MINIMAL_BUILD: true${RES}" || echo -e "${GREEN_COLOR}MINIMAL_BUILD: false${RES}" [ "$KERNEL_CLANG_LTO" = "y" ] && echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO: true${RES}\r\n" || echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO:${RES} ${YELLOW_COLOR}false${RES}\r\n" From 03212e7e658f1f10bccc7eda1823b6392aaf55d7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 9 Nov 2024 14:44:35 +0800 Subject: [PATCH 126/425] ci: fix netgear_r8500 release Signed-off-by: sbwml --- .github/workflows/build-release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 8da854fbd..b378e881c 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -187,6 +187,11 @@ jobs: cp -a openwrt/bin/targets/x86/*/*-x86-64-generic.manifest info/manifest.txt cp -a openwrt/bin/targets/x86/*/config.buildinfo info/config.buildinfo cd rom && sha256sum *gz > ../info/sha256sums.txt + elif [ "${{ github.event.inputs.device }}" = "netgear_r8500" ]; then + cp -a openwrt/bin/targets/bcm53xx/generic/*-bcm53xx-generic-netgear_r8500-squashfs.chk rom/ + cp -a openwrt/bin/targets/bcm53xx/generic/*.manifest info/manifest.txt + cp -a openwrt/bin/targets/bcm53xx/generic/config.buildinfo info/config.buildinfo + cd rom && sha256sum * > ../info/sha256sums.txt elif [ "${{ github.event.inputs.device }}" = "armv8" ]; then tar zcf rom/u-boot-qemu_armv8.tar.gz -C openwrt/bin/targets/armsr/armv8*/ ./u-boot-qemu_armv8 cp -a openwrt/bin/targets/armsr/armv8*/*-generic-initramfs-kernel.bin rom/ From 53af5cb1bb36532a822193d3677b202910e03669 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 9 Nov 2024 21:10:27 +0800 Subject: [PATCH 127/425] build.sh: fix error output Signed-off-by: sbwml --- openwrt/build.sh | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index d309336cc..e2e7df6bf 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -426,8 +426,10 @@ if [ "$platform" = "x86_64" ]; then # driver firmware cp -a bin/packages/x86_64/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/x86_64/base/*natflow*.ipk $kmodpkg_name/ - cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true - cp -a bin/packages/x86_64/base/*numa*.ipk $kmodpkg_name/ || true + [ "$ENABLE_DPDK" = "y" ] && { + cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/*numa*.ipk $kmodpkg_name/ || true + } bash kmod-sign $kmodpkg_name tar zcf x86_64-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -467,8 +469,10 @@ elif [ "$platform" = "armv8" ]; then # driver firmware cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true - cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true + [ "$ENABLE_DPDK" = "y" ] && { + cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true + } bash kmod-sign $kmodpkg_name tar zcf armv8-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -532,8 +536,10 @@ else # driver firmware cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true - cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true + [ "$ENABLE_DPDK" = "y" ] && { + cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true + } bash kmod-sign $kmodpkg_name tar zcf aarch64-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name From 4ec7d90f6880900c3f5d5c4ad7d41a5e4a8d1800 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 10 Nov 2024 02:24:24 +0800 Subject: [PATCH 128/425] kernel: clang: build with ThinLTO Signed-off-by: sbwml --- .../0006-build-kernel-add-out-of-tree-kernel-config.patch | 4 ++-- .../openwrt}/linux-6.12-target-linux-generic.patch | 0 openwrt/scripts/01-prepare_base-mainline.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename openwrt/patch/{generic-24.10/kernel => kernel-6.12/openwrt}/linux-6.12-target-linux-generic.patch (100%) diff --git a/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch index 8861d78a9..b0a941f2b 100644 --- a/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch +++ b/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch @@ -41,11 +41,11 @@ index f94ed33..8e9ed74 100644 +ifneq (,$(findstring clang,$(KERNEL_CC))) + echo 'CONFIG_LTO=y' >> $(LINUX_DIR)/.config.set + echo 'CONFIG_LTO_CLANG=y' >> $(LINUX_DIR)/.config.set -+ echo 'CONFIG_LTO_CLANG_FULL=y' >> $(LINUX_DIR)/.config.set ++ echo 'CONFIG_LTO_CLANG_THIN=y' >> $(LINUX_DIR)/.config.set + echo 'CONFIG_HAS_LTO_CLANG=y' >> $(LINUX_DIR)/.config.set + echo 'CONFIG_RANDSTRUCT_NONE=y' >> $(LINUX_DIR)/.config.set + echo '# CONFIG_CFI_CLANG is not set' >> $(LINUX_DIR)/.config.set -+ echo '# CONFIG_LTO_CLANG_THIN is not set' >> $(LINUX_DIR)/.config.set ++ echo '# CONFIG_LTO_CLANG_FULL is not set' >> $(LINUX_DIR)/.config.set + echo '# CONFIG_LTO_NONE is not set' >> $(LINUX_DIR)/.config.set + echo '# CONFIG_RANDSTRUCT_FULL is not set' >> $(LINUX_DIR)/.config.set + echo '# CONFIG_RELR is not set' >> $(LINUX_DIR)/.config.set diff --git a/openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch b/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch similarity index 100% rename from openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch rename to openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 7a58276cb..b195db56b 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -39,7 +39,7 @@ sed -ie 's/^\(.\).*vermagic$/\1cp $(TOPDIR)\/.vermagic $(LINUX_DIR)\/.vermagic/' grep HASH include/kernel-6.12 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic # kernel generic patches -curl -s https://$mirror/openwrt/patch/generic-24.10/kernel/linux-6.12-target-linux-generic.patch | patch -p1 +curl -s https://$mirror/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch | patch -p1 local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-6.12) release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-6.12 | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then From 95012741036be1b169f62df43509fadaf2705769 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 10 Nov 2024 16:14:08 +0800 Subject: [PATCH 129/425] ci: download all tar multi-volume of ccache Signed-off-by: sbwml --- .github/workflows/build-release.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index b378e881c..53f8694e9 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -91,11 +91,10 @@ jobs: continue-on-error: true working-directory: /builder run: | - wget -q https://github.com/${{ github.repository }}/releases/download/ccache/${{ github.event.inputs.device }}.tar.00 || true - wget -q https://github.com/${{ github.repository }}/releases/download/ccache/${{ github.event.inputs.device }}.tar.01 || true + curl -s https://api.github.com/repos/${{ github.repository }}/releases | grep 'browser_download_url' | grep ccache | grep ${{ github.event.inputs.device }} | awk -F '"' '{print $4}' | grep -v '^$' | xargs -n 1 wget -q cat ${{ github.event.inputs.device }}.tar.* | tar -xf - || true rm -rf ${{ github.event.inputs.device }}.tar.* || true - cache_size=$(du -sb .ccache | awk '{print $1}') + [ -d .ccache ] && cache_size=$(du -sb .ccache | awk '{print $1}') || cache_size=0 cache_size_mb=$(echo "scale=0; ${cache_size} / (1024 * 1024)" | bc) echo "Cache Size: ~${cache_size_mb} MB (${cache_size} B)" echo "Cache restored successfully" From 7822a97359ea30371a79f688e8850c2a2cf3ec5b Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 11 Nov 2024 23:49:55 +0800 Subject: [PATCH 130/425] linux-6.12: bump to 6.12-rc7 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index dbc9b8f15..88675b756 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -rc6 -LINUX_KERNEL_HASH-6.12-rc6 = 7932703bbf3859932f615c21de4c5ae56d99dc85525bc2361d543216cff7e4ca +LINUX_VERSION-6.12 = -rc7 +LINUX_KERNEL_HASH-6.12-rc7 = 8581f2f35bf1fbed271add5af73cfd88c299a2b3be4668110116987443caa361 From ba73cdc14711329b3612e708757a1592a3a5a92f Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 12 Nov 2024 21:20:10 +0800 Subject: [PATCH 131/425] default-settings: update for openwrt-24.10 (linux-6.12) Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 635037800..64a4950ee 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -9,7 +9,7 @@ rm -rf feeds/packages/lang/node git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages/lang/node -b packages-24.10 # default settings -git clone https://$github/sbwml/default-settings package/new/default-settings +git clone https://$github/sbwml/default-settings package/new/default-settings -b openwrt-24.10 # luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager From 8d6f4a1d103ba94e0b4287b6a5f76ca9e7683b5f Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 17 Nov 2024 19:28:27 +0800 Subject: [PATCH 132/425] libnftnl: delete obsolete makefile Signed-off-by: sbwml --- openwrt/patch/firewall4/libnftnl/Makefile | 75 ----------------------- openwrt/scripts/00-prepare_base.sh | 2 - 2 files changed, 77 deletions(-) delete mode 100644 openwrt/patch/firewall4/libnftnl/Makefile diff --git a/openwrt/patch/firewall4/libnftnl/Makefile b/openwrt/patch/firewall4/libnftnl/Makefile deleted file mode 100644 index f06b22399..000000000 --- a/openwrt/patch/firewall4/libnftnl/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# -# Copyright (C) 2014 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=libnftnl -PKG_CPE_ID:=cpe:/a:netfilter:libnftnl -PKG_VERSION:=1.2.8 -PKG_RELEASE:=1 - -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz -PKG_SOURCE_URL:=https://netfilter.org/projects/$(PKG_NAME)/files -PKG_HASH:=37fea5d6b5c9b08de7920d298de3cdc942e7ae64b1a3e8b880b2d390ae67ad95 - -PKG_MAINTAINER:=Steven Barth -PKG_LICENSE:=GPL-2.0-or-later -PKG_LICENSE_FILES:=COPYING - -PKG_INSTALL:=1 -PKG_BUILD_PARALLEL:=1 -PKG_BUILD_FLAGS:=lto - -include $(INCLUDE_DIR)/package.mk - -DISABLE_NLS:= - -define Package/libnftnl - SECTION:=libs - CATEGORY:=Libraries - DEPENDS:=+libmnl - TITLE:=Low-level netlink library for the nf_tables subsystem - URL:=http://www.netfilter.org/projects/libnftnl - ABI_VERSION:=11 -endef - -define Package/libnftnl/description - libnftnl is a userspace library providing a low-level netlink - programming interface (API) to the in-kernel nf_tables subsystem. -endef - -TARGET_CFLAGS += $(FPIC) - -CONFIGURE_ARGS += \ - --enable-static \ - --enable-shared - -define Build/InstallDev - $(INSTALL_DIR) $(1)/usr/include/libnftnl - $(CP) \ - $(PKG_INSTALL_DIR)/usr/include/libnftnl/*.h \ - $(1)/usr/include/libnftnl/ - - $(INSTALL_DIR) $(1)/usr/lib - $(CP) \ - $(PKG_INSTALL_DIR)/usr/lib/libnftnl.{so*,a,la} \ - $(1)/usr/lib/ - - $(INSTALL_DIR) $(1)/usr/lib/pkgconfig - $(CP) \ - $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnftnl.pc \ - $(1)/usr/lib/pkgconfig/ -endef - -define Package/libnftnl/install - $(INSTALL_DIR) $(1)/usr/lib - $(CP) \ - $(PKG_INSTALL_DIR)/usr/lib/libnftnl.so.* \ - $(1)/usr/lib/ -endef - -$(eval $(call BuildPackage,libnftnl)) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index a8e39c190..5f9855db7 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -120,9 +120,7 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then # add custom nft command support curl -s https://$mirror/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch | patch -p1 # libnftnl - rm -rf package/libs/libnftnl mkdir -p package/libs/libnftnl/patches - curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/Makefile > package/libs/libnftnl/Makefile curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/0001-libnftnl-add-fullcone-expression-support.patch curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/0002-libnftnl-add-brcm-fullcone-support.patch # nftables From 234b394cd83cbe6809c7579475a06c4af346ac03 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 17 Nov 2024 21:28:36 +0800 Subject: [PATCH 133/425] nftables: delete obsolete makefile Signed-off-by: sbwml --- .../nftables/0003-drop-rej-file.patch | 29 +++++++ openwrt/patch/firewall4/nftables/Makefile | 85 ------------------- openwrt/scripts/00-prepare_base.sh | 3 +- 3 files changed, 30 insertions(+), 87 deletions(-) create mode 100644 openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch delete mode 100644 openwrt/patch/firewall4/nftables/Makefile diff --git a/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch b/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch new file mode 100644 index 000000000..d9eba3069 --- /dev/null +++ b/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch @@ -0,0 +1,29 @@ +From ffe0a07aaf5534cf1047238f52d7cda346444046 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 17 Nov 2024 21:19:18 +0800 +Subject: [PATCH 3/3] drop rej file + +Signed-off-by: sbwml +--- + tests/shell/run-tests.sh.rej | 15 --------------- + 1 file changed, 15 deletions(-) + delete mode 100644 tests/shell/run-tests.sh.rej + +--- 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/openwrt/patch/firewall4/nftables/Makefile b/openwrt/patch/firewall4/nftables/Makefile deleted file mode 100644 index f8159155c..000000000 --- a/openwrt/patch/firewall4/nftables/Makefile +++ /dev/null @@ -1,85 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Copyright (C) 2015 OpenWrt.org -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=nftables -PKG_VERSION:=1.1.1 -PKG_RELEASE:=1 - -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz -PKG_SOURCE_URL:=https://github.com/sbwml/nftables/releases/download/v$(PKG_VERSION)/ -PKG_HASH:=d702a729cf1069622187d8921ad8ed74898677fffb003059368112db5dc984c1 - -PKG_MAINTAINER:= -PKG_LICENSE:=GPL-2.0 -PKG_LICENSE_FILES:=COPYING - -PKG_FIXUP:=autoreconf -PKG_INSTALL:=1 - -PKG_BUILD_FLAGS:=lto - -include $(INCLUDE_DIR)/package.mk - -DISABLE_NLS:= - -CONFIGURE_ARGS += \ - --disable-debug \ - --disable-man-doc \ - --with-mini-gmp \ - --without-cli \ - --disable-python - -define Package/nftables/Default - SECTION:=net - CATEGORY:=Network - SUBMENU:=Firewall - TITLE:=nftables userspace utility - DEPENDS:=+kmod-nft-core +libnftnl - URL:=http://netfilter.org/projects/nftables/ - PROVIDES:=nftables -endef - -define Package/nftables-nojson - $(Package/nftables/Default) - TITLE+= no JSON support - VARIANT:=nojson - DEFAULT_VARIANT:=1 - CONFLICTS:=nftables-json -endef - -define Package/nftables-json - $(Package/nftables/Default) - TITLE+= with JSON support - VARIANT:=json - DEPENDS+=+jansson -endef - -ifeq ($(BUILD_VARIANT),json) - CONFIGURE_ARGS += --with-json -endif - -define Build/InstallDev - $(INSTALL_DIR) $(1)/usr/lib $(1)/usr/include - $(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/ - $(CP) $(PKG_INSTALL_DIR)/usr/include/nftables $(1)/usr/include/ - $(INSTALL_DIR) $(1)/usr/lib/pkgconfig - $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnftables.pc \ - $(1)/usr/lib/pkgconfig/ -endef - -define Package/nftables/install/Default - $(INSTALL_DIR) $(1)/usr/sbin - $(CP) $(PKG_INSTALL_DIR)/usr/sbin/nft $(1)/usr/sbin/ - $(INSTALL_DIR) $(1)/usr/lib - $(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/ -endef - -Package/nftables-nojson/install = $(Package/nftables/install/Default) -Package/nftables-json/install = $(Package/nftables/install/Default) - -$(eval $(call BuildPackage,nftables-nojson)) -$(eval $(call BuildPackage,nftables-json)) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 5f9855db7..70965ba0b 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -124,11 +124,10 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/0001-libnftnl-add-fullcone-expression-support.patch curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/0002-libnftnl-add-brcm-fullcone-support.patch # nftables - rm -rf package/network/utils/nftables mkdir -p package/network/utils/nftables/patches - curl -s https://$mirror/openwrt/patch/firewall4/nftables/Makefile > package/network/utils/nftables/Makefile curl -s https://$mirror/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/0001-nftables-add-fullcone-expression-support.patch curl -s https://$mirror/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/0002-nftables-add-brcm-fullconenat-support.patch + curl -s https://$mirror/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch > package/network/utils/nftables/patches/0003-drop-rej-file.patch fi # FullCone module From 65dc3a3e512a7f547add7c8d49e6b53ece38b5a5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 17 Nov 2024 22:13:35 +0800 Subject: [PATCH 134/425] mt76: update from openwrt upstream Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 768 ------------------ openwrt/patch/mt76/README.md | 1 + ...ix-build-with-mac80211-6.11-backport.patch | 2 +- openwrt/scripts/01-prepare_base-mainline.sh | 2 - 4 files changed, 2 insertions(+), 771 deletions(-) delete mode 100644 openwrt/patch/mt76/Makefile create mode 100644 openwrt/patch/mt76/README.md diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile deleted file mode 100644 index 7023d0047..000000000 --- a/openwrt/patch/mt76/Makefile +++ /dev/null @@ -1,768 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=mt76 -PKG_RELEASE=1 - -PKG_LICENSE:=GPLv2 -PKG_LICENSE_FILES:= - -PKG_SOURCE_URL:=https://github.com/openwrt/mt76 -PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2024-10-11 -PKG_SOURCE_VERSION:=ecca0e77b4bce629ec1f79d83bbd14a68f919188 -PKG_MIRROR_HASH:=a8852a446d4fbd7e022c669a3c574c8ba0cc1dcdc987c9d7d5a148113a71d842 - -PKG_MAINTAINER:=Felix Fietkau -PKG_USE_NINJA:=0 -PKG_BUILD_PARALLEL:=1 - -PKG_CONFIG_DEPENDS += \ - CONFIG_PACKAGE_kmod-mt76-usb \ - CONFIG_PACKAGE_kmod-mt76x02-common \ - CONFIG_PACKAGE_kmod-mt76x0-common \ - CONFIG_PACKAGE_kmod-mt76x0u \ - CONFIG_PACKAGE_kmod-mt76x2-common \ - CONFIG_PACKAGE_kmod-mt76x2 \ - CONFIG_PACKAGE_kmod-mt76x2u \ - CONFIG_PACKAGE_kmod-mt7603 \ - CONFIG_PACKAGE_CFG80211_TESTMODE - -STAMP_CONFIGURED_DEPENDS := $(STAGING_DIR)/usr/include/mac80211-backport/backport/autoconf.h - -include $(INCLUDE_DIR)/kernel.mk -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/cmake.mk - -CMAKE_SOURCE_DIR:=$(PKG_BUILD_DIR)/tools -CMAKE_BINARY_DIR:=$(PKG_BUILD_DIR)/tools - -define KernelPackage/mt76-default - SUBMENU:=Wireless Drivers - DEPENDS:= \ - +kmod-mac80211 \ - +@DRIVER_11AC_SUPPORT \ - +@KERNEL_PAGE_POOL -endef - -define KernelPackage/mt76 - SUBMENU:=Wireless Drivers - TITLE:=MediaTek MT76x2/MT7603 wireless driver (metapackage) - DEPENDS:= \ - +kmod-mt76-core +kmod-mt76x2 +kmod-mt7603 -endef - -define KernelPackage/mt76-core - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76xx wireless driver - HIDDEN:=1 - FILES:=\ - $(PKG_BUILD_DIR)/mt76.ko -endef - -define KernelPackage/mt76-usb - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76xx wireless driver USB support - DEPENDS += +kmod-usb-core +kmod-mt76-core - HIDDEN:=1 - FILES:=\ - $(PKG_BUILD_DIR)/mt76-usb.ko -endef - -define KernelPackage/mt76x02-usb - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x0/MT76x2 USB wireless driver common code - DEPENDS+=+kmod-mt76-usb +kmod-mt76x02-common - HIDDEN:=1 - FILES:=$(PKG_BUILD_DIR)/mt76x02-usb.ko -endef - -define KernelPackage/mt76x02-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x0/MT76x2 wireless driver common code - DEPENDS+=+kmod-mt76-core - HIDDEN:=1 - FILES:=$(PKG_BUILD_DIR)/mt76x02-lib.ko -endef - -define KernelPackage/mt76x0-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x0 wireless driver common code - DEPENDS+=+kmod-mt76x02-common - HIDDEN:=1 - FILES:=$(PKG_BUILD_DIR)/mt76x0/mt76x0-common.ko -endef - -define KernelPackage/mt76x0e - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x0E wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76x0-common - FILES:=\ - $(PKG_BUILD_DIR)/mt76x0/mt76x0e.ko - AUTOLOAD:=$(call AutoProbe,mt76x0e) -endef - -define KernelPackage/mt76x0u - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x0U wireless driver - DEPENDS+=+kmod-mt76x0-common +kmod-mt76x02-usb - FILES:=\ - $(PKG_BUILD_DIR)/mt76x0/mt76x0u.ko - AUTOLOAD:=$(call AutoProbe,mt76x0u) -endef - -define KernelPackage/mt76x2-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x2 wireless driver common code - DEPENDS+=+kmod-mt76-core +kmod-mt76x02-common - HIDDEN:=1 - FILES:=$(PKG_BUILD_DIR)/mt76x2/mt76x2-common.ko -endef - -define KernelPackage/mt76x2u - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x2U wireless driver - DEPENDS+=+kmod-mt76x2-common +kmod-mt76x02-usb - FILES:=\ - $(PKG_BUILD_DIR)/mt76x2/mt76x2u.ko - AUTOLOAD:=$(call AutoProbe,mt76x2u) -endef - -define KernelPackage/mt76x2 - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT76x2 wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76x2-common - FILES:=\ - $(PKG_BUILD_DIR)/mt76x2/mt76x2e.ko - AUTOLOAD:=$(call AutoProbe,mt76x2e) -endef - -define KernelPackage/mt7603 - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7603 wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76-core - FILES:=\ - $(PKG_BUILD_DIR)/mt7603/mt7603e.ko - AUTOLOAD:=$(call AutoProbe,mt7603e) -endef - -define KernelPackage/mt76-connac - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7615/MT79xx wireless driver common code - HIDDEN:=1 - DEPENDS+=+kmod-mt76-core - FILES:= $(PKG_BUILD_DIR)/mt76-connac-lib.ko -endef - -define KernelPackage/mt76-sdio - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7615/MT79xx SDIO driver common code - HIDDEN:=1 - DEPENDS+=+kmod-mt76-core +kmod-mmc - FILES:= $(PKG_BUILD_DIR)/mt76-sdio.ko -endef - -define KernelPackage/mt7615-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7615 wireless driver common code - HIDDEN:=1 - DEPENDS+=@PCI_SUPPORT +kmod-mt76-core +kmod-mt76-connac +kmod-hwmon-core - FILES:= $(PKG_BUILD_DIR)/mt7615/mt7615-common.ko -endef - -define KernelPackage/mt7615-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7615e firmware - DEPENDS+=+kmod-mt7615e -endef - -define KernelPackage/mt7615e - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7615e wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt7615-common - FILES:= $(PKG_BUILD_DIR)/mt7615/mt7615e.ko - AUTOLOAD:=$(call AutoProbe,mt7615e) -endef - -define KernelPackage/mt7622-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7622 firmware - DEPENDS+=+kmod-mt7615e -endef - -define KernelPackage/mt7663-firmware-ap - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7663e firmware (optimized for AP) -endef - -define KernelPackage/mt7663-firmware-sta - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7663e firmware (client mode offload) -endef - -define KernelPackage/mt7663-usb-sdio - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7663 USB/SDIO shared code - DEPENDS+=+kmod-mt7615-common - HIDDEN:=1 - FILES:= \ - $(PKG_BUILD_DIR)/mt7615/mt7663-usb-sdio-common.ko -endef - -define KernelPackage/mt7663s - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7663s wireless driver - DEPENDS+=+kmod-mt76-sdio +kmod-mt7615-common +kmod-mt7663-usb-sdio - FILES:= \ - $(PKG_BUILD_DIR)/mt7615/mt7663s.ko - AUTOLOAD:=$(call AutoProbe,mt7663s) -endef - -define KernelPackage/mt7663u - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7663u wireless driver - DEPENDS+=+kmod-mt76-usb +kmod-mt7615-common +kmod-mt7663-usb-sdio - FILES:= $(PKG_BUILD_DIR)/mt7615/mt7663u.ko - AUTOLOAD:=$(call AutoProbe,mt7663u) -endef - -define KernelPackage/mt7915-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7915 firmware - DEPENDS+=+kmod-mt7915e -endef - -define KernelPackage/mt7915e - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7915e wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core +kmod-thermal +@DRIVER_11AX_SUPPORT +@KERNEL_RELAY - FILES:= $(PKG_BUILD_DIR)/mt7915/mt7915e.ko - AUTOLOAD:=$(call AutoProbe,mt7915e) -endef - -define KernelPackage/mt7916-firmware - $(KernelPackage/mt76-default) - DEPENDS+=+kmod-mt7915e - TITLE:=MediaTek MT7916 firmware -endef - -define KernelPackage/mt7981-firmware - $(KernelPackage/mt76-default) - DEPENDS:=@TARGET_mediatek_filogic - TITLE:=MediaTek MT7981 firmware -endef - -define KernelPackage/mt7986-firmware - $(KernelPackage/mt76-default) - DEPENDS:=@TARGET_mediatek_filogic - TITLE:=MediaTek MT7986 firmware -endef - -define KernelPackage/mt7921-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7921 firmware -endef - -define KernelPackage/mt7922-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7922 firmware -endef - -define KernelPackage/mt792x-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT792x wireless driver common code - HIDDEN:=1 - DEPENDS+=+kmod-mt76-connac +@DRIVER_11AX_SUPPORT - FILES:= $(PKG_BUILD_DIR)/mt792x-lib.ko -endef - -define KernelPackage/mt792x-usb - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT792x wireless driver USB code - HIDDEN:=1 - DEPENDS+=+kmod-mt792x-common +kmod-mt76-usb +@DRIVER_11AX_SUPPORT - FILES:= $(PKG_BUILD_DIR)/mt792x-usb.ko -endef - -define KernelPackage/mt7921-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7921 wireless driver common code - HIDDEN:=1 - DEPENDS+=+kmod-mt792x-common +kmod-mt7921-firmware +@DRIVER_11AX_SUPPORT +kmod-hwmon-core - FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921-common.ko -endef - -define KernelPackage/mt7921u - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7921U wireless driver - DEPENDS+=+kmod-mt792x-usb +kmod-mt7921-common - FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921u.ko - AUTOLOAD:=$(call AutoProbe,mt7921u) -endef - -define KernelPackage/mt7921s - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7921S wireless driver - DEPENDS+=+kmod-mt76-sdio +kmod-mt7921-common - FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921s.ko - AUTOLOAD:=$(call AutoProbe,mt7921s) -endef - -define KernelPackage/mt7921e - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7921e wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt7921-common - FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921e.ko - AUTOLOAD:=$(call AutoProbe,mt7921e) -endef - -define KernelPackage/mt7996e - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7996E wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core +@DRIVER_11AX_SUPPORT \ - +@KERNEL_RELAY +@DRIVER_11BE_SUPPORT - FILES:= $(PKG_BUILD_DIR)/mt7996/mt7996e.ko - AUTOLOAD:=$(call AutoProbe,mt7996e) -endef - -define KernelPackage/mt7992-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7992 firmware - DEPENDS+=+kmod-mt7996e -endef - -define KernelPackage/mt7992-23-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7996 firmware (2+3 antenna variant) - DEPENDS+=+kmod-mt7996e -endef - -define KernelPackage/mt7996-firmware-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7996 firmware (common files) - HIDDEN:=1 -endef - -define KernelPackage/mt7996-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7996 firmware - DEPENDS+=+kmod-mt7996e +kmod-mt7996-firmware-common -endef - -define KernelPackage/mt7996-233-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7996 firmware (2+3+3 antenna variant) - DEPENDS+=+kmod-mt7996e +kmod-mt7996-firmware-common -endef - -define KernelPackage/mt7925-firmware - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7925 firmware - DEPENDS+=+kmod-mt7925e -endef - -define KernelPackage/mt7925-common - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7925 wireless driver common code - HIDDEN:=1 - DEPENDS+=+kmod-mt792x-common +@DRIVER_11AX_SUPPORT +kmod-hwmon-core +@DRIVER_11BE_SUPPORT - FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925-common.ko -endef - -define KernelPackage/mt7925u - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7925U wireless driver - DEPENDS+=+kmod-mt792x-usb +kmod-mt7925-common - FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925u.ko - AUTOLOAD:=$(call AutoProbe,mt7925u) -endef - -define KernelPackage/mt7925e - $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7925e wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt7925-common - FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925e.ko - AUTOLOAD:=$(call AutoProbe,mt7925e) -endef - -define Package/mt76-test - SECTION:=devel - CATEGORY:=Development - TITLE:=mt76 testmode CLI - DEPENDS:=kmod-mt76-core +libnl-tiny -endef - -TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny - -NOSTDINC_FLAGS := \ - $(KERNEL_NOSTDINC_FLAGS) \ - -I$(PKG_BUILD_DIR) \ - -I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \ - -I$(STAGING_DIR)/usr/include/mac80211-backport \ - -I$(STAGING_DIR)/usr/include/mac80211/uapi \ - -I$(STAGING_DIR)/usr/include/mac80211 \ - -include backport/autoconf.h \ - -include backport/backport.h - -ifdef CONFIG_PACKAGE_MAC80211_MESH - NOSTDINC_FLAGS += -DCONFIG_MAC80211_MESH -endif - -ifdef CONFIG_PACKAGE_CFG80211_TESTMODE - NOSTDINC_FLAGS += -DCONFIG_NL80211_TESTMODE - PKG_MAKE_FLAGS += CONFIG_NL80211_TESTMODE=y -endif - -ifdef CONFIG_PACKAGE_kmod-mt76-usb - PKG_MAKE_FLAGS += CONFIG_MT76_USB=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x02-common - PKG_MAKE_FLAGS += CONFIG_MT76x02_LIB=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x02-usb - PKG_MAKE_FLAGS += CONFIG_MT76x02_USB=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x0-common - PKG_MAKE_FLAGS += CONFIG_MT76x0_COMMON=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x0e - PKG_MAKE_FLAGS += CONFIG_MT76x0E=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x0u - PKG_MAKE_FLAGS += CONFIG_MT76x0U=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x2-common - PKG_MAKE_FLAGS += CONFIG_MT76x2_COMMON=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x2 - PKG_MAKE_FLAGS += CONFIG_MT76x2E=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76x2u - PKG_MAKE_FLAGS += CONFIG_MT76x2U=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7603 - PKG_MAKE_FLAGS += CONFIG_MT7603E=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76-connac - PKG_MAKE_FLAGS += CONFIG_MT76_CONNAC_LIB=m -endif -ifdef CONFIG_PACKAGE_kmod-mt76-sdio - PKG_MAKE_FLAGS += CONFIG_MT76_SDIO=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7615-common - PKG_MAKE_FLAGS += CONFIG_MT7615_COMMON=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7615e - PKG_MAKE_FLAGS += CONFIG_MT7615E=m - ifdef CONFIG_TARGET_mediatek_mt7622 - PKG_MAKE_FLAGS += CONFIG_MT7622_WMAC=y - NOSTDINC_FLAGS += -DCONFIG_MT7622_WMAC - endif -endif -ifdef CONFIG_PACKAGE_kmod-mt7663-usb-sdio - PKG_MAKE_FLAGS += CONFIG_MT7663_USB_SDIO_COMMON=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7663s - PKG_MAKE_FLAGS += CONFIG_MT7663S=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7663u - PKG_MAKE_FLAGS += CONFIG_MT7663U=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7915e - PKG_MAKE_FLAGS += CONFIG_MT7915E=m - ifdef CONFIG_TARGET_mediatek_filogic - PKG_MAKE_FLAGS += CONFIG_MT798X_WMAC=y - NOSTDINC_FLAGS += -DCONFIG_MT798X_WMAC - endif -endif -ifdef CONFIG_PACKAGE_kmod-mt792x-common - PKG_MAKE_FLAGS += CONFIG_MT792x_LIB=m -endif -ifdef CONFIG_PACKAGE_kmod-mt792x-usb - PKG_MAKE_FLAGS += CONFIG_MT792x_USB=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7921-common - PKG_MAKE_FLAGS += CONFIG_MT7921_COMMON=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7921u - PKG_MAKE_FLAGS += CONFIG_MT7921U=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7921s - PKG_MAKE_FLAGS += CONFIG_MT7921S=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7921e - PKG_MAKE_FLAGS += CONFIG_MT7921E=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7996e - PKG_MAKE_FLAGS += CONFIG_MT7996E=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7925-common - PKG_MAKE_FLAGS += CONFIG_MT7925_COMMON=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7925u - PKG_MAKE_FLAGS += CONFIG_MT7925U=m -endif -ifdef CONFIG_PACKAGE_kmod-mt7925e - PKG_MAKE_FLAGS += CONFIG_MT7925E=m -endif - -define Build/Compile - +$(KERNEL_MAKE) $(PKG_JOBS) \ - $(PKG_MAKE_FLAGS) \ - M="$(PKG_BUILD_DIR)" \ - NOSTDINC_FLAGS="$(NOSTDINC_FLAGS)" \ - modules - $(MAKE) -C $(PKG_BUILD_DIR)/tools -endef - -define Build/Install - : -endef - -define Package/kmod-mt76/install - true -endef - -define KernelPackage/mt76x0-common/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7610e.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt76x2-common/install - $(INSTALL_DIR) $(1)/lib/firmware - cp \ - $(PKG_BUILD_DIR)/firmware/mt7662_rom_patch.bin \ - $(PKG_BUILD_DIR)/firmware/mt7662.bin \ - $(1)/lib/firmware -endef - -define KernelPackage/mt76x0u/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - ln -sf mt7610e.bin $(1)/lib/firmware/mediatek/mt7610u.bin -endef - -define KernelPackage/mt76x2u/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - ln -sf ../mt7662.bin $(1)/lib/firmware/mediatek/mt7662u.bin - ln -sf ../mt7662_rom_patch.bin $(1)/lib/firmware/mediatek/mt7662u_rom_patch.bin -endef - -define KernelPackage/mt7603/install - $(INSTALL_DIR) $(1)/lib/firmware - cp $(if $(CONFIG_TARGET_ramips_mt76x8), \ - $(PKG_BUILD_DIR)/firmware/mt7628_e1.bin \ - $(PKG_BUILD_DIR)/firmware/mt7628_e2.bin \ - ,\ - $(PKG_BUILD_DIR)/firmware/mt7603_e1.bin \ - $(PKG_BUILD_DIR)/firmware/mt7603_e2.bin \ - ) \ - $(1)/lib/firmware -endef - -define KernelPackage/mt7615-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7615_cr4.bin \ - $(PKG_BUILD_DIR)/firmware/mt7615_n9.bin \ - $(PKG_BUILD_DIR)/firmware/mt7615_rom_patch.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7622-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7622_n9.bin \ - $(PKG_BUILD_DIR)/firmware/mt7622_rom_patch.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7663-firmware-ap/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7663_n9_rebb.bin \ - $(PKG_BUILD_DIR)/firmware/mt7663pr2h_rebb.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7663-firmware-sta/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7663_n9_v3.bin \ - $(PKG_BUILD_DIR)/firmware/mt7663pr2h.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7915-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7915_wa.bin \ - $(PKG_BUILD_DIR)/firmware/mt7915_wm.bin \ - $(PKG_BUILD_DIR)/firmware/mt7915_rom_patch.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7916-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7916_wa.bin \ - $(PKG_BUILD_DIR)/firmware/mt7916_wm.bin \ - $(PKG_BUILD_DIR)/firmware/mt7916_rom_patch.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7981-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7981_wa.bin \ - $(PKG_BUILD_DIR)/firmware/mt7981_wm.bin \ - $(PKG_BUILD_DIR)/firmware/mt7981_rom_patch.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7986-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/mt7986_wa.bin \ - $(PKG_BUILD_DIR)/firmware/mt7986_wm_mt7975.bin \ - $(PKG_BUILD_DIR)/firmware/mt7986_wm.bin \ - $(PKG_BUILD_DIR)/firmware/mt7986_rom_patch_mt7975.bin \ - $(PKG_BUILD_DIR)/firmware/mt7986_rom_patch.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7921-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/WIFI_MT7961_patch_mcu_1_2_hdr.bin \ - $(PKG_BUILD_DIR)/firmware/WIFI_RAM_CODE_MT7961_1.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7922-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek - cp \ - $(PKG_BUILD_DIR)/firmware/WIFI_MT7922_patch_mcu_1_1_hdr.bin \ - $(PKG_BUILD_DIR)/firmware/WIFI_RAM_CODE_MT7922_1.bin \ - $(1)/lib/firmware/mediatek -endef - -define KernelPackage/mt7925-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7925 - cp \ - $(PKG_BUILD_DIR)/firmware/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin \ - $(PKG_BUILD_DIR)/firmware/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin \ - $(1)/lib/firmware/mediatek/mt7925 -endef - -define KernelPackage/mt7992-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 - cp \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_2i5i.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_2i5e.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm.bin \ - $(1)/lib/firmware/mediatek/mt7996 -endef - -define KernelPackage/mt7992-23-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 - cp \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp_23.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23_2i5i.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch_23.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa_23.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm_23.bin \ - $(1)/lib/firmware/mediatek/mt7996 -endef - -define KernelPackage/mt7996-firmware-common/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 - cp \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_dsp.bin \ - $(1)/lib/firmware/mediatek/mt7996 -endef - -define KernelPackage/mt7996-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 - cp \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_2i5i6i.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_rom_patch.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wa.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wm.bin \ - $(1)/lib/firmware/mediatek/mt7996 -endef - -define KernelPackage/mt7996-233-firmware/install - $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 - cp \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_233.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_233_2i5i6i.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_rom_patch_233.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wa_233.bin \ - $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wm_233.bin \ - $(1)/lib/firmware/mediatek/mt7996 -endef - -define Package/mt76-test/install - mkdir -p $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/tools/mt76-test $(1)/usr/sbin -endef - -define Build/InstallDev - mkdir -p $(STAGING_DIR_IMAGE) - $(CP) $(PKG_BUILD_DIR)/firmware/mt7981_eeprom_mt7976_dbdc.bin $(STAGING_DIR_IMAGE)/ -endef - -$(eval $(call KernelPackage,mt76-core)) -$(eval $(call KernelPackage,mt76-usb)) -$(eval $(call KernelPackage,mt76x02-usb)) -$(eval $(call KernelPackage,mt76x02-common)) -$(eval $(call KernelPackage,mt76x0-common)) -$(eval $(call KernelPackage,mt76x0e)) -$(eval $(call KernelPackage,mt76x0u)) -$(eval $(call KernelPackage,mt76x2-common)) -$(eval $(call KernelPackage,mt76x2u)) -$(eval $(call KernelPackage,mt76x2)) -$(eval $(call KernelPackage,mt7603)) -$(eval $(call KernelPackage,mt76-connac)) -$(eval $(call KernelPackage,mt76-sdio)) -$(eval $(call KernelPackage,mt7615-common)) -$(eval $(call KernelPackage,mt7615-firmware)) -$(eval $(call KernelPackage,mt7622-firmware)) -$(eval $(call KernelPackage,mt7615e)) -$(eval $(call KernelPackage,mt7663-firmware-ap)) -$(eval $(call KernelPackage,mt7663-firmware-sta)) -$(eval $(call KernelPackage,mt7663-usb-sdio)) -$(eval $(call KernelPackage,mt7663u)) -$(eval $(call KernelPackage,mt7663s)) -$(eval $(call KernelPackage,mt7915-firmware)) -$(eval $(call KernelPackage,mt7915e)) -$(eval $(call KernelPackage,mt7916-firmware)) -$(eval $(call KernelPackage,mt7981-firmware)) -$(eval $(call KernelPackage,mt7986-firmware)) -$(eval $(call KernelPackage,mt7921-firmware)) -$(eval $(call KernelPackage,mt7922-firmware)) -$(eval $(call KernelPackage,mt7925-firmware)) -$(eval $(call KernelPackage,mt792x-common)) -$(eval $(call KernelPackage,mt792x-usb)) -$(eval $(call KernelPackage,mt7921-common)) -$(eval $(call KernelPackage,mt7925-common)) -$(eval $(call KernelPackage,mt7921u)) -$(eval $(call KernelPackage,mt7921s)) -$(eval $(call KernelPackage,mt7921e)) -$(eval $(call KernelPackage,mt7925u)) -$(eval $(call KernelPackage,mt7925e)) -$(eval $(call KernelPackage,mt7996e)) -$(eval $(call KernelPackage,mt7992-firmware)) -$(eval $(call KernelPackage,mt7992-23-firmware)) -$(eval $(call KernelPackage,mt7996-firmware-common)) -$(eval $(call KernelPackage,mt7996-firmware)) -$(eval $(call KernelPackage,mt7996-233-firmware)) -$(eval $(call KernelPackage,mt76)) -$(eval $(call BuildPackage,mt76-test)) diff --git a/openwrt/patch/mt76/README.md b/openwrt/patch/mt76/README.md new file mode 100644 index 000000000..6f63b6e6c --- /dev/null +++ b/openwrt/patch/mt76/README.md @@ -0,0 +1 @@ +# mt76 - fix work for linux-6.12 diff --git a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch index ef08a3494..0128977c6 100644 --- a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +++ b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch @@ -1,6 +1,6 @@ --- a/mac80211.c +++ b/mac80211.c -@@ -582,7 +582,7 @@ int mt76_create_page_pool(struct mt76_de +@@ -613,7 +613,7 @@ int mt76_create_page_pool(struct mt76_de { struct page_pool_params pp_params = { .order = 0, diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index b195db56b..3c16d8102 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -171,9 +171,7 @@ git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl88 git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac -b v6.11 # mt76 - 2024-10-11 -rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches -curl -s https://$mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch curl -s https://$mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch From 2abc19ddaa6949d44ba1e0eaccdb2403fb14f17a Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 18 Nov 2024 05:45:33 +0800 Subject: [PATCH 135/425] sync kernel module Signed-off-by: sbwml --- openwrt/24-config-musl-x86 | 16 +-- openwrt/build.sh | 13 +- openwrt/generic/config-firmware | 11 -- openwrt/patch/openwrt-6.x/modules/can.mk | 19 +++ openwrt/patch/openwrt-6.x/modules/fs.mk | 5 +- openwrt/patch/openwrt-6.x/modules/video.mk | 133 +++++++++++++------ openwrt/patch/openwrt-6.x/modules/virt.mk | 4 +- openwrt/patch/openwrt-6.x/x86/64/config-6.12 | 9 -- openwrt/patch/openwrt-6.x/x86/config-6.12 | 13 +- 9 files changed, 126 insertions(+), 97 deletions(-) delete mode 100644 openwrt/generic/config-firmware diff --git a/openwrt/24-config-musl-x86 b/openwrt/24-config-musl-x86 index f15626697..f9c01bd0e 100644 --- a/openwrt/24-config-musl-x86 +++ b/openwrt/24-config-musl-x86 @@ -41,21 +41,7 @@ CONFIG_PACKAGE_kmod-txgbe=y CONFIG_PACKAGE_kmod-nvme=y ### Display & Extra Drivers -CONFIG_PACKAGE_kmod-backlight-pwm=y -CONFIG_PACKAGE_kmod-backlight=y +CONFIG_PACKAGE_i915-firmware-huc=y CONFIG_PACKAGE_kmod-drm-i915=y -CONFIG_PACKAGE_kmod-drm-kms-helper=y -CONFIG_PACKAGE_kmod-drm-radeon=y -CONFIG_PACKAGE_kmod-drm-ttm=y -CONFIG_PACKAGE_kmod-drm=y -CONFIG_PACKAGE_kmod-fb-cfb-copyarea=y -CONFIG_PACKAGE_kmod-fb-cfb-fillrect=y -CONFIG_PACKAGE_kmod-fb-cfb-imgblt=y -CONFIG_PACKAGE_kmod-fb-sys-fops=y -CONFIG_PACKAGE_kmod-fb-sys-ram=y -CONFIG_PACKAGE_kmod-fb=y CONFIG_PACKAGE_kmod-sound-hda-codec-realtek=y CONFIG_PACKAGE_kmod-sound-hda-intel=y -CONFIG_PACKAGE_kmod-video-pwc=y -CONFIG_PACKAGE_kmod-video-uvc=y -CONFIG_PACKAGE_kmod-video-videobuf2=y diff --git a/openwrt/build.sh b/openwrt/build.sh index e2e7df6bf..57995e2bc 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -160,7 +160,7 @@ echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" [ "$ENABLE_LRNG" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_LRNG: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_LRNG:${RES} ${RED_COLOR}false${RES}" [ "$ENABLE_LOCAL_KMOD" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_LOCAL_KMOD: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_LOCAL_KMOD: false${RES}" [ "$BUILD_FAST" = "y" ] && echo -e "${GREEN_COLOR}BUILD_FAST: true${RES}" || echo -e "${GREEN_COLOR}BUILD_FAST:${RES} ${YELLOW_COLOR}false${RES}" -[ "$ENABLE_CCACHE" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_CCACHE: true${RES}" || echo -e "${YELLOW_COLOR}ENABLE_CCACHE:${RES} ${YELLOW_COLOR}false${RES}" +[ "$ENABLE_CCACHE" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_CCACHE: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_CCACHE:${RES} ${YELLOW_COLOR}false${RES}" [ "$MINIMAL_BUILD" = "y" ] && echo -e "${GREEN_COLOR}MINIMAL_BUILD: true${RES}" || echo -e "${GREEN_COLOR}MINIMAL_BUILD: false${RES}" [ "$KERNEL_CLANG_LTO" = "y" ] && echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO: true${RES}\r\n" || echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO:${RES} ${YELLOW_COLOR}false${RES}\r\n" @@ -281,9 +281,6 @@ else [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi -# config-firmware -[ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ] && curl -s https://$mirror/openwrt/generic/config-firmware >> .config - # ota [ "$ENABLE_OTA" = "y" ] && [ "$version" = "rc2" ] && echo 'CONFIG_PACKAGE_luci-app-ota=y' >> .config @@ -423,8 +420,6 @@ if [ "$platform" = "x86_64" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - # driver firmware - cp -a bin/packages/x86_64/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/x86_64/base/*natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true @@ -466,8 +461,6 @@ elif [ "$platform" = "armv8" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/armsr/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - # driver firmware - cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true @@ -499,8 +492,6 @@ elif [ "$platform" = "bcm53xx" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/bcm53xx/generic/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - # driver firmware - cp -a bin/packages/arm_cortex-a9/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/arm_cortex-a9/base/*natflow*.ipk $kmodpkg_name/ bash kmod-sign $kmodpkg_name tar zcf bcm53xx-$kmodpkg_name.tar.gz $kmodpkg_name @@ -533,8 +524,6 @@ else if [ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ]; then cp -a bin/targets/rockchip/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - # driver firmware - cp -a bin/packages/aarch64_generic/base/*firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true diff --git a/openwrt/generic/config-firmware b/openwrt/generic/config-firmware deleted file mode 100644 index a193a5dec..000000000 --- a/openwrt/generic/config-firmware +++ /dev/null @@ -1,11 +0,0 @@ - -### RTL Firmware -CONFIG_PACKAGE_rtl8723de-firmware=m -CONFIG_PACKAGE_rtl8821ce-firmware=m -CONFIG_PACKAGE_rtl8851be-firmware=m -CONFIG_PACKAGE_rtl8852ae-firmware=m -CONFIG_PACKAGE_rtl8852be-firmware=m -CONFIG_PACKAGE_rtl8852ce-firmware=m - -### MT76 Firmware -CONFIG_PACKAGE_mt7988-2p5g-phy-firmware=m diff --git a/openwrt/patch/openwrt-6.x/modules/can.mk b/openwrt/patch/openwrt-6.x/modules/can.mk index c86d02d8d..1a4c81cc3 100644 --- a/openwrt/patch/openwrt-6.x/modules/can.mk +++ b/openwrt/patch/openwrt-6.x/modules/can.mk @@ -245,6 +245,25 @@ endef $(eval $(call KernelPackage,can-usb-esd)) +define KernelPackage/can-usb-gs + TITLE:=Geschwister Schneider UG interfaces + KCONFIG:=CONFIG_CAN_GS_USB + FILES:= \ + $(LINUX_DIR)/drivers/net/can/usb/gs_usb.ko + AUTOLOAD:=$(call AutoProbe,gs_usb) + $(call AddDepends/can,+kmod-usb-core) +endef + +define KernelPackage/can-usb-gsr/description + This driver supports the Geschwister Schneider and + bytewerk.org candleLight compatible + (https://github.com/candle-usb/candleLight_fw) USB/CAN + interfaces. +endef + +$(eval $(call KernelPackage,can-usb-gs)) + + define KernelPackage/can-usb-kvaser TITLE:=Kvaser CAN/USB interface KCONFIG:=CONFIG_CAN_KVASER_USB diff --git a/openwrt/patch/openwrt-6.x/modules/fs.mk b/openwrt/patch/openwrt-6.x/modules/fs.mk index 1f0a87bb2..e676ea767 100644 --- a/openwrt/patch/openwrt-6.x/modules/fs.mk +++ b/openwrt/patch/openwrt-6.x/modules/fs.mk @@ -707,10 +707,7 @@ define KernelPackage/pstore DEFAULT:=m if ALL_KMODS KCONFIG:= \ CONFIG_PSTORE \ - CONFIG_PSTORE_COMPRESS=y \ - CONFIG_PSTORE_COMPRESS_DEFAULT="deflate" \ - CONFIG_PSTORE_DEFLATE_COMPRESS=y \ - CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y + CONFIG_PSTORE_COMPRESS=y FILES:= $(LINUX_DIR)/fs/pstore/pstore.ko AUTOLOAD:=$(call AutoLoad,30,pstore,1) DEPENDS:=+kmod-lib-zlib-deflate +kmod-lib-zlib-inflate diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index 009f74654..fdcd99312 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -343,6 +343,38 @@ endef $(eval $(call KernelPackage,drm-exec)) +define KernelPackage/drm-dma-helper + SUBMENU:=$(VIDEO_MENU) + HIDDEN:=1 + TITLE:=GEM DMA helper functions + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper + KCONFIG:=CONFIG_DRM_GEM_DMA_HELPER + FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_dma_helper.ko + AUTOLOAD:=$(call AutoProbe,drm_dma_helper) +endef + +define KernelPackage/drm-dma-helper/description + GEM DMA helper functions. +endef + +$(eval $(call KernelPackage,drm-dma-helper)) + +define KernelPackage/drm-mipi-dbi + SUBMENU:=$(VIDEO_MENU) + HIDDEN:=1 + TITLE:=MIPI DBI helpers + DEPENDS:=@DISPLAY_SUPPORT +kmod-backlight +kmod-drm-kms-helper + KCONFIG:=CONFIG_DRM_MIPI_DBI + FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_mipi_dbi.ko + AUTOLOAD:=$(call AutoProbe,drm_mipi_dbi) +endef + +define KernelPackage/drm-mipi-dbi/description + MIPI Display Bus Interface (DBI) LCD controller support. +endef + +$(eval $(call KernelPackage,drm-mipi-dbi)) + define KernelPackage/drm-ttm SUBMENU:=$(VIDEO_MENU) TITLE:=GPU memory management subsystem @@ -438,6 +470,49 @@ endef $(eval $(call KernelPackage,drm-amdgpu)) +define KernelPackage/drm-i915 + SUBMENU:=$(VIDEO_MENU) + TITLE:=Intel i915 DRM support + DEPENDS:=@(TARGET_x86_64||TARGET_x86_generic||TARGET_x86_legacy) \ + @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-ttm \ + +kmod-drm-ttm-helper +kmod-drm-kms-helper +kmod-i2c-algo-bit +i915-firmware-dmc \ + +kmod-drm-display-helper +kmod-drm-buddy +kmod-acpi-video \ + +kmod-drm-exec +kmod-drm-suballoc-helper + KCONFIG:=CONFIG_DRM_I915 \ + CONFIG_DRM_I915_CAPTURE_ERROR=y \ + CONFIG_DRM_I915_COMPRESS_ERROR=y \ + CONFIG_DRM_I915_DEBUG=n \ + CONFIG_DRM_I915_DEBUG_GUC=n \ + CONFIG_DRM_I915_DEBUG_MMIO=n \ + CONFIG_DRM_I915_DEBUG_RUNTIME_PM=n \ + CONFIG_DRM_I915_DEBUG_VBLANK_EVADE=n \ + CONFIG_DRM_I915_FENCE_TIMEOUT=10000 \ + CONFIG_DRM_I915_FORCE_PROBE="" \ + CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500 \ + CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS=n \ + CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000 \ + CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 \ + CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE=7500 \ + CONFIG_DRM_I915_REQUEST_TIMEOUT=20000 \ + CONFIG_DRM_I915_SELFTEST=n \ + CONFIG_DRM_I915_STOP_TIMEOUT=100 \ + CONFIG_DRM_I915_SW_FENCE_CHECK_DAG=n \ + CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS=n \ + CONFIG_DRM_I915_TIMESLICE_DURATION=1 \ + CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 \ + CONFIG_DRM_I915_USERPTR=y \ + CONFIG_DRM_I915_WERROR=n \ + CONFIG_FB_INTEL=n + FILES:=$(LINUX_DIR)/drivers/gpu/drm/i915/i915.ko + AUTOLOAD:=$(call AutoProbe,i915) +endef + +define KernelPackage/drm-i915/description + Direct Rendering Manager (DRM) support for Intel GPU +endef + +$(eval $(call KernelPackage,drm-i915)) + define KernelPackage/drm-imx SUBMENU:=$(VIDEO_MENU) @@ -516,6 +591,24 @@ endef $(eval $(call KernelPackage,drm-imx-ldb)) +define KernelPackage/drm-panel-mipi-dbi + SUBMENU:=$(VIDEO_MENU) + TITLE:=Generic MIPI DBI LCD panel + DEPENDS:=+kmod-drm-mipi-dbi +kmod-drm-dma-helper + KCONFIG:=CONFIG_DRM_PANEL_MIPI_DBI \ + CONFIG_DRM_FBDEV_EMULATION=y \ + CONFIG_DRM_FBDEV_OVERALLOC=100 + FILES:= \ + $(LINUX_DIR)/drivers/gpu/drm/tiny/panel-mipi-dbi.ko + AUTOLOAD:=$(call AutoProbe,panel-mipi-dbi) +endef + +define KernelPackage/drm-panel-mipi-dbi/description + Generic driver for MIPI Alliance Display Bus Interface +endef + +$(eval $(call KernelPackage,drm-panel-mipi-dbi)) + define KernelPackage/drm-lima SUBMENU:=$(VIDEO_MENU) TITLE:=Mali-4xx GPU support @@ -1280,7 +1373,6 @@ endef $(eval $(call KernelPackage,video-mem2mem)) - define KernelPackage/video-dma-contig SUBMENU:=$(VIDEO_MENU) TITLE:=Video DMA support @@ -1368,42 +1460,3 @@ define KernelPackage/video-tw686x/description endef $(eval $(call KernelPackage,video-tw686x)) - - -define KernelPackage/drm-i915 - SUBMENU:=$(VIDEO_MENU) - TITLE:=Intel GPU drm support - DEPENDS:=@TARGET_x86 +kmod-drm-buddy +kmod-drm-ttm +kmod-drm-kms-helper +i915-firmware \ - +kmod-drm-display-helper +kmod-acpi-video - KCONFIG:= \ - CONFIG_INTEL_GTT \ - CONFIG_DRM_I915 \ - CONFIG_DRM_I915_CAPTURE_ERROR=y \ - CONFIG_DRM_I915_COMPRESS_ERROR=y \ - CONFIG_DRM_I915_DEBUG=n \ - CONFIG_DRM_I915_DEBUG_GUC=n \ - CONFIG_DRM_I915_DEBUG_MMIO=n \ - CONFIG_DRM_I915_DEBUG_RUNTIME_PM=n \ - CONFIG_DRM_I915_DEBUG_VBLANK_EVADE=n \ - CONFIG_DRM_I915_GVT=y \ - CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS=n \ - CONFIG_DRM_I915_SELFTEST=n \ - CONFIG_DRM_I915_SW_FENCE_CHECK_DAG=n \ - CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS=n \ - CONFIG_DRM_I915_USERPTR=y \ - CONFIG_DRM_I915_WERROR=n - FILES:= \ - $(LINUX_DIR)/drivers/gpu/drm/i915/i915.ko - AUTOLOAD:=$(call AutoProbe,i915) -endef - -define KernelPackage/drm-i915/description - Direct Rendering Manager (DRM) support for "Intel Graphics - Media Accelerator" or "HD Graphics" integrated graphics, - including 830M, 845G, 852GM, 855GM, 865G, 915G, 945G, 965G, - G35, G41, G43, G45 chipsets and Celeron, Pentium, Core i3, - Core i5, Core i7 as well as Atom CPUs with integrated graphics. -endef - -$(eval $(call KernelPackage,drm-i915)) - diff --git a/openwrt/patch/openwrt-6.x/modules/virt.mk b/openwrt/patch/openwrt-6.x/modules/virt.mk index 88137df6b..d7ba60b61 100644 --- a/openwrt/patch/openwrt-6.x/modules/virt.mk +++ b/openwrt/patch/openwrt-6.x/modules/virt.mk @@ -80,10 +80,8 @@ define KernelPackage/vfio TITLE:=VFIO Non-Privileged userspace driver framework KCONFIG:= \ CONFIG_VFIO \ - CONFIG_VFIO_AMBA=n \ CONFIG_VFIO_NOIOMMU=n \ - CONFIG_VFIO_MDEV=n \ - CONFIG_VFIO_PLATFORM=n + CONFIG_VFIO_MDEV=n FILES:= \ $(LINUX_DIR)/drivers/vfio/vfio.ko \ $(LINUX_DIR)/drivers/vfio/vfio_iommu_type1.ko diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.12 b/openwrt/patch/openwrt-6.x/x86/64/config-6.12 index 211bdc52e..996c787f7 100644 --- a/openwrt/patch/openwrt-6.x/x86/64/config-6.12 +++ b/openwrt/patch/openwrt-6.x/x86/64/config-6.12 @@ -155,15 +155,6 @@ CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 CONFIG_DRM_GEM_SHMEM_HELPER=y # CONFIG_DRM_HYPERV is not set -CONFIG_DRM_I915_FENCE_TIMEOUT=10000 -CONFIG_DRM_I915_FORCE_PROBE="" -CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500 -CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000 -CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 -CONFIG_DRM_I915_REQUEST_TIMEOUT=20000 -CONFIG_DRM_I915_STOP_TIMEOUT=100 -CONFIG_DRM_I915_TIMESLICE_DURATION=1 -CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 CONFIG_DRM_KMS_HELPER=y CONFIG_DRM_MIPI_DSI=y CONFIG_DRM_PANEL_BRIDGE=y diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.12 b/openwrt/patch/openwrt-6.x/x86/config-6.12 index 3df65431e..865242a61 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.12 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.12 @@ -34,8 +34,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_BLK_MQ_PCI=y CONFIG_BOUNCE=y CONFIG_BUFFER_HEAD=y -CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" -CONFIG_CC_NO_ARRAY_BOUNDS=y CONFIG_CLKBLD_I8253=y CONFIG_CLKEVT_I8253=y CONFIG_CLKSRC_I8253=y @@ -49,6 +47,7 @@ CONFIG_COMPAT_32BIT_TIME=y CONFIG_COMPAT_32=y # CONFIG_COMPAT_VDSO is not set CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CONTEXT_TRACKING_USER_FORCE=y # CONFIG_CPU5_WDT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set @@ -61,7 +60,10 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_USERSPACE is not set CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ=y +CONFIG_CPU_IDLE_GOV_HALTPOLL=y CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_GOV_TEO=y CONFIG_CPU_IDLE=y CONFIG_CPU_MITIGATIONS=y CONFIG_CPU_SUP_AMD=y @@ -138,7 +140,6 @@ CONFIG_FUSION_SPI=y CONFIG_FUSION=y CONFIG_FW_LOADER_PAGED_BUF=y CONFIG_FW_LOADER_SYSFS=y -CONFIG_GCC11_NO_ARRAY_BOUNDS=y CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y # CONFIG_GDS_FORCE_MITIGATION is not set CONFIG_GENERIC_ALLOCATOR=y @@ -297,6 +298,9 @@ CONFIG_NET_XGRESS=y CONFIG_NLS=y # CONFIG_NMI_CHECK_CPU is not set # CONFIG_NOHIGHMEM is not set +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_FULL=y +CONFIG_NO_HZ=y CONFIG_NR_CPUS=1 CONFIG_NR_CPUS_DEFAULT=1 CONFIG_NR_CPUS_RANGE_BEGIN=1 @@ -358,6 +362,9 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y # CONFIG_RANDOM_KMALLOC_CACHES is not set CONFIG_RANDSTRUCT_NONE=y CONFIG_RATIONAL=y +# CONFIG_RCU_LAZY_DEFAULT_OFF is not set +CONFIG_RCU_LAZY=y +CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y CONFIG_RD_BZIP2=y CONFIG_RD_GZIP=y CONFIG_RETHUNK=y From 8a0c7d0fc00a2c7aed08978073e31a908403ba01 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 18 Nov 2024 20:29:13 +0800 Subject: [PATCH 136/425] linux-6.12: bump to 6.12 Signed-off-by: sbwml --- .../953-net-patch-linux-kernel-to-support-shortcut-fe.patch | 6 +++--- .../net/983-add-bcm-fullcone-nft_masq-support.patch | 2 +- tags/kernel-6.12 | 4 ++-- tags/kernel-tag.sh | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 683f04974..363606f3c 100644 --- a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -111,7 +111,7 @@ Signed-off-by: Xiaoping Fan len = skb->len; trace_net_dev_start_xmit(skb, dev); -@@ -5413,6 +5422,11 @@ void netdev_rx_handler_unregister(struct +@@ -5417,6 +5426,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5461,6 +5475,10 @@ static int __netif_receive_skb_core(stru +@@ -5465,6 +5479,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5499,6 +5517,16 @@ another_round: +@@ -5503,6 +5521,16 @@ another_round: goto out; } diff --git a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch index 4f0f40b51..0891fbf4d 100644 --- a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -30,7 +30,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -11082,6 +11082,24 @@ static int nft_validate_register_load(en +@@ -11083,6 +11083,24 @@ static int nft_validate_register_load(en return 0; } diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 88675b756..933cdd68f 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -rc7 -LINUX_KERNEL_HASH-6.12-rc7 = 8581f2f35bf1fbed271add5af73cfd88c299a2b3be4668110116987443caa361 +LINUX_VERSION-6.12 = +LINUX_KERNEL_HASH-6.12 = b1a2562be56e42afb3f8489d4c2a7ac472ac23098f1ef1c1e40da601f54625eb diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index cb72ec981..262f8400c 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -3,8 +3,8 @@ ROOT="./" # LTS -KERNEL_VERSION=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | awk '{print $2}' | grep -E ^linux-6.12 | grep tar.xz | sed 's/linux-//g;s/.tar.xz//g' | tail -n 1` -KERNEL_HASH=`curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc | grep linux-$KERNEL_VERSION | grep tar.xz | awk '{print $1}'` +KERNEL_VERSION=`curl -s https://cdn.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc | awk '{print $2}' | grep -E ^linux-6.12 | grep tar.xz | sed 's/linux-//g;s/.tar.xz//g' | tail -n 1` +KERNEL_HASH=`curl -s https://cdn.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc | grep linux-$KERNEL_VERSION | grep tar.xz | awk '{print $1}'` TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` [ -z $TAG ] && TAG="" || TAG=.$TAG From bdefa519860ba02acb24368775f65a6db3ae499c Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 18 Nov 2024 20:33:58 +0800 Subject: [PATCH 137/425] bpf-headers: update to linux 6.12 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 3c16d8102..262d3c17d 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -9,6 +9,9 @@ git clone https://$github/sbwml/autocore-arm -b openwrt-24.10 package/system/aut rm -rf target/linux/rockchip git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-24.10 +# bpf-headers - 6.12 +sed -ri "s/(PKG_PATCHVER:=)[^\"]*/\16.12/" package/kernel/bpf-headers/Makefile + # x86_64 - target 6.12 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.12 > target/linux/x86/64/config-6.12 curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/config-6.12 From a84c446990030f68bb52382cd1a0796115c2ba06 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 19 Nov 2024 20:52:28 +0800 Subject: [PATCH 138/425] ci: use a local http server as a source Signed-off-by: sbwml --- .github/workflows/build-release.yml | 19 +- openwrt/build.sh | 60 +++--- openwrt/scripts/00-prepare_base.sh | 208 ++++++++++---------- openwrt/scripts/01-prepare_base-mainline.sh | 198 +++++++++---------- openwrt/scripts/02-prepare_package.sh | 20 +- openwrt/scripts/04-fix_kmod.sh | 40 ++-- openwrt/scripts/05-fix-source.sh | 20 +- 7 files changed, 290 insertions(+), 275 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 53f8694e9..442602511 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -46,6 +46,12 @@ jobs: shell: bash steps: + - name: Checkout + continue-on-error: true + uses: actions/checkout@main + with: + path: r4s_build_script + - name: Setup variables run: | sudo timedatectl set-timezone 'Asia/Shanghai' @@ -68,6 +74,16 @@ jobs: uname -a echo + - name: Install Caddy Server + run: | + sudo curl -sL -o /usr/bin/caddy https://github.com/sbwml/r4s_build_script/releases/download/caddy/caddy + sudo chmod 755 /usr/bin/caddy + echo ":8080 {" > caddyfile + echo " root * $(pwd)/r4s_build_script" >> caddyfile + echo " file_server browse" >> caddyfile + echo "}" >> caddyfile + sudo /usr/bin/caddy start --config caddyfile --adapter caddyfile + - name: Free disk space uses: sbwml/actions@free-disk with: @@ -105,10 +121,9 @@ jobs: id: compile continue-on-error: true run: | - export GITHUB_REPO=${{ github.repository }} export ${{ github.event.inputs.build_options }} LAN=${{ github.event.inputs.lan_addr }} USE_GCC15=y [ ${{ github.event.inputs.ccache }} = 'true' ] && export ENABLE_CCACHE=y - bash <(curl -sS https://raw.githubusercontent.com/${{ github.repository }}/master/openwrt/build.sh) ${{ env.build_version }} ${{ github.event.inputs.device }} + bash <(curl -sS http://127.0.0.1:8080/build.sh) ${{ env.build_version }} ${{ github.event.inputs.device }} cd openwrt if [ "${{ github.event.inputs.version }}" = release ]; then tags=OpenWrt-$(git describe --abbrev=0 --tags) diff --git a/openwrt/build.sh b/openwrt/build.sh index 57995e2bc..8670dc2a0 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -30,14 +30,14 @@ ip_info=`curl -sk https://ip.cooluc.com`; # script url if [ "$isCN" = "CN" ]; then - export mirror=init.cooluc.com + export mirror=https://init.cooluc.com else - export mirror=init2.cooluc.com + export mirror=https://init2.cooluc.com fi # github actions - automatically retrieve `github raw` links -if [ "$(whoami)" = "runner" ] && [ -n "$GITHUB_REPO" ]; then - export mirror=raw.githubusercontent.com/$GITHUB_REPO/master +if [ "$(whoami)" = "runner" ]; then + export mirror=http://127.0.0.1:8080 fi # private gitea @@ -91,7 +91,7 @@ if [ "$1" = "dev" ]; then export branch=openwrt-24.10 export version=dev elif [ "$1" = "rc2" ]; then - latest_release="v$(curl -s https://$mirror/tags/v24)" + latest_release="v$(curl -s $mirror/tags/v24)" export branch=$latest_release export version=rc2 fi @@ -143,7 +143,7 @@ else echo -e "${GREEN_COLOR}Model: nanopi-r4s${RES}" [ "$1" = "rc2" ] && model="nanopi-r4s" fi -get_kernel_version=$(curl -s https://$mirror/tags/kernel-6.12) +get_kernel_version=$(curl -s $mirror/tags/kernel-6.12) kmod_hash=$(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}' | tail -1 | md5sum | awk '{print $1}') kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" @@ -178,7 +178,7 @@ git clone https://$github/immortalwrt/packages master/immortalwrt_packages --dep if [ -d openwrt ]; then cd openwrt echo "1730409337" > version.date # OpenWrt v24.10: set branch defaults - curl -Os https://$mirror/openwrt/patch/key.tar.gz && tar zxf key.tar.gz && rm -f key.tar.gz + curl -Os $mirror/openwrt/patch/key.tar.gz && tar zxf key.tar.gz && rm -f key.tar.gz else echo -e "${RED_COLOR}Failed to download source code${RES}" exit 1 @@ -228,17 +228,17 @@ fi echo -e "\n${GREEN_COLOR}Patching ...${RES}\n" # scripts -curl -sO https://$mirror/openwrt/scripts/00-prepare_base.sh -curl -sO https://$mirror/openwrt/scripts/01-prepare_base-mainline.sh -curl -sO https://$mirror/openwrt/scripts/02-prepare_package.sh -curl -sO https://$mirror/openwrt/scripts/03-convert_translation.sh -curl -sO https://$mirror/openwrt/scripts/04-fix_kmod.sh -curl -sO https://$mirror/openwrt/scripts/05-fix-source.sh -curl -sO https://$mirror/openwrt/scripts/99_clean_build_cache.sh +curl -sO $mirror/openwrt/scripts/00-prepare_base.sh +curl -sO $mirror/openwrt/scripts/01-prepare_base-mainline.sh +curl -sO $mirror/openwrt/scripts/02-prepare_package.sh +curl -sO $mirror/openwrt/scripts/03-convert_translation.sh +curl -sO $mirror/openwrt/scripts/04-fix_kmod.sh +curl -sO $mirror/openwrt/scripts/05-fix-source.sh +curl -sO $mirror/openwrt/scripts/99_clean_build_cache.sh if [ -n "$git_password" ] && [ -n "$private_url" ]; then curl -u openwrt:$git_password -sO "$private_url" else - curl -sO https://$mirror/openwrt/scripts/10-custom.sh + curl -sO $mirror/openwrt/scripts/10-custom.sh fi chmod 0755 *sh [ "$(whoami)" = "runner" ] && group "patching openwrt" @@ -256,28 +256,28 @@ rm -rf ../master # Load devices Config if [ "$platform" = "x86_64" ]; then - curl -s https://$mirror/openwrt/24-config-musl-x86 > .config + curl -s $mirror/openwrt/24-config-musl-x86 > .config elif [ "$platform" = "bcm53xx" ]; then if [ "$MINIMAL_BUILD" = "y" ]; then - curl -s https://$mirror/openwrt/24-config-musl-r8500-minimal > .config + curl -s $mirror/openwrt/24-config-musl-r8500-minimal > .config else - curl -s https://$mirror/openwrt/24-config-musl-r8500 > .config + curl -s $mirror/openwrt/24-config-musl-r8500 > .config fi sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config elif [ "$platform" = "rk3568" ]; then - curl -s https://$mirror/openwrt/24-config-musl-r5s > .config + curl -s $mirror/openwrt/24-config-musl-r5s > .config elif [ "$platform" = "armv8" ]; then - curl -s https://$mirror/openwrt/24-config-musl-armsr-armv8 > .config + curl -s $mirror/openwrt/24-config-musl-armsr-armv8 > .config else - curl -s https://$mirror/openwrt/24-config-musl-r4s > .config + curl -s $mirror/openwrt/24-config-musl-r4s > .config fi # config-common if [ "$MINIMAL_BUILD" = "y" ]; then - [ "$platform" != "bcm53xx" ] && curl -s https://$mirror/openwrt/24-config-minimal-common >> .config + [ "$platform" != "bcm53xx" ] && curl -s $mirror/openwrt/24-config-minimal-common >> .config echo 'VERSION_TYPE="minimal"' >> package/base-files/files/usr/lib/os-release else - [ "$platform" != "bcm53xx" ] && curl -s https://$mirror/openwrt/24-config-common >> .config + [ "$platform" != "bcm53xx" ] && curl -s $mirror/openwrt/24-config-common >> .config [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi @@ -285,15 +285,15 @@ fi [ "$ENABLE_OTA" = "y" ] && [ "$version" = "rc2" ] && echo 'CONFIG_PACKAGE_luci-app-ota=y' >> .config # bpf -[ "$ENABLE_BPF" = "y" ] && curl -s https://$mirror/openwrt/generic/config-bpf >> .config +[ "$ENABLE_BPF" = "y" ] && curl -s $mirror/openwrt/generic/config-bpf >> .config # LTO export ENABLE_LTO=$ENABLE_LTO -[ "$ENABLE_LTO" = "y" ] && curl -s https://$mirror/openwrt/generic/config-lto >> .config +[ "$ENABLE_LTO" = "y" ] && curl -s $mirror/openwrt/generic/config-lto >> .config # glibc [ "$ENABLE_GLIBC" = "y" ] && { - curl -s https://$mirror/openwrt/generic/config-glibc >> .config + curl -s $mirror/openwrt/generic/config-glibc >> .config sed -i '/NaiveProxy/d' .config } @@ -334,11 +334,11 @@ fi # gcc15 patches [ "$(whoami)" = "runner" ] && group "patching toolchain" -curl -s https://$mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 # gcc config -[ "$USE_GCC13" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc13 >> .config -[ "$USE_GCC14" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc14 >> .config -[ "$USE_GCC15" = "y" ] && curl -s https://$mirror/openwrt/generic/config-gcc15 >> .config +[ "$USE_GCC13" = "y" ] && curl -s $mirror/openwrt/generic/config-gcc13 >> .config +[ "$USE_GCC14" = "y" ] && curl -s $mirror/openwrt/generic/config-gcc14 >> .config +[ "$USE_GCC15" = "y" ] && curl -s $mirror/openwrt/generic/config-gcc15 >> .config [ "$(whoami)" = "runner" ] && endgroup # uhttpd diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 70965ba0b..85dc04217 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -6,16 +6,16 @@ git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-r git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip # patch source -curl -s https://$mirror/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 # attr no-mold [ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile @@ -54,27 +54,27 @@ git clone https://$github/sbwml/package_kernel_r8126 package/kernel/r8126 # GCC Optimization level -O3 if [ "$platform" = "x86_64" ]; then - curl -s https://$mirror/openwrt/patch/target-modify_for_x86_64.patch | patch -p1 + curl -s $mirror/openwrt/patch/target-modify_for_x86_64.patch | patch -p1 elif [ "$platform" = "armv8" ]; then - curl -s https://$mirror/openwrt/patch/target-modify_for_armsr.patch | patch -p1 + curl -s $mirror/openwrt/patch/target-modify_for_armsr.patch | patch -p1 else - curl -s https://$mirror/openwrt/patch/target-modify_for_rockchip.patch | patch -p1 + curl -s $mirror/openwrt/patch/target-modify_for_rockchip.patch | patch -p1 fi # DPDK & NUMACTL mkdir -p package/new/{dpdk/patches,numactl} -curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Makefile > package/new/dpdk/Makefile -curl -s https://$mirror/openwrt/patch/dpdk/dpdk/Config.in > package/new/dpdk/Config.in -curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch > package/new/dpdk/patches/010-dpdk_arm_build_platform_fix.patch -curl -s https://$mirror/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch > package/new/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch -curl -s https://$mirror/openwrt/patch/dpdk/numactl/Makefile > package/new/numactl/Makefile +curl -s $mirror/openwrt/patch/dpdk/dpdk/Makefile > package/new/dpdk/Makefile +curl -s $mirror/openwrt/patch/dpdk/dpdk/Config.in > package/new/dpdk/Config.in +curl -s $mirror/openwrt/patch/dpdk/dpdk/patches/010-dpdk_arm_build_platform_fix.patch > package/new/dpdk/patches/010-dpdk_arm_build_platform_fix.patch +curl -s $mirror/openwrt/patch/dpdk/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch > package/new/dpdk/patches/201-r8125-add-r8125-ethernet-poll-mode-driver.patch +curl -s $mirror/openwrt/patch/dpdk/numactl/Makefile > package/new/numactl/Makefile # IF USE GLIBC if [ "$ENABLE_GLIBC" = "y" ]; then # musl-libc git clone https://$gitea/sbwml/package_libs_musl-libc package/libs/musl-libc # glibc-common - curl -s https://$mirror/openwrt/patch/glibc/glibc-common.patch | patch -p1 + curl -s $mirror/openwrt/patch/glibc/glibc-common.patch | patch -p1 # glibc-common - locale data mkdir -p package/libs/toolchain/glibc-locale curl -Lso package/libs/toolchain/glibc-locale/locale-archive https://github.com/sbwml/r4s_build_script/releases/download/locale/locale-archive @@ -98,7 +98,7 @@ git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe # dnsmasq if [ "$version" = "dev" ]; then - curl -s https://$mirror/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch | patch -p1 + curl -s $mirror/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch | patch -p1 [ "$?" -ne 0 ] && curl -s https://init2.cooluc.com/openwrt/patch/dnsmasq/dnsmasq.init > package/network/services/dnsmasq/files/dnsmasq.init fi @@ -108,26 +108,26 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/network/config/firewall4/Makefile mkdir -p package/network/config/firewall4/patches # fix ct status dnat - curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch > package/network/config/firewall4/patches/990-unconditionally-allow-ct-status-dnat.patch + curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch > package/network/config/firewall4/patches/990-unconditionally-allow-ct-status-dnat.patch # fullcone - curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch + curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch # bcm fullcone - curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch + curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch # kernel version - curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch > package/network/config/firewall4/patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch + curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch > package/network/config/firewall4/patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch # fix flow offload - curl -s https://$mirror/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch > package/network/config/firewall4/patches/001-fix-fw4-flow-offload.patch + curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch > package/network/config/firewall4/patches/001-fix-fw4-flow-offload.patch # add custom nft command support - curl -s https://$mirror/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch | patch -p1 # libnftnl mkdir -p package/libs/libnftnl/patches - curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/0001-libnftnl-add-fullcone-expression-support.patch - curl -s https://$mirror/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/0002-libnftnl-add-brcm-fullcone-support.patch + curl -s $mirror/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/0001-libnftnl-add-fullcone-expression-support.patch + curl -s $mirror/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/0002-libnftnl-add-brcm-fullcone-support.patch # nftables mkdir -p package/network/utils/nftables/patches - curl -s https://$mirror/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/0001-nftables-add-fullcone-expression-support.patch - curl -s https://$mirror/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/0002-nftables-add-brcm-fullconenat-support.patch - curl -s https://$mirror/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch > package/network/utils/nftables/patches/0003-drop-rej-file.patch + curl -s $mirror/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/0001-nftables-add-fullcone-expression-support.patch + curl -s $mirror/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/0002-nftables-add-brcm-fullconenat-support.patch + curl -s $mirror/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch > package/network/utils/nftables/patches/0003-drop-rej-file.patch fi # FullCone module @@ -141,60 +141,60 @@ git clone https://$github/sbwml/package_new_natflow package/new/natflow # Patch Luci add nft_fullcone/bcm_fullcone & shortcut-fe & natflow & ipv6-nat & custom nft command option pushd feeds/luci - curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 popd # openssl - quictls pushd package/libs/openssl/patches - curl -sO https://$mirror/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0003-QUIC-Make-temp-secret-names-less-confusing.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0005-QUIC-Use-proper-secrets-for-handshake.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0006-QUIC-Handle-partial-handshake-messages.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0008-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0009-QUIC-Don-t-process-an-incomplete-message.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0010-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0011-QUIC-Add-client-early-traffic-secret-storage.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0013-QUIC-Correctly-disable-middlebox-compat.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0014-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0015-QUIC-Tweeks-to-quic_change_cipher_state.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0016-QUIC-Add-support-for-more-secrets.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0017-QUIC-Fix-resumption-secret.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0019-QUIC-Fall-through-for-0RTT.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0023-QUIC-Buffer-all-provided-quic-data.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0024-QUIC-Enforce-consistent-encryption-level-for-handsha.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0026-QUIC-return-success-when-no-post-handshake-data.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0027-QUIC-__owur-makes-no-sense-for-void-return-values.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0029-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0030-QUIC-Add-compile-run-time-checking-for-QUIC.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0032-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0035-QUIC-Break-up-header-body-processing.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0036-QUIC-Don-t-muck-with-FIPS-checksums.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0038-QUIC-revert-white-space-change.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0040-QUIC-Error-when-non-empty-session_id-in-CH.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0043-QUIC-Fix-extension-test.patch - curl -sO https://$mirror/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0003-QUIC-Make-temp-secret-names-less-confusing.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0005-QUIC-Use-proper-secrets-for-handshake.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0006-QUIC-Handle-partial-handshake-messages.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0008-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0009-QUIC-Don-t-process-an-incomplete-message.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0010-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0011-QUIC-Add-client-early-traffic-secret-storage.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0013-QUIC-Correctly-disable-middlebox-compat.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0014-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0015-QUIC-Tweeks-to-quic_change_cipher_state.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0016-QUIC-Add-support-for-more-secrets.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0017-QUIC-Fix-resumption-secret.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0019-QUIC-Fall-through-for-0RTT.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0023-QUIC-Buffer-all-provided-quic-data.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0024-QUIC-Enforce-consistent-encryption-level-for-handsha.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0026-QUIC-return-success-when-no-post-handshake-data.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0027-QUIC-__owur-makes-no-sense-for-void-return-values.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0029-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0030-QUIC-Add-compile-run-time-checking-for-QUIC.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0032-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0035-QUIC-Break-up-header-body-processing.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0036-QUIC-Don-t-muck-with-FIPS-checksums.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0038-QUIC-revert-white-space-change.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0040-QUIC-Error-when-non-empty-session_id-in-CH.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0043-QUIC-Fix-extension-test.patch + curl -sO $mirror/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch popd # openssl urandom @@ -230,22 +230,22 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then fi sed -i '/sysctl.d/d' feeds/packages/utils/dockerd/Makefile pushd feeds/packages - curl -s https://$mirror/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/docker/0003-dockerd-disable-ip6tables-for-bridge-network-by-defa.patch | patch -p1 + curl -s $mirror/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch | patch -p1 + curl -s $mirror/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch | patch -p1 + curl -s $mirror/openwrt/patch/docker/0003-dockerd-disable-ip6tables-for-bridge-network-by-defa.patch | patch -p1 popd # cgroupfs-mount # fix unmount hierarchical mount pushd feeds/packages - curl -s https://$mirror/openwrt/patch/cgroupfs-mount/0001-fix-cgroupfs-mount.patch | patch -p1 + curl -s $mirror/openwrt/patch/cgroupfs-mount/0001-fix-cgroupfs-mount.patch | patch -p1 popd # mount cgroup v2 hierarchy to /sys/fs/cgroup/cgroup2 mkdir -p feeds/packages/utils/cgroupfs-mount/patches -curl -s https://$mirror/openwrt/patch/cgroupfs-mount/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch > feeds/packages/utils/cgroupfs-mount/patches/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch -curl -s https://$mirror/openwrt/patch/cgroupfs-mount/901-fix-cgroupfs-umount.patch > feeds/packages/utils/cgroupfs-mount/patches/901-fix-cgroupfs-umount.patch +curl -s $mirror/openwrt/patch/cgroupfs-mount/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch > feeds/packages/utils/cgroupfs-mount/patches/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch +curl -s $mirror/openwrt/patch/cgroupfs-mount/901-fix-cgroupfs-umount.patch > feeds/packages/utils/cgroupfs-mount/patches/901-fix-cgroupfs-umount.patch # docker systemd support -curl -s https://$mirror/openwrt/patch/cgroupfs-mount/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch > feeds/packages/utils/cgroupfs-mount/patches/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch +curl -s $mirror/openwrt/patch/cgroupfs-mount/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch > feeds/packages/utils/cgroupfs-mount/patches/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch # procps-ng - top sed -i 's/enable-skill/enable-skill --disable-modern-top/g' feeds/packages/utils/procps-ng/Makefile @@ -271,12 +271,12 @@ sed -i 's/ubus_parallel_req 2/ubus_parallel_req 6/g' feeds/packages/net/nginx/fi sed -i '/ubus_parallel_req/a\ ubus_script_timeout 300;' feeds/packages/net/nginx/files-luci-support/60_nginx-luci-support # nginx - config -curl -s https://$mirror/openwrt/nginx/luci.locations > feeds/packages/net/nginx/files-luci-support/luci.locations -curl -s https://$mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template +curl -s $mirror/openwrt/nginx/luci.locations > feeds/packages/net/nginx/files-luci-support/luci.locations +curl -s $mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template # opkg mkdir -p package/system/opkg/patches -curl -s https://$mirror/openwrt/patch/opkg/900-opkg-download-disable-hsts.patch > package/system/opkg/patches/900-opkg-download-disable-hsts.patch +curl -s $mirror/openwrt/patch/opkg/900-opkg-download-disable-hsts.patch > package/system/opkg/patches/900-opkg-download-disable-hsts.patch # uwsgi - fix timeout sed -i '$a cgi-timeout = 600' feeds/packages/net/uwsgi/files-luci-support/luci-*.ini @@ -295,12 +295,12 @@ sed -i 's#20) \* 1000#60) \* 1000#g' feeds/luci/modules/luci-base/htdocs/luci-st # luci-mod extra pushd feeds/luci - curl -s https://$mirror/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch | patch -p1 - curl -s https://$mirror/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch | patch -p1 popd # Luci diagnostics.js @@ -311,9 +311,9 @@ sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/l # odhcpd RFC-9096 mkdir -p package/network/services/odhcpd/patches -curl -s https://$mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch +curl -s $mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch pushd feeds/luci - curl -s https://$mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 + curl -s $mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 popd # urngd - 2020-01-21 @@ -334,16 +334,16 @@ sed -i '/PS1/a\export TERM=xterm-color' package/base-files/files/etc/profile sed -i 's#ash#bash#g' package/base-files/files/etc/passwd sed -i '\#export ENV=/etc/shinit#a export HISTCONTROL=ignoredups' package/base-files/files/etc/profile mkdir -p files/root -curl -so files/root/.bash_profile https://$mirror/openwrt/files/root/.bash_profile -curl -so files/root/.bashrc https://$mirror/openwrt/files/root/.bashrc +curl -so files/root/.bash_profile $mirror/openwrt/files/root/.bash_profile +curl -so files/root/.bashrc $mirror/openwrt/files/root/.bashrc # rootfs files mkdir -p files/etc/sysctl.d -curl -so files/etc/sysctl.d/15-vm-swappiness.conf https://$mirror/openwrt/files/etc/sysctl.d/15-vm-swappiness.conf -curl -so files/etc/sysctl.d/16-udp-buffer-size.conf https://$mirror/openwrt/files/etc/sysctl.d/16-udp-buffer-size.conf +curl -so files/etc/sysctl.d/15-vm-swappiness.conf $mirror/openwrt/files/etc/sysctl.d/15-vm-swappiness.conf +curl -so files/etc/sysctl.d/16-udp-buffer-size.conf $mirror/openwrt/files/etc/sysctl.d/16-udp-buffer-size.conf if [ "$platform" = "bcm53xx" ]; then mkdir -p files/etc/hotplug.d/block - curl -so files/etc/hotplug.d/block/20-usbreset https://$mirror/openwrt/files/etc/hotplug.d/block/20-usbreset + curl -so files/etc/hotplug.d/block/20-usbreset $mirror/openwrt/files/etc/hotplug.d/block/20-usbreset fi # NTP diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 262d3c17d..46d15840f 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -13,16 +13,16 @@ git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/li sed -ri "s/(PKG_PATCHVER:=)[^\"]*/\16.12/" package/kernel/bpf-headers/Makefile # x86_64 - target 6.12 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.12 > target/linux/x86/64/config-6.12 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/config-6.12 +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.12 > target/linux/x86/64/config-6.12 +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/config-6.12 mkdir -p target/linux/x86/patches-6.12 -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.12/100-fix_cs5535_clockevt.patch -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.12/103-pcengines_apu6_platform.patch +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.12/100-fix_cs5535_clockevt.patch +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.12/103-pcengines_apu6_platform.patch # x86_64 - target sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.12/" target/linux/x86/Makefile sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds -curl -s https://$mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network # bcm53xx - target rm -rf target/linux/bcm53xx @@ -35,14 +35,14 @@ rm -rf target/linux/armsr git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b main # kernel - 6.12 -curl -s https://$mirror/tags/kernel-6.12 > include/kernel-6.12 +curl -s $mirror/tags/kernel-6.12 > include/kernel-6.12 # kenrel Vermagic sed -ie 's/^\(.\).*vermagic$/\1cp $(TOPDIR)\/.vermagic $(LINUX_DIR)\/.vermagic/' include/kernel-defaults.mk grep HASH include/kernel-6.12 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic # kernel generic patches -curl -s https://$mirror/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch | patch -p1 +curl -s $mirror/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch | patch -p1 local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-6.12) release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-6.12 | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then @@ -65,97 +65,97 @@ rm -rf package/kernel/linux git checkout package/kernel/linux pushd package/kernel/linux/modules rm -f [a-z]*.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/block.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/can.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/crypto.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/firewire.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/fs.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/gpio.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/hwmon.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/i2c.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/iio.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/input.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/leds.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/lib.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/multiplexer.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/netdevices.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/netfilter.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/netsupport.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/nls.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/other.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/pcmcia.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/rtc.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/sound.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/spi.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/usb.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/video.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/virt.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/w1.mk - curl -Os https://$mirror/openwrt/patch/openwrt-6.x/modules/wpan.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/block.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/can.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/crypto.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/firewire.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/fs.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/gpio.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/hwmon.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/i2c.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/iio.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/input.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/leds.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/lib.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/multiplexer.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/netdevices.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/netfilter.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/netsupport.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/nls.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/other.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/pcmcia.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/rtc.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/sound.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/spi.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/usb.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/video.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/virt.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/w1.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/wpan.mk popd # BBRv3 - linux-6.12 pushd target/linux/generic/backport-6.12 - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch popd # LRNG - 6.12 pushd target/linux/generic/hack-6.12 - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch popd # linux-rt - i915 pushd target/linux/generic/hack-6.12 - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch - curl -Os https://$mirror/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch popd # iproute2 - bbr3 @@ -175,11 +175,11 @@ git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl88 # mt76 - 2024-10-11 mkdir -p package/kernel/mt76/patches -curl -s https://$mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch -curl -s https://$mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch +curl -s $mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch # wireless-regdb -curl -s https://$mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch +curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch # mac80211 - 6.11 rm -rf package/kernel/mac80211 @@ -191,27 +191,27 @@ git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-c # kernel patch # btf: silence btf module warning messages -curl -s https://$mirror/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-6.12/990-btf-silence-btf-module-warning-messages.patch +curl -s $mirror/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-6.12/990-btf-silence-btf-module-warning-messages.patch # cpu model -curl -s https://$mirror/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/hack-6.12/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch +curl -s $mirror/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/hack-6.12/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch # fullcone -curl -s https://$mirror/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-6.12/952-net-conntrack-events-support-multiple-registrant.patch +curl -s $mirror/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-6.12/952-net-conntrack-events-support-multiple-registrant.patch # bcm-fullcone -curl -s https://$mirror/openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-6.12/982-add-bcm-fullcone-support.patch -curl -s https://$mirror/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-6.12/983-add-bcm-fullcone-nft_masq-support.patch +curl -s $mirror/openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-6.12/982-add-bcm-fullcone-support.patch +curl -s $mirror/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-6.12/983-add-bcm-fullcone-nft_masq-support.patch # shortcut-fe -curl -s https://$mirror/openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-6.12/601-netfilter-export-udp_get_timeouts-function.patch -curl -s https://$mirror/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.12/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +curl -s $mirror/openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-6.12/601-netfilter-export-udp_get_timeouts-function.patch +curl -s $mirror/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.12/953-net-patch-linux-kernel-to-support-shortcut-fe.patch # RTC if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ]; then - curl -s https://$mirror/openwrt/patch/rtc/sysfixtime > package/base-files/files/etc/init.d/sysfixtime + curl -s $mirror/openwrt/patch/rtc/sysfixtime > package/base-files/files/etc/init.d/sysfixtime chmod 755 package/base-files/files/etc/init.d/sysfixtime fi # emmc-install if [ "$platform" = "rk3568" ]; then mkdir -p files/sbin - curl -so files/sbin/emmc-install https://$mirror/openwrt/files/sbin/emmc-install + curl -so files/sbin/emmc-install $mirror/openwrt/files/sbin/emmc-install chmod 755 files/sbin/emmc-install fi diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 64a4950ee..c5fc1b244 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -25,15 +25,15 @@ sed -i 's/stderr 1/stderr 0/g' feeds/packages/net/nlbwmon/files/nlbwmon.init # pcre - 8.45 mkdir -p package/libs/pcre -curl -s https://$mirror/openwrt/patch/pcre/Makefile > package/libs/pcre/Makefile -curl -s https://$mirror/openwrt/patch/pcre/Config.in > package/libs/pcre/Config.in +curl -s $mirror/openwrt/patch/pcre/Makefile > package/libs/pcre/Makefile +curl -s $mirror/openwrt/patch/pcre/Config.in > package/libs/pcre/Config.in # lrzsz - 0.12.20 rm -rf feeds/packages/utils/lrzsz git clone https://$github/sbwml/packages_utils_lrzsz package/new/lrzsz # irqbalance: disable build with numa -curl -s https://$mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch +curl -s $mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch sed -i '/-Dcapng=disabled/i\\t-Dnuma=disabled \\' feeds/packages/utils/irqbalance/Makefile # frpc @@ -46,12 +46,12 @@ sed -i 's/env conf_inc/env conf_inc enable/g' feeds/packages/net/frp/files/frpc. sed -i "s/'conf_inc:list(string)'/& \\\\/" feeds/packages/net/frp/files/frpc.init sed -i "/conf_inc:list/a\\\t\t\'enable:bool:0\'" feeds/packages/net/frp/files/frpc.init sed -i '/procd_open_instance/i\\t\[ "$enable" -ne 1 \] \&\& return 1\n' feeds/packages/net/frp/files/frpc.init -curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch | patch -p1 -curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch | patch -p1 +curl -s $mirror/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch | patch -p1 +curl -s $mirror/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch | patch -p1 # natmap pushd feeds/luci - curl -s https://$mirror/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch | patch -p1 popd # samba4 - bump version @@ -134,11 +134,11 @@ rm -rf feeds/packages/utils/coremark git clone https://$github/sbwml/openwrt_pkgs package/new/custom --depth=1 # coremark - prebuilt with gcc15 if [ "$platform" = "rk3568" ]; then - curl -s https://$mirror/openwrt/patch/coremark/coremark.aarch64-4-threads > package/new/custom/coremark/src/musl/coremark.aarch64 + curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-4-threads > package/new/custom/coremark/src/musl/coremark.aarch64 elif [ "$platform" = "rk3399" ]; then - curl -s https://$mirror/openwrt/patch/coremark/coremark.aarch64-6-threads > package/new/custom/coremark/src/musl/coremark.aarch64 + curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-6-threads > package/new/custom/coremark/src/musl/coremark.aarch64 elif [ "$platform" = "armv8" ]; then - curl -s https://$mirror/openwrt/patch/coremark/coremark.aarch64-16-threads > package/new/custom/coremark/src/musl/coremark.aarch64 + curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-16-threads > package/new/custom/coremark/src/musl/coremark.aarch64 fi # luci-compat - fix translation @@ -152,7 +152,7 @@ sed -i 's,frp 客户端,FRP 客户端,g' feeds/luci/applications/luci-app-frpc/p # SQM Translation mkdir -p feeds/packages/net/sqm-scripts/patches -curl -s https://$mirror/openwrt/patch/sqm/001-help-translation.patch > feeds/packages/net/sqm-scripts/patches/001-help-translation.patch +curl -s $mirror/openwrt/patch/sqm/001-help-translation.patch > feeds/packages/net/sqm-scripts/patches/001-help-translation.patch # unzip rm -rf feeds/packages/utils/unzip diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index 9d58fa5aa..38d306c59 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -4,54 +4,54 @@ # cryptodev-linux mkdir -p package/kernel/cryptodev-linux/patches -curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch -curl -s https://$mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch > package/kernel/cryptodev-linux/patches/0006-Exclude-unused-struct-since-Linux-6.5.patch +curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch +curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch > package/kernel/cryptodev-linux/patches/0006-Exclude-unused-struct-since-Linux-6.5.patch # gpio-button-hotplug -curl -s https://$mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 +curl -s $mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 # jool -curl -s https://$mirror/openwrt/patch/packages-patches/jool/Makefile > feeds/packages/net/jool/Makefile +curl -s $mirror/openwrt/patch/packages-patches/jool/Makefile > feeds/packages/net/jool/Makefile # ovpn-dco mkdir -p feeds/packages/kernel/ovpn-dco/patches -curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch > feeds/packages/kernel/ovpn-dco/patches/901-fix-linux-6.11.patch -curl -s https://$mirror/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch > feeds/packages/kernel/ovpn-dco/patches/902-fix-linux-6.12.patch +curl -s $mirror/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch > feeds/packages/kernel/ovpn-dco/patches/901-fix-linux-6.11.patch +curl -s $mirror/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch > feeds/packages/kernel/ovpn-dco/patches/902-fix-linux-6.12.patch # libpfring rm -rf feeds/packages/libs/libpfring mkdir -p feeds/packages/libs/libpfring/patches -curl -s https://$mirror/openwrt/patch/packages-patches/libpfring/Makefile > feeds/packages/libs/libpfring/Makefile +curl -s $mirror/openwrt/patch/packages-patches/libpfring/Makefile > feeds/packages/libs/libpfring/Makefile pushd feeds/packages/libs/libpfring/patches - curl -Os https://$mirror/openwrt/patch/packages-patches/libpfring/patches/0001-fix-cross-compiling.patch - curl -Os https://$mirror/openwrt/patch/packages-patches/libpfring/patches/100-fix-compilation-warning.patch - curl -Os https://$mirror/openwrt/patch/packages-patches/libpfring/patches/900-fix-linux-6.6.patch + curl -Os $mirror/openwrt/patch/packages-patches/libpfring/patches/0001-fix-cross-compiling.patch + curl -Os $mirror/openwrt/patch/packages-patches/libpfring/patches/100-fix-compilation-warning.patch + curl -Os $mirror/openwrt/patch/packages-patches/libpfring/patches/900-fix-linux-6.6.patch popd # nat46 mkdir -p package/kernel/nat46/patches -curl -s https://$mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch > package/kernel/nat46/patches/100-fix-build-with-kernel-6.9.patch -curl -s https://$mirror/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch > package/kernel/nat46/patches/101-fix-build-with-kernel-6.12.patch +curl -s $mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch > package/kernel/nat46/patches/100-fix-build-with-kernel-6.9.patch +curl -s $mirror/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch > package/kernel/nat46/patches/101-fix-build-with-kernel-6.12.patch # openvswitch sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile # rtpengine -curl -s https://$mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch +curl -s $mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch # ubootenv-nvram - 6.12 mkdir -p package/kernel/ubootenv-nvram/patches -curl -s https://$mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.12.patch +curl -s $mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.12.patch # packages pushd feeds/packages # xr_usb_serial_common linux-6.12 - curl -s https://$mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch + curl -s $mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch popd # xtables-addons -curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch -curl -s https://$mirror/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch > feeds/packages/net/xtables-addons/patches/302-fix-build-for-linux-6.12rc2.patch +curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch +curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch > feeds/packages/net/xtables-addons/patches/302-fix-build-for-linux-6.12rc2.patch # telephony pushd feeds/telephony @@ -61,7 +61,7 @@ pushd feeds/telephony popd # routing - batman-adv fix build with linux-6.12 -curl -s https://$mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch > feeds/routing/batman-adv/patches/901-fix-linux-6.12rc2-builds.patch +curl -s $mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch > feeds/routing/batman-adv/patches/901-fix-linux-6.12rc2-builds.patch # bcm53xx if [ "$platform" = "bcm53xx" ]; then @@ -76,12 +76,12 @@ if [ "$KERNEL_CLANG_LTO" = "y" ]; then git clone https://$github/sbwml/kmod_packages_net_xtables-addons feeds/packages/net/xtables-addons # netatop sed -i 's/$(MAKE)/$(KERNEL_MAKE)/g' feeds/packages/admin/netatop/Makefile - curl -s https://$mirror/openwrt/patch/packages-patches/clang/netatop/900-fix-build-with-clang.patch > feeds/packages/admin/netatop/patches/900-fix-build-with-clang.patch + curl -s $mirror/openwrt/patch/packages-patches/clang/netatop/900-fix-build-with-clang.patch > feeds/packages/admin/netatop/patches/900-fix-build-with-clang.patch # dmx_usb_module rm -rf feeds/packages/libs/dmx_usb_module git clone https://$gitea/sbwml/feeds_packages_libs_dmx_usb_module feeds/packages/libs/dmx_usb_module # macremapper - curl -s https://$mirror/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch | patch -p1 + curl -s $mirror/openwrt/patch/packages-patches/clang/macremapper/100-macremapper-fix-clang-build.patch | patch -p1 # coova-chilli module rm -rf feeds/packages/net/coova-chilli git clone https://$github/sbwml/kmod_packages_net_coova-chilli feeds/packages/net/coova-chilli diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 252f974e5..f052fd798 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,7 +1,7 @@ #!/bin/bash # apk-tools -curl -s https://$mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch +curl -s $mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile @@ -49,16 +49,16 @@ fi # fix gcc-15 if [ "$USE_GCC15" = y ]; then # Mbedtls - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch > package/libs/mbedtls/patches/901-tests-fix-string-initialization-error-on-gcc15.patch + curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch > package/libs/mbedtls/patches/901-tests-fix-string-initialization-error-on-gcc15.patch sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile # elfutils - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch + curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch # libwebsockets mkdir -p feeds/packages/libs/libwebsockets/patches - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libwebsockets/patches/901-fix-string-initialization-error-on-gcc15.patch + curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libwebsockets/patches/901-fix-string-initialization-error-on-gcc15.patch # libxcrypt mkdir -p feeds/packages/libs/libxcrypt/patches - curl -s https://$mirror/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libxcrypt/patches/901-fix-string-initialization-error-on-gcc15.patch + curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libxcrypt/patches/901-fix-string-initialization-error-on-gcc15.patch fi # ksmbd luci @@ -70,20 +70,20 @@ sed -i 's/bind interfaces only = yes/bind interfaces only = no/g' feeds/packages # vim - fix E1187: Failed to source defaults.vim pushd feeds/packages - curl -s https://$mirror/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch | patch -p1 + curl -s $mirror/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch | patch -p1 popd # perf -curl -s https://$mirror/openwrt/patch/openwrt-6.x/musl/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch > toolchain/musl/patches/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch +curl -s $mirror/openwrt/patch/openwrt-6.x/musl/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch > toolchain/musl/patches/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch if [ "$KERNEL_CLANG_LTO" = "y" ]; then - curl -s https://$mirror/openwrt/patch/openwrt-6.x/perf/Makefile.2 > package/devel/perf/Makefile + curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile.2 > package/devel/perf/Makefile else - curl -s https://$mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Makefile + curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Makefile fi [ "$ENABLE_MOLD" != y ] && sed -i 's/no-mold//g' package/devel/perf/Makefile # kselftests-bpf -curl -s https://$mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package/devel/kselftests-bpf/Makefile +curl -s $mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package/devel/kselftests-bpf/Makefile # bcm53xx if [ "$platform" = "bcm53xx" ]; then From dccda2f1702c8b537d89bf00538f12b0b46983be Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 19 Nov 2024 23:32:05 +0800 Subject: [PATCH 139/425] rtl8812au: use rtw88-8812au/8821au to replace the old driver Signed-off-by: sbwml --- openwrt/build.sh | 12 ++++++++---- openwrt/scripts/01-prepare_base-mainline.sh | 8 +------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 8670dc2a0..b1b16e60a 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -420,7 +420,8 @@ if [ "$platform" = "x86_64" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/x86_64/base/*natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true cp -a bin/packages/x86_64/base/*numa*.ipk $kmodpkg_name/ || true @@ -461,7 +462,8 @@ elif [ "$platform" = "armv8" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/armsr/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true @@ -492,7 +494,8 @@ elif [ "$platform" = "bcm53xx" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/bcm53xx/generic/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/arm_cortex-a9/base/*natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/natflow*.ipk $kmodpkg_name/ bash kmod-sign $kmodpkg_name tar zcf bcm53xx-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -524,7 +527,8 @@ else if [ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ]; then cp -a bin/targets/rockchip/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/aarch64_generic/base/*natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 46d15840f..cc5d527f6 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -163,16 +163,10 @@ curl -s https://init2.cooluc.com/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3- curl -s https://init2.cooluc.com/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch > package/network/utils/iproute2/patches/901-ip-introduce-the-ecn_low-per-route-feature.patch curl -s https://init2.cooluc.com/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch > package/network/utils/iproute2/patches/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch -# linux-firmware: rtw89 / rtl8723d / rtl8821c /i915 firmware +# linux-firmware rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware -# rtl8812au-ct - fix linux-6.12 -rm -rf package/kernel/rtl8812au-ct -git clone https://$github/sbwml/package_kernel_rtl8812au-ct package/kernel/rtl8812au-ct -b v6.11 -# add rtl8812au-ac -git clone https://$github/sbwml/package_kernel_rtl8812au-ac package/kernel/rtl8812au-ac -b v6.11 - # mt76 - 2024-10-11 mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch From 0b097fbc54a6e3a4893ce458412941cb860f1025 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 19 Nov 2024 23:58:46 +0800 Subject: [PATCH 140/425] build.sh: fix build for sbwml/builder Signed-off-by: sbwml --- openwrt/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index b1b16e60a..d8cc944d8 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -35,8 +35,8 @@ else export mirror=https://init2.cooluc.com fi -# github actions - automatically retrieve `github raw` links -if [ "$(whoami)" = "runner" ]; then +# github actions - caddy server +if [ "$(whoami)" = "runner" ] && [ -z "$git_password" ]; then export mirror=http://127.0.0.1:8080 fi From e1aee1fe0ceae2208f81acb95ae7d1d7a4e3972e Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 20 Nov 2024 00:06:21 +0800 Subject: [PATCH 141/425] build.sh: add rtl8821a-firmware to opkg source Signed-off-by: sbwml --- openwrt/build.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index d8cc944d8..bdabe708b 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -420,7 +420,7 @@ if [ "$platform" = "x86_64" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/x86_64/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/x86_64/base/natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true @@ -462,7 +462,7 @@ elif [ "$platform" = "armv8" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/armsr/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/aarch64_generic/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true @@ -494,7 +494,7 @@ elif [ "$platform" = "bcm53xx" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/bcm53xx/generic/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/arm_cortex-a9/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/arm_cortex-a9/base/natflow*.ipk $kmodpkg_name/ bash kmod-sign $kmodpkg_name tar zcf bcm53xx-$kmodpkg_name.tar.gz $kmodpkg_name @@ -527,7 +527,7 @@ else if [ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ]; then cp -a bin/targets/rockchip/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/aarch64_generic/base/rtl8812a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true From 9c5949dbffe65a1cf836c75b77eff260beae054c Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 20 Nov 2024 01:37:50 +0800 Subject: [PATCH 142/425] config: add rtw88-8812au/8821au/8822bu usb wifi driver Signed-off-by: sbwml --- openwrt/24-config-common | 3 +++ openwrt/24-config-minimal-common | 3 +++ 2 files changed, 6 insertions(+) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index a4e1711c4..2d3ddbc65 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -225,6 +225,9 @@ CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y ### Kernel Modules - USB WiFi Adapter CONFIG_PACKAGE_kmod-mt7921u=y +CONFIG_PACKAGE_kmod-rtw88-8812au=y +CONFIG_PACKAGE_kmod-rtw88-8821au=y +CONFIG_PACKAGE_kmod-rtw88-8822bu=y ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index 20c1e3223..fda544bf9 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -153,6 +153,9 @@ CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y ### Kernel Modules - USB WiFi Adapter CONFIG_PACKAGE_kmod-mt7921u=y +CONFIG_PACKAGE_kmod-rtw88-8812au=y +CONFIG_PACKAGE_kmod-rtw88-8821au=y +CONFIG_PACKAGE_kmod-rtw88-8822bu=y ### Utilities CONFIG_PACKAGE_bash=y From 5be15c0f5d79976bdc413eeeaa1fd4ff5a597ca2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 20 Nov 2024 12:23:31 +0800 Subject: [PATCH 143/425] config: skip build kmod-rtl8812au-ct Signed-off-by: sbwml --- openwrt/24-config-common | 1 + openwrt/24-config-minimal-common | 1 + 2 files changed, 2 insertions(+) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 2d3ddbc65..a5f4d450f 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -228,6 +228,7 @@ CONFIG_PACKAGE_kmod-mt7921u=y CONFIG_PACKAGE_kmod-rtw88-8812au=y CONFIG_PACKAGE_kmod-rtw88-8821au=y CONFIG_PACKAGE_kmod-rtw88-8822bu=y +# CONFIG_PACKAGE_ kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index fda544bf9..ee66ac95d 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -156,6 +156,7 @@ CONFIG_PACKAGE_kmod-mt7921u=y CONFIG_PACKAGE_kmod-rtw88-8812au=y CONFIG_PACKAGE_kmod-rtw88-8821au=y CONFIG_PACKAGE_kmod-rtw88-8822bu=y +# CONFIG_PACKAGE_ kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y From 763b00375e3c438dd1e4e9fddbe8e1f88929b562 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 21 Nov 2024 20:34:20 +0800 Subject: [PATCH 144/425] config: fixup 5be15c0f5d79976bdc413eeeaa1fd4ff5a597ca2 Signed-off-by: sbwml --- openwrt/24-config-common | 2 +- openwrt/24-config-minimal-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index a5f4d450f..17ab87112 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -228,7 +228,7 @@ CONFIG_PACKAGE_kmod-mt7921u=y CONFIG_PACKAGE_kmod-rtw88-8812au=y CONFIG_PACKAGE_kmod-rtw88-8821au=y CONFIG_PACKAGE_kmod-rtw88-8822bu=y -# CONFIG_PACKAGE_ kmod-rtl8812au-ct is not set +# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index ee66ac95d..7cad92913 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -156,7 +156,7 @@ CONFIG_PACKAGE_kmod-mt7921u=y CONFIG_PACKAGE_kmod-rtw88-8812au=y CONFIG_PACKAGE_kmod-rtw88-8821au=y CONFIG_PACKAGE_kmod-rtw88-8822bu=y -# CONFIG_PACKAGE_ kmod-rtl8812au-ct is not set +# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y From d8cfd545c2ab26c94482f72168612b0d976c99f7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 23 Nov 2024 07:06:07 +0800 Subject: [PATCH 145/425] linux-6.12: bump to 6.12.1 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 933cdd68f..95eed4678 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = -LINUX_KERNEL_HASH-6.12 = b1a2562be56e42afb3f8489d4c2a7ac472ac23098f1ef1c1e40da601f54625eb +LINUX_VERSION-6.12 = .1 +LINUX_KERNEL_HASH-6.12.1 = 0193b1d86dd372ec891bae799f6da20deef16fc199f30080a4ea9de8cef0c619 From 3c6441446927c306b1bed60935bb1bad889a9490 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 24 Nov 2024 09:25:22 +0800 Subject: [PATCH 146/425] script: unify use $mirror url Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 2 +- openwrt/scripts/01-prepare_base-mainline.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 85dc04217..69f1e8d56 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -99,7 +99,7 @@ git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe # dnsmasq if [ "$version" = "dev" ]; then curl -s $mirror/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch | patch -p1 - [ "$?" -ne 0 ] && curl -s https://init2.cooluc.com/openwrt/patch/dnsmasq/dnsmasq.init > package/network/services/dnsmasq/files/dnsmasq.init + [ "$?" -ne 0 ] && curl -s $mirror/openwrt/patch/dnsmasq/dnsmasq.init > package/network/services/dnsmasq/files/dnsmasq.init fi # Patch FireWall 4 diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index cc5d527f6..0c715ecd6 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -159,9 +159,9 @@ pushd target/linux/generic/hack-6.12 popd # iproute2 - bbr3 -curl -s https://init2.cooluc.com/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch > package/network/utils/iproute2/patches/900-ss-output-TCP-BBRv3-diag-information.patch -curl -s https://init2.cooluc.com/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch > package/network/utils/iproute2/patches/901-ip-introduce-the-ecn_low-per-route-feature.patch -curl -s https://init2.cooluc.com/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch > package/network/utils/iproute2/patches/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch +curl -s $mirror/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch > package/network/utils/iproute2/patches/900-ss-output-TCP-BBRv3-diag-information.patch +curl -s $mirror/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch > package/network/utils/iproute2/patches/901-ip-introduce-the-ecn_low-per-route-feature.patch +curl -s $mirror/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch > package/network/utils/iproute2/patches/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch # linux-firmware rm -rf package/firmware/linux-firmware From 0b78b513c731cfb5312f3e7b8e6e90b84fc98971 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 25 Nov 2024 21:07:35 +0800 Subject: [PATCH 147/425] rockchip: drop FriendlyElec pwn-fan controller * Will be replaced by private pwm-fan controller program. Signed-off-by: sbwml --- openwrt/patch/FriendlyWrt/fa-fancontrol.tar.gz | Bin 1432 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 openwrt/patch/FriendlyWrt/fa-fancontrol.tar.gz diff --git a/openwrt/patch/FriendlyWrt/fa-fancontrol.tar.gz b/openwrt/patch/FriendlyWrt/fa-fancontrol.tar.gz deleted file mode 100644 index deaf6b03ca3387806cafda7ed71a25fbea585a4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1432 zcmV;J1!wvniwFR$dthP!1MOLDZ_`K+?$`KN3?WzA6N%rGgDNL+ZIO_mS3!_K2&JyQ zX{>W>W3MT_DF6Lt)-TN~PEk{IVjn5CWADr}>zSRIO&E98y&XeC^m;a(^`33bpG)lN zmSN&3TQhrmnyz;ZV-M_I8%D@d?j!(vQOv^Ygl`;I_xyhfhW__MpLe|7g~1*CZ|RnX z{>MvQ`u`y?=l_w@9yy^Kg*=IZ`{bzeziur1-?nV@zjmKSY{D<@|HqHiOFvZ8F{l&@ ziQ93b$s`ID<=x=L+d<#Z6?#GZ;1H$?Ak-{Pgvdg;bWp**GEX;Rv;U9e zf5Wn5{eKWt{(ooayD9*=|9ji}-_R}F+ykT2*?DdH)%{P|eAgUzU;ld7mh1mPP*(F@ za@@uLwrPv}Z%Y3^2ulCEamLvs#y;-;IqLl1v&^OSZ;ARZ`~Tge=>IRBbgU@XV?SWP zlZ+`|q%e0JL9@M#X7S)SOA;6*?8|ewa2*b6dXuUi`|7(arE3f)iYoeObfBSh_QO#$ zbhBhgH!hym$y%FbOG^eAxbsH1fs>{xAG2iQ1m$`7Zxk|3r65N^e*~YP?JW|=fx|~p zGEw8}3AG#W`3O)t6#Jgz_iy{Fwtn>!p52nDZWIN6cs0zQXH8|~D`~)33^sZ(WZ&PCt=-MFJwIVCzprFa zv;IvDi~ZvI@AkTK{XYm6*8gMh7{?g&Lk1N8MK}a3`GEzKhiM$7kfm(%&jy`lKKh%_ zL8sWwsUB5i`D#W6`nY31*4NPRv7f>u@>l>~#8L<&4rvz0QNjVmR!C|&=t5g1(%{dH z66_n%-7Y`9$fw&8QN|^jQdTV8SMN^GUi|g?w7;C(Ry3$AbS?wT5MpMnQV`ng3#@rz z-*O35&?baS4OA1IKYjB_-`2*g}tG($V}w91T1kE{;FHo}8erV^W1eI*l{L z3p2&hvW1MYmZB#px`M(M6n0LrnINB?X;-@Qm$k@n&Jve}JhumWHo6dB%b{|@Mot!R z($}}1p;&pR63~_#fd&=Le(PZC0(+=5UY(tsen3@?mw&%MI~kn5Ij1it?*||ItvM5v z#`)>nWcJdMKq>4G~1CqAp@F)e3MJfW1<5K-A8 z`R$|fND=Fm@VHEKqSFyme+o46d9L&+nq3$$`>i=AR?}SlzOlJNoAVWAq(@t{5fcAX zY%0t5$x+k)8Ctiu{Qr-w_hkR~5ZGP+ci?*8-{vgT4cOm@X_>dG1QtYBS1f^cOg&`M zp$r9Wj$P&T1nHX4Oc^IevefgrAB8DU(V&Nw6101Swakx)apZ@5Xbwf`_$(-^QF*>h zS%4cKG5LTtSJ;Tn4_N4hR#a9)XB)Y#yKozAYYn@-!fvf&pB*aOxnXIyxoFwo<9X41 z@|(EWe-iRiNl&2!xHNKPybB Date: Wed, 27 Nov 2024 21:20:17 +0800 Subject: [PATCH 148/425] script: add wwan packages Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index c5fc1b244..1527cbe60 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -11,6 +11,9 @@ git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages # default settings git clone https://$github/sbwml/default-settings package/new/default-settings -b openwrt-24.10 +# wwan +git clone https://github.com/sbwml/wwan-packages package/new/wwan + # luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager From 13d60c78ee949ced1ca640dc4ee54e2e285acaaa Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 29 Nov 2024 06:40:17 +0800 Subject: [PATCH 149/425] fix config-gcc15 Signed-off-by: sbwml --- openwrt/build.sh | 8 +++++--- openwrt/generic/config-gcc13 | 5 ----- openwrt/generic/config-gcc14 | 5 ----- openwrt/generic/config-gcc15 | 5 ----- 4 files changed, 5 insertions(+), 18 deletions(-) delete mode 100644 openwrt/generic/config-gcc13 delete mode 100644 openwrt/generic/config-gcc14 delete mode 100644 openwrt/generic/config-gcc15 diff --git a/openwrt/build.sh b/openwrt/build.sh index bdabe708b..8ba655b06 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -335,10 +335,12 @@ fi # gcc15 patches [ "$(whoami)" = "runner" ] && group "patching toolchain" curl -s $mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 + # gcc config -[ "$USE_GCC13" = "y" ] && curl -s $mirror/openwrt/generic/config-gcc13 >> .config -[ "$USE_GCC14" = "y" ] && curl -s $mirror/openwrt/generic/config-gcc14 >> .config -[ "$USE_GCC15" = "y" ] && curl -s $mirror/openwrt/generic/config-gcc15 >> .config +echo -e "\n# gcc ${gcc_version}" >> .config +echo -e "CONFIG_DEVEL=y" >> .config +echo -e "CONFIG_TOOLCHAINOPTS=y" >> .config +echo -e "CONFIG_GCC_USE_VERSION_${gcc_version}=y\n" >> .config [ "$(whoami)" = "runner" ] && endgroup # uhttpd diff --git a/openwrt/generic/config-gcc13 b/openwrt/generic/config-gcc13 deleted file mode 100644 index 6e1fa77cb..000000000 --- a/openwrt/generic/config-gcc13 +++ /dev/null @@ -1,5 +0,0 @@ - -# gcc 13 -CONFIG_DEVEL=y -CONFIG_TOOLCHAINOPTS=y -CONFIG_GCC_USE_VERSION_13=y diff --git a/openwrt/generic/config-gcc14 b/openwrt/generic/config-gcc14 deleted file mode 100644 index 94a2a5790..000000000 --- a/openwrt/generic/config-gcc14 +++ /dev/null @@ -1,5 +0,0 @@ - -# gcc 14 -CONFIG_DEVEL=y -CONFIG_TOOLCHAINOPTS=y -CONFIG_GCC_USE_VERSION_14=y diff --git a/openwrt/generic/config-gcc15 b/openwrt/generic/config-gcc15 deleted file mode 100644 index 5bdeab420..000000000 --- a/openwrt/generic/config-gcc15 +++ /dev/null @@ -1,5 +0,0 @@ - -# gcc 15 -CONFIG_DEVEL=y -CONFIG_TOOLCHAINOPTS=y -CONFIG_GCC_USE_VERSION_15=y From 9693e23687df62a0e83e710162760e99d56d08f5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 29 Nov 2024 19:55:14 +0800 Subject: [PATCH 150/425] x86: fix tickless issue for older Intel CPUs Signed-off-by: sbwml --- .../x86/base-files/etc/init.d/scaling_governor | 15 +++++++++++++++ openwrt/patch/openwrt-6.x/x86/config-6.12 | 4 ++-- openwrt/scripts/00-prepare_base.sh | 4 ++-- openwrt/scripts/01-prepare_base-mainline.sh | 4 ++++ 4 files changed, 23 insertions(+), 4 deletions(-) create mode 100755 openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor diff --git a/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor b/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor new file mode 100755 index 000000000..5b8d1b662 --- /dev/null +++ b/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor @@ -0,0 +1,15 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=15 + +boot() { + [ ! -f /sys/devices/system/cpu/intel_pstate/status ] && return 1 + + if [ "$(cat /sys/devices/system/cpu/intel_pstate/status)" = "passive" ]; then + for i in $(find /sys/devices/system/cpu/cpu* -maxdepth 0 | grep -Eo '[0-9]+') + do + echo "ondemand" > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor + done + fi +} diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.12 b/openwrt/patch/openwrt-6.x/x86/config-6.12 index 865242a61..76af18e88 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.12 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.12 @@ -47,7 +47,7 @@ CONFIG_COMPAT_32BIT_TIME=y CONFIG_COMPAT_32=y # CONFIG_COMPAT_VDSO is not set CONFIG_CONSOLE_TRANSLATIONS=y -CONFIG_CONTEXT_TRACKING_USER_FORCE=y +# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set # CONFIG_CPU5_WDT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set @@ -364,7 +364,7 @@ CONFIG_RANDSTRUCT_NONE=y CONFIG_RATIONAL=y # CONFIG_RCU_LAZY_DEFAULT_OFF is not set CONFIG_RCU_LAZY=y -CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y +# CONFIG_RCU_NOCB_CPU_DEFAULT_ALL is not set CONFIG_RD_BZIP2=y CONFIG_RD_GZIP=y CONFIG_RETHUNK=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 69f1e8d56..5e112255c 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -24,8 +24,8 @@ curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-f rm -rf tools/dwarves git clone https://$github/sbwml/tools_dwarves tools/dwarves -# x86 - disable intel_pstate & mitigations -sed -i 's/noinitrd/noinitrd intel_pstate=disable mitigations=off/g' target/linux/x86/image/grub-efi.cfg +# x86 - disable mitigations +sed -i 's/noinitrd/noinitrd mitigations=off/g' target/linux/x86/image/grub-efi.cfg # default LAN IP sed -i "s/192.168.1.1/$LAN/g" package/base-files/files/bin/config_generate diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 0c715ecd6..a0e09dc30 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -18,11 +18,15 @@ curl -s $mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/con mkdir -p target/linux/x86/patches-6.12 curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.12/100-fix_cs5535_clockevt.patch curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.12/103-pcengines_apu6_platform.patch + # x86_64 - target sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.12/" target/linux/x86/Makefile sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network +mkdir -p target/linux/x86/base-files/etc/init.d +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor > target/linux/x86/base-files/etc/init.d/scaling_governor +chmod 755 target/linux/x86/base-files/etc/init.d/scaling_governor # bcm53xx - target rm -rf target/linux/bcm53xx From bf64100b2210a8ca9c6ec3e82af06d22f969306e Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 29 Nov 2024 20:23:47 +0800 Subject: [PATCH 151/425] x86: enable scaling_governor Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index a0e09dc30..c7b8d4449 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -24,9 +24,10 @@ sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.12/" target/linux/x86/Makefile sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network -mkdir -p target/linux/x86/base-files/etc/init.d +mkdir -p target/linux/x86/base-files/etc/{init.d,rc.d} curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor > target/linux/x86/base-files/etc/init.d/scaling_governor chmod 755 target/linux/x86/base-files/etc/init.d/scaling_governor +ln -sf ../init.d/scaling_governor target/linux/x86/base-files/etc/rc.d/S15scaling_governor # bcm53xx - target rm -rf target/linux/bcm53xx From d62b2d8b1f96ee331d5ae298f3ab3d885aad7b7f Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 29 Nov 2024 20:28:48 +0800 Subject: [PATCH 152/425] docs: udpate github raw url Signed-off-by: sbwml --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4ed6c10a6..bfc40f0f3 100644 --- a/README.md +++ b/README.md @@ -197,16 +197,16 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 ### 二、修改构建脚本文件:`openwrt/build.sh`(使用 Github Actions 构建时无需更改) -将 init.cooluc.com 脚本默认连接替换为你的 github raw 连接(不带 https://),像这样 `raw.githubusercontent.com/你的用户名/r4s_build_script/master` +将 init.cooluc.com 脚本默认连接替换为你的 github raw 连接,像这样 `https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master` ```diff # script url if [ "$isCN" = "CN" ]; then -- export mirror=init.cooluc.com -+ export mirror=raw.githubusercontent.com/你的用户名/r4s_build_script/master +- export mirror=https://init.cooluc.com ++ export mirror=https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master else -- export mirror=init2.cooluc.com -+ export mirror=raw.githubusercontent.com/你的用户名/r4s_build_script/master +- export mirror=https://init2.cooluc.com ++ export mirror=https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master fi ``` @@ -215,19 +215,19 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 #### nanopi-r4s openwrt-24.10 ```shell # linux-6.12 -bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/master/openwrt/build.sh) rc2 nanopi-r4s +bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 nanopi-r4s ``` #### nanopi-r5s/r5c openwrt-24.10 ```shell # linux-6.12 -bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/master/openwrt/build.sh) rc2 nanopi-r5s +bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 nanopi-r5s ``` #### x86_64 openwrt-24.10 ```shell # linux-6.12 -bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/master/openwrt/build.sh) rc2 x86_64 +bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 x86_64 ``` ----------------- From a938266a044ec0c019d2e918695102da697c1c78 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 30 Nov 2024 21:20:03 +0800 Subject: [PATCH 153/425] Revert "x86: enable scaling_governor" This reverts commit bf64100b2210a8ca9c6ec3e82af06d22f969306e. --- openwrt/scripts/01-prepare_base-mainline.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index c7b8d4449..a0e09dc30 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -24,10 +24,9 @@ sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.12/" target/linux/x86/Makefile sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network -mkdir -p target/linux/x86/base-files/etc/{init.d,rc.d} +mkdir -p target/linux/x86/base-files/etc/init.d curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor > target/linux/x86/base-files/etc/init.d/scaling_governor chmod 755 target/linux/x86/base-files/etc/init.d/scaling_governor -ln -sf ../init.d/scaling_governor target/linux/x86/base-files/etc/rc.d/S15scaling_governor # bcm53xx - target rm -rf target/linux/bcm53xx From 69f4bc7390a1f2d6484ca365ab07c0a374a1fdc8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 30 Nov 2024 21:20:12 +0800 Subject: [PATCH 154/425] Revert "x86: fix tickless issue for older Intel CPUs" This reverts commit 9693e23687df62a0e83e710162760e99d56d08f5. * The problem has been fixed since linux 6.12 --- .../x86/base-files/etc/init.d/scaling_governor | 15 --------------- openwrt/patch/openwrt-6.x/x86/config-6.12 | 4 ++-- openwrt/scripts/00-prepare_base.sh | 4 ++-- openwrt/scripts/01-prepare_base-mainline.sh | 4 ---- 4 files changed, 4 insertions(+), 23 deletions(-) delete mode 100755 openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor diff --git a/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor b/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor deleted file mode 100755 index 5b8d1b662..000000000 --- a/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2006 OpenWrt.org - -START=15 - -boot() { - [ ! -f /sys/devices/system/cpu/intel_pstate/status ] && return 1 - - if [ "$(cat /sys/devices/system/cpu/intel_pstate/status)" = "passive" ]; then - for i in $(find /sys/devices/system/cpu/cpu* -maxdepth 0 | grep -Eo '[0-9]+') - do - echo "ondemand" > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor - done - fi -} diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.12 b/openwrt/patch/openwrt-6.x/x86/config-6.12 index 76af18e88..865242a61 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.12 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.12 @@ -47,7 +47,7 @@ CONFIG_COMPAT_32BIT_TIME=y CONFIG_COMPAT_32=y # CONFIG_COMPAT_VDSO is not set CONFIG_CONSOLE_TRANSLATIONS=y -# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set +CONFIG_CONTEXT_TRACKING_USER_FORCE=y # CONFIG_CPU5_WDT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set @@ -364,7 +364,7 @@ CONFIG_RANDSTRUCT_NONE=y CONFIG_RATIONAL=y # CONFIG_RCU_LAZY_DEFAULT_OFF is not set CONFIG_RCU_LAZY=y -# CONFIG_RCU_NOCB_CPU_DEFAULT_ALL is not set +CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y CONFIG_RD_BZIP2=y CONFIG_RD_GZIP=y CONFIG_RETHUNK=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 5e112255c..69f1e8d56 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -24,8 +24,8 @@ curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-f rm -rf tools/dwarves git clone https://$github/sbwml/tools_dwarves tools/dwarves -# x86 - disable mitigations -sed -i 's/noinitrd/noinitrd mitigations=off/g' target/linux/x86/image/grub-efi.cfg +# x86 - disable intel_pstate & mitigations +sed -i 's/noinitrd/noinitrd intel_pstate=disable mitigations=off/g' target/linux/x86/image/grub-efi.cfg # default LAN IP sed -i "s/192.168.1.1/$LAN/g" package/base-files/files/bin/config_generate diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index a0e09dc30..0c715ecd6 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -18,15 +18,11 @@ curl -s $mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/con mkdir -p target/linux/x86/patches-6.12 curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.12/100-fix_cs5535_clockevt.patch curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.12/103-pcengines_apu6_platform.patch - # x86_64 - target sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.12/" target/linux/x86/Makefile sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network -mkdir -p target/linux/x86/base-files/etc/init.d -curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/init.d/scaling_governor > target/linux/x86/base-files/etc/init.d/scaling_governor -chmod 755 target/linux/x86/base-files/etc/init.d/scaling_governor # bcm53xx - target rm -rf target/linux/bcm53xx From e725c854e9d429dd4058be28cd1fdc3898ee44de Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 30 Nov 2024 21:23:11 +0800 Subject: [PATCH 155/425] x86: re-enable `intel_pstate` cpu performance scaling driver Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/x86/config-6.12 | 4 ++-- openwrt/scripts/00-prepare_base.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.12 b/openwrt/patch/openwrt-6.x/x86/config-6.12 index 865242a61..76af18e88 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.12 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.12 @@ -47,7 +47,7 @@ CONFIG_COMPAT_32BIT_TIME=y CONFIG_COMPAT_32=y # CONFIG_COMPAT_VDSO is not set CONFIG_CONSOLE_TRANSLATIONS=y -CONFIG_CONTEXT_TRACKING_USER_FORCE=y +# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set # CONFIG_CPU5_WDT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set @@ -364,7 +364,7 @@ CONFIG_RANDSTRUCT_NONE=y CONFIG_RATIONAL=y # CONFIG_RCU_LAZY_DEFAULT_OFF is not set CONFIG_RCU_LAZY=y -CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y +# CONFIG_RCU_NOCB_CPU_DEFAULT_ALL is not set CONFIG_RD_BZIP2=y CONFIG_RD_GZIP=y CONFIG_RETHUNK=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 69f1e8d56..5e112255c 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -24,8 +24,8 @@ curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-f rm -rf tools/dwarves git clone https://$github/sbwml/tools_dwarves tools/dwarves -# x86 - disable intel_pstate & mitigations -sed -i 's/noinitrd/noinitrd intel_pstate=disable mitigations=off/g' target/linux/x86/image/grub-efi.cfg +# x86 - disable mitigations +sed -i 's/noinitrd/noinitrd mitigations=off/g' target/linux/x86/image/grub-efi.cfg # default LAN IP sed -i "s/192.168.1.1/$LAN/g" package/base-files/files/bin/config_generate From 80a39c2843538ccbeb370b36292fcb91b51677ec Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 1 Dec 2024 16:05:51 +0800 Subject: [PATCH 156/425] grub2: drop obsolete change * It has been fixed upstream Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index f052fd798..01b0f1802 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -6,9 +6,6 @@ curl -s $mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile -# grub2 - disable `gc-sections` flag -sed -i '/PKG_BUILD_FLAGS/ s/$/ no-gc-sections/' package/boot/grub2/Makefile - # haproxy - fix build with quictls sed -i '/USE_QUIC_OPENSSL_COMPAT/d' feeds/packages/net/haproxy/Makefile From 7fc2f5521554dc4be08fccb9dfee67a1bc49c9c5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 2 Dec 2024 09:11:24 +0800 Subject: [PATCH 157/425] OpenWrt 24.10.0-rc1 Signed-off-by: sbwml --- .github/workflows/build-release.yml | 4 +- openwrt/build.sh | 3 -- openwrt/patch/openwrt-6.x/modules/crypto.mk | 9 ++++ openwrt/patch/openwrt-6.x/modules/iio.mk | 32 ++++++++++++++ .../patch/openwrt-6.x/modules/netsupport.mk | 18 ++++++++ openwrt/patch/openwrt-6.x/modules/other.mk | 1 + openwrt/patch/openwrt-6.x/modules/sound.mk | 11 +++++ openwrt/patch/openwrt-6.x/modules/usb.mk | 1 + openwrt/patch/openwrt-6.x/modules/video.mk | 44 ++++++++++++++++++- tags/v24 | 1 + 10 files changed, 117 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 442602511..311f92e50 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,10 +17,10 @@ on: version: description: 'Select the build version' required: true - default: 'snapshot-24.10' + default: 'release' type: choice options: - # - 'release' + - 'release' - 'snapshot-24.10' ccache: description: 'Enable ccache (Use Cache to speed up next build)' diff --git a/openwrt/build.sh b/openwrt/build.sh index 8ba655b06..d60820239 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -84,8 +84,6 @@ if [ -z "$1" ] || [ "$2" != "nanopi-r4s" -a "$2" != "nanopi-r5s" -a "$2" != "x86 exit 1 fi -[ "$1" = "rc2" ] && echo -e "\n${RED_COLOR}openwrt-24.10 release build is not available yet.${RES}\n" && exit 0 - # Source branch if [ "$1" = "dev" ]; then export branch=openwrt-24.10 @@ -177,7 +175,6 @@ git clone https://$github/immortalwrt/packages master/immortalwrt_packages --dep if [ -d openwrt ]; then cd openwrt - echo "1730409337" > version.date # OpenWrt v24.10: set branch defaults curl -Os $mirror/openwrt/patch/key.tar.gz && tar zxf key.tar.gz && rm -f key.tar.gz else echo -e "${RED_COLOR}Failed to download source code${RES}" diff --git a/openwrt/patch/openwrt-6.x/modules/crypto.mk b/openwrt/patch/openwrt-6.x/modules/crypto.mk index ce2216354..2257a36c8 100644 --- a/openwrt/patch/openwrt-6.x/modules/crypto.mk +++ b/openwrt/patch/openwrt-6.x/modules/crypto.mk @@ -249,6 +249,15 @@ endef $(eval $(call KernelPackage,crypto-echainiv)) +define KernelPackage/crypto-engine + TITLE:=Crypto engine + KCONFIG:=CONFIG_CRYPTO_ENGINE + FILES:=$(LINUX_DIR)/crypto/crypto_engine.ko + AUTOLOAD:=$(call AutoLoad,09,crypto_engine) + $(call AddDepends/crypto, +kmod-crypto-rsa +kmod-crypto-kpp) +endef + +$(eval $(call KernelPackage,crypto-engine)) define KernelPackage/crypto-essiv TITLE:=ESSIV support for block encryption diff --git a/openwrt/patch/openwrt-6.x/modules/iio.mk b/openwrt/patch/openwrt-6.x/modules/iio.mk index 053f61c8b..531c8207d 100644 --- a/openwrt/patch/openwrt-6.x/modules/iio.mk +++ b/openwrt/patch/openwrt-6.x/modules/iio.mk @@ -46,6 +46,38 @@ endef $(eval $(call KernelPackage,iio-kfifo-buf)) +define KernelPackage/industrialio-hw-consumer + TITLE:=Provides a bonding way to an other device in hardware + KCONFIG:=CONFIG_IIO_BUFFER_HW_CONSUMER + FILES:=$(LINUX_DIR)/drivers/iio/buffer/industrialio-hw-consumer.ko + AUTOLOAD:=$(call AutoLoad,55,industrialio-hw-consumer) + $(call AddDepends/iio,+kmod-iio-kfifo-buf) +endef + +define KernelPackage/industrialio-hw-consumer/description + Provides a way to bonding when an IIO device has a direct connection + to another device in hardware. In this case buffers for data transfers + are handled by hardware. +endef + +$(eval $(call KernelPackage,industrialio-hw-consumer)) + + +define KernelPackage/industrialio-buffer-cb + TITLE:=Provides callback buffer used for push in-kernel interfaces + KCONFIG:=CONFIG_IIO_BUFFER_CB + FILES:=$(LINUX_DIR)/drivers/iio/buffer/industrialio-buffer-cb.ko + AUTOLOAD:=$(call AutoLoad,55,industrialio-triggered-buffer-cb) + $(call AddDepends/iio) +endef + +define KernelPackage/industrialio-buffer-cb/description + Should be selected by any drivers that do in-kernel push usage. +endef + +$(eval $(call KernelPackage,industrialio-buffer-cb)) + + define KernelPackage/industrialio-triggered-buffer TITLE:=Provides helper functions for setting up triggered buffers. DEPENDS:=+kmod-iio-kfifo-buf diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index 1e2591571..49721b151 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -42,6 +42,24 @@ endef $(eval $(call KernelPackage,atmtcp)) +define KernelPackage/appletalk + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Appletalk protocol support + KCONFIG:= \ + CONFIG_ATALK \ + CONFIG_DEV_APPLETALK \ + CONFIG_IPDDP=n + FILES:=$(LINUX_DIR)/net/appletalk/appletalk.ko + AUTOLOAD:=$(call AutoLoad,40,appletalk) +endef + +define KernelPackage/appletalk/description + Kernel module for AppleTalk protocol. +endef + +$(eval $(call KernelPackage,appletalk)) + + define KernelPackage/bonding SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Ethernet bonding driver diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index c77aee327..75ca9e483 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -962,6 +962,7 @@ define KernelPackage/thermal CONFIG_THERMAL=y \ CONFIG_THERMAL_OF=y \ CONFIG_CPU_THERMAL=y \ + CONFIG_DEVFREQ_THERMAL=n \ CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y \ CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE=n \ CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=n \ diff --git a/openwrt/patch/openwrt-6.x/modules/sound.mk b/openwrt/patch/openwrt-6.x/modules/sound.mk index 15f2ddcce..2a33898c8 100644 --- a/openwrt/patch/openwrt-6.x/modules/sound.mk +++ b/openwrt/patch/openwrt-6.x/modules/sound.mk @@ -314,6 +314,17 @@ endef $(eval $(call KernelPackage,sound-soc-spdif)) +define KernelPackage/sound-soc-dmic + TITLE:=Generic Digital Microphone CODEC + KCONFIG:=CONFIG_SND_SOC_DMIC + FILES:=$(LINUX_DIR)/sound/soc/codecs/snd-soc-dmic.ko + AUTOLOAD:=$(call AutoProbe,snd-soc-dmic) + $(call AddDepends/sound,+kmod-sound-soc-core) +endef + +$(eval $(call KernelPackage,sound-soc-dmic)) + + define KernelPackage/pcspkr DEPENDS:=@TARGET_x86 +kmod-input-core TITLE:=PC speaker support diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index 458c8c4ba..734df050c 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -576,6 +576,7 @@ define KernelPackage/usb-audio CONFIG_SND_USB_AUDIO $(call AddDepends/usb) $(call AddDepends/sound) + DEPENDS+=+kmod-media-controller FILES:= \ $(LINUX_DIR)/sound/usb/snd-usbmidi-lib.ko \ $(LINUX_DIR)/sound/usb/snd-usb-audio.ko diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index fdcd99312..4ef3b1643 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -12,6 +12,28 @@ V4L2_DIR=v4l2-core V4L2_USB_DIR=usb V4L2_MEM2MEM_DIR=platform +# +# Media +# +define KernelPackage/media-controller + SUBMENU:=$(VIDEO_MENU) + TITLE:=Media Controller API + KCONFIG:= \ + CONFIG_MEDIA_SUPPORT \ + CONFIG_MEDIA_CONTROLLER=y + FILES:= \ + $(LINUX_DIR)/drivers/media/mc/mc.ko + AUTOLOAD:=$(call AutoProbe,mc) +endef + +define KernelPackage/media-controller/description + Kernel modules for media controller API used to query media devices + internal topology and configure it dynamically. +endef + +$(eval $(call KernelPackage,media-controller)) + + # # Video Display # @@ -692,9 +714,8 @@ $(eval $(call KernelPackage,drm-radeon)) define KernelPackage/video-core SUBMENU:=$(VIDEO_MENU) TITLE=Video4Linux support - DEPENDS:=+PACKAGE_kmod-i2c-core:kmod-i2c-core + DEPENDS:=+PACKAGE_kmod-i2c-core:kmod-i2c-core +kmod-media-controller KCONFIG:= \ - CONFIG_MEDIA_SUPPORT \ CONFIG_MEDIA_CAMERA_SUPPORT=y \ CONFIG_VIDEO_DEV \ CONFIG_V4L_PLATFORM_DRIVERS=y \ @@ -750,6 +771,25 @@ endef $(eval $(call KernelPackage,video-videobuf2)) +define KernelPackage/video-async + TITLE:=V4L2 ASYNC support + KCONFIG:=CONFIG_V4L2_ASYNC + FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/v4l2-async.ko + $(call AddDepends/video) + AUTOLOAD:=$(call AutoProbe,v4l2-async) +endef + +$(eval $(call KernelPackage,video-async)) + +define KernelPackage/video-fwnode + TITLE:=V4L2 FWNODE support + KCONFIG:=CONFIG_V4L2_FWNODE + FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/v4l2-fwnode.ko + $(call AddDepends/video,+kmod-video-async) + AUTOLOAD:=$(call AutoProbe,v4l2-fwnode) +endef + +$(eval $(call KernelPackage,video-fwnode)) define KernelPackage/video-cpia2 TITLE:=CPIA2 video driver diff --git a/tags/v24 b/tags/v24 index e69de29bb..45904e521 100644 --- a/tags/v24 +++ b/tags/v24 @@ -0,0 +1 @@ +24.10.0-rc1 From 6a3d57754ecb3ae5090e544844a528edb9f3386d Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 2 Dec 2024 11:19:04 +0800 Subject: [PATCH 158/425] config: r8500: skip build unsupported modules Signed-off-by: sbwml --- openwrt/24-config-musl-r8500 | 2 ++ openwrt/24-config-musl-r8500-minimal | 2 ++ 2 files changed, 4 insertions(+) diff --git a/openwrt/24-config-musl-r8500 b/openwrt/24-config-musl-r8500 index ad939bf69..32b8129f5 100644 --- a/openwrt/24-config-musl-r8500 +++ b/openwrt/24-config-musl-r8500 @@ -197,6 +197,8 @@ CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-usb-audio=y CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-uas=y +# CONFIG_PACKAGE_kmod-mhi-pcie is not set +# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/24-config-musl-r8500-minimal b/openwrt/24-config-musl-r8500-minimal index f6397bda1..81724f597 100644 --- a/openwrt/24-config-musl-r8500-minimal +++ b/openwrt/24-config-musl-r8500-minimal @@ -149,6 +149,8 @@ CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-uas=y +# CONFIG_PACKAGE_kmod-mhi-pcie is not set +# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y From 83d84c79c316a0a7ac25309fb1f657a4f0d62fd2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 2 Dec 2024 12:27:29 +0800 Subject: [PATCH 159/425] rk3399: rollback the previous uboot & rkbin Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 5e112255c..7f45207ea 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -2,8 +2,13 @@ # Rockchip - rkbin & u-boot rm -rf package/boot/rkbin package/boot/uboot-rockchip package/boot/arm-trusted-firmware-rockchip -git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip -git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip +if [ "$platform" = "rk3568" ]; then + git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip + git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip +else + git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip -b v2023.04 + git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip -b 0419 +fi # patch source curl -s $mirror/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch | patch -p1 From 50d8df456d9fadbffb808becd78e7a71374d1f05 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 3 Dec 2024 10:28:41 +0800 Subject: [PATCH 160/425] config: add bpf module support Signed-off-by: sbwml --- openwrt/24-config-common | 4 ++++ openwrt/24-config-minimal-common | 4 ++++ openwrt/24-config-musl-r8500 | 6 +++++- openwrt/24-config-musl-r8500-minimal | 6 +++++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 17ab87112..e563cde3b 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -208,6 +208,8 @@ CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y CONFIG_PACKAGE_kmod-nls-cp936=y CONFIG_PACKAGE_kmod-nls-cp950=y +CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y CONFIG_PACKAGE_kmod-tcp-brutal=y @@ -219,6 +221,8 @@ CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb2-pci=y CONFIG_PACKAGE_kmod-usb2=y CONFIG_PACKAGE_kmod-usb3=y +CONFIG_PACKAGE_kmod-veth=y +CONFIG_PACKAGE_kmod-xdp-sockets-diag=y ### Kernel Modules - out-of-tree driver CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index 7cad92913..6114a9384 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -136,6 +136,8 @@ CONFIG_PACKAGE_kmod-nft-fullcone=y CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y +CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y CONFIG_PACKAGE_kmod-tcp-brutal=y @@ -147,6 +149,8 @@ CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb2-pci=y CONFIG_PACKAGE_kmod-usb2=y CONFIG_PACKAGE_kmod-usb3=y +CONFIG_PACKAGE_kmod-veth=y +CONFIG_PACKAGE_kmod-xdp-sockets-diag=y ### Kernel Modules - out-of-tree driver CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y diff --git a/openwrt/24-config-musl-r8500 b/openwrt/24-config-musl-r8500 index 32b8129f5..35916bd16 100644 --- a/openwrt/24-config-musl-r8500 +++ b/openwrt/24-config-musl-r8500 @@ -190,13 +190,17 @@ CONFIG_PACKAGE_kmod-nft-fullcone=y CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y +CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-usb-audio=y -CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-uas=y +CONFIG_PACKAGE_kmod-usb-storage=y +CONFIG_PACKAGE_kmod-veth=y +CONFIG_PACKAGE_kmod-xdp-sockets-diag=y # CONFIG_PACKAGE_kmod-mhi-pcie is not set # CONFIG_PACKAGE_kmod-rtl8812au-ct is not set diff --git a/openwrt/24-config-musl-r8500-minimal b/openwrt/24-config-musl-r8500-minimal index 81724f597..d4b58f3c4 100644 --- a/openwrt/24-config-musl-r8500-minimal +++ b/openwrt/24-config-musl-r8500-minimal @@ -143,12 +143,16 @@ CONFIG_PACKAGE_kmod-nft-fullcone=y CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y +CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y -CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-uas=y +CONFIG_PACKAGE_kmod-usb-storage=y +CONFIG_PACKAGE_kmod-veth=y +CONFIG_PACKAGE_kmod-xdp-sockets-diag=y # CONFIG_PACKAGE_kmod-mhi-pcie is not set # CONFIG_PACKAGE_kmod-rtl8812au-ct is not set From 0f6f812d4170d2c1fc97ff9b4b9c1bd561c1582a Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 3 Dec 2024 17:59:41 +0800 Subject: [PATCH 161/425] perf: update to openwrt-24.10 Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/perf/Makefile | 28 +++++--- openwrt/patch/openwrt-6.x/perf/Makefile.2 | 86 ----------------------- openwrt/scripts/05-fix-source.sh | 7 +- 3 files changed, 20 insertions(+), 101 deletions(-) delete mode 100644 openwrt/patch/openwrt-6.x/perf/Makefile.2 diff --git a/openwrt/patch/openwrt-6.x/perf/Makefile b/openwrt/patch/openwrt-6.x/perf/Makefile index 53b110581..1fc6915e6 100644 --- a/openwrt/patch/openwrt-6.x/perf/Makefile +++ b/openwrt/patch/openwrt-6.x/perf/Makefile @@ -10,9 +10,9 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=perf PKG_VERSION:=$(LINUX_VERSION) -PKG_RELEASE:=6 +PKG_RELEASE:=5 -PKG_BUILD_FLAGS:=no-mips16 no-lto no-mold +PKG_BUILD_FLAGS:=no-mips16 no-lto PKG_BUILD_PARALLEL:=1 PKG_MAINTAINER:=Felix Fietkau PKG_FLAGS:=nonshared @@ -27,8 +27,8 @@ include $(INCLUDE_DIR)/nls.mk define Package/perf SECTION:=devel CATEGORY:=Development - DEPENDS:= +libelf +libdw +PACKAGE_libunwind:libunwind +libpthread +librt +libstdcpp +objdump @!IN_SDK @KERNEL_PERF_EVENTS \ - +PACKAGE_libbfd:libbfd +PACKAGE_libopcodes:libopcodes + DEPENDS:= +libelf +libdw +PACKAGE_libunwind:libunwind +libpthread +librt +objdump @!IN_SDK @KERNEL_PERF_EVENTS \ + +PACKAGE_libbfd:libbfd +PACKAGE_libopcodes:libopcodes +libtraceevent TITLE:=Linux performance monitoring tool VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE) URL:=http://www.kernel.org @@ -42,8 +42,6 @@ HOST_CFLAGS += -I$(LINUX_DIR)/tools/include TARGET_LDFLAGS += $(INTL_LDFLAGS) -TARGET_CFLAGS += -Wno-maybe-uninitialized - MAKE_FLAGS = \ ARCH="$(LINUX_KARCH)" \ NO_LIBPERL=1 \ @@ -58,7 +56,6 @@ MAKE_FLAGS = \ NO_LIBUNWIND=1 \ NO_LIBZSTD=1 \ NO_LIBCAP=1 \ - NO_LIBTRACEEVENT=1 \ CROSS_COMPILE="$(TARGET_CROSS)" \ CC="$(TARGET_CC)" \ LD="$(TARGET_CROSS)ld" \ @@ -66,14 +63,27 @@ MAKE_FLAGS = \ LDFLAGS="$(TARGET_LDFLAGS)" \ KBUILD_HOSTCFLAGS="$(HOST_CFLAGS)" \ $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \ + PKG_CONFIG="$(PKG_CONFIG)" \ + PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" \ + EXCLUDE_EXTLIBS="-lstdc++" \ + EXTRA_PERFLIBS="$(shell $(TARGET_CC) -print-file-name=libstdc++.a)" \ WERROR=0 \ O=$(PKG_BUILD_DIR) \ prefix=/usr +ifeq ($(LINUX_KARCH),powerpc) + MAKE_FLAGS += NO_AUXTRACE=1 +endif + +ifneq (,$(findstring clang,$(KERNEL_CC))) + MAKE_FLAGS += NO_LIBELF=1 +endif + define Build/Compile - +$(MAKE_FLAGS) $(MAKE) $(PKG_JOBS) \ + +$(MAKE) $(PKG_JOBS) $(MAKE_FLAGS) \ --no-print-directory \ - -C $(LINUX_DIR)/tools/perf + -C $(LINUX_DIR)/tools/perf \ + -f Makefile.perf endef define Package/perf/install diff --git a/openwrt/patch/openwrt-6.x/perf/Makefile.2 b/openwrt/patch/openwrt-6.x/perf/Makefile.2 deleted file mode 100644 index 7ea6e9164..000000000 --- a/openwrt/patch/openwrt-6.x/perf/Makefile.2 +++ /dev/null @@ -1,86 +0,0 @@ -# -# Copyright (C) 2011-2013 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk -include $(INCLUDE_DIR)/kernel.mk - -PKG_NAME:=perf -PKG_VERSION:=$(LINUX_VERSION) -PKG_RELEASE:=6 - -PKG_BUILD_FLAGS:=no-mips16 no-lto no-mold -PKG_BUILD_PARALLEL:=1 -PKG_MAINTAINER:=Felix Fietkau -PKG_FLAGS:=nonshared - -# Perf's makefile and headers are not relocatable and must be built from the -# Linux sources directory -PKG_BUILD_DIR:=$(LINUX_DIR)/tools/perf-$(TARGET_DIR_NAME) - -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/nls.mk - -define Package/perf - SECTION:=devel - CATEGORY:=Development - DEPENDS:= +libelf +libdw +PACKAGE_libunwind:libunwind +libpthread +librt +libstdcpp +objdump @!IN_SDK @KERNEL_PERF_EVENTS \ - +PACKAGE_libbfd:libbfd +PACKAGE_libopcodes:libopcodes - TITLE:=Linux performance monitoring tool - VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE) - URL:=http://www.kernel.org -endef - -define Package/perf/description - perf is the Linux performance monitoring tool -endef - -HOST_CFLAGS += -I$(LINUX_DIR)/tools/include - -TARGET_LDFLAGS += $(INTL_LDFLAGS) - -TARGET_CFLAGS += -Wno-error=calloc-transposed-args -Wno-error=alloc-size - -KERNEL_CC := $(TARGET_CC) - -MAKE_FLAGS = \ - ARCH="$(LINUX_KARCH)" \ - NO_LIBPERL=1 \ - NO_LIBPYTHON=1 \ - NO_NEWT=1 \ - NO_LZMA=1 \ - NO_BACKTRACE=1 \ - NO_LIBNUMA=1 \ - NO_GTK2=1 \ - NO_LIBAUDIT=1 \ - NO_LIBCRYPTO=1 \ - NO_LIBUNWIND=1 \ - NO_LIBZSTD=1 \ - NO_LIBCAP=1 \ - LIBC_SUPPORT=1 \ - NO_LIBELF=1 \ - NO_LIBTRACEEVENT=1 \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \ - LDFLAGS="$(TARGET_LDFLAGS)" \ - KBUILD_HOSTCFLAGS="$(HOST_CFLAGS)" \ - $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \ - WERROR=0 \ - O=$(PKG_BUILD_DIR) \ - prefix=/usr - -define Build/Compile - +$(MAKE_FLAGS) $(KERNEL_MAKE) $(PKG_JOBS) \ - --no-print-directory \ - -C $(LINUX_DIR)/tools/perf -endef - -define Package/perf/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/perf $(1)/usr/bin/ -endef - -$(eval $(call BuildPackage,perf)) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 01b0f1802..a1372fc1f 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -72,12 +72,7 @@ popd # perf curl -s $mirror/openwrt/patch/openwrt-6.x/musl/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch > toolchain/musl/patches/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch -if [ "$KERNEL_CLANG_LTO" = "y" ]; then - curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile.2 > package/devel/perf/Makefile -else - curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Makefile -fi -[ "$ENABLE_MOLD" != y ] && sed -i 's/no-mold//g' package/devel/perf/Makefile +curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Makefile # kselftests-bpf curl -s $mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package/devel/kselftests-bpf/Makefile From afc3d4d6fbd1bc869de6c3fae1f95c7eb5d02b48 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Dec 2024 22:45:12 +0800 Subject: [PATCH 162/425] OpenWrt 24.10.0-rc2 Signed-off-by: sbwml --- tags/v24 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v24 b/tags/v24 index 45904e521..a9b5877a4 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.0-rc1 +24.10.0-rc2 From 91e16c4a72afd22468d781f54a4f0fe78f912392 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 5 Dec 2024 12:27:54 +0800 Subject: [PATCH 163/425] fix luci-app-filemanager Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 1527cbe60..b3329ed54 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -15,6 +15,7 @@ git clone https://$github/sbwml/default-settings package/new/default-settings -b git clone https://github.com/sbwml/wwan-packages package/new/wwan # luci-app-filemanager +rm -rf feeds/luci/applications/luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager # luci-app-webdav From ac0fce0550a14cbb95eb03da93a5743e520248d1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 6 Dec 2024 12:48:48 +0800 Subject: [PATCH 164/425] linux-6.12: bump to 6.12.2 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 95eed4678..875f5fffe 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .1 -LINUX_KERNEL_HASH-6.12.1 = 0193b1d86dd372ec891bae799f6da20deef16fc199f30080a4ea9de8cef0c619 +LINUX_VERSION-6.12 = .2 +LINUX_KERNEL_HASH-6.12.2 = bb1e0710c73e877b1f3005be7301734903636be8ef1700d3b12106e8f3403d8b From 991411495e505d4fb15d31715d78f44eea4990fd Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 6 Dec 2024 22:49:19 +0800 Subject: [PATCH 165/425] linux-6.12: bump to 6.12.3 Signed-off-by: sbwml --- openwrt/build.sh | 31 +++++++++++++++++++++++++++++++ openwrt/generic/config-wwan | 9 +++++++++ tags/kernel-6.12 | 4 ++-- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 openwrt/generic/config-wwan diff --git a/openwrt/build.sh b/openwrt/build.sh index d60820239..2a21e7ac9 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -346,6 +346,9 @@ echo -e "CONFIG_GCC_USE_VERSION_${gcc_version}=y\n" >> .config # not all kmod [ "$NO_KMOD" = "y" ] && sed -i '/CONFIG_ALL_KMODS=y/d; /CONFIG_ALL_NONSHARED=y/d' .config +# build wwan pkgs for openwrt_core +[ "$OPENWRT_CORE" = "y" ] && curl -s $mirror/openwrt/generic/config-wwan >> .config + # ccache if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then echo "CONFIG_CCACHE=y" >> .config @@ -421,6 +424,13 @@ if [ "$platform" = "x86_64" ]; then rm -f $kmodpkg_name/Packages* cp -a bin/packages/x86_64/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/x86_64/base/natflow*.ipk $kmodpkg_name/ + [ "$OPENWRT_CORE" = "y" ] && { + cp -a bin/packages/x86_64/base/*3ginfo*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/*modemband*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/*sms-tool*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/*quectel*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/*fibocom*.ipk $kmodpkg_name/ + } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true cp -a bin/packages/x86_64/base/*numa*.ipk $kmodpkg_name/ || true @@ -463,6 +473,13 @@ elif [ "$platform" = "armv8" ]; then rm -f $kmodpkg_name/Packages* cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ + [ "$OPENWRT_CORE" = "y" ] && { + cp -a bin/packages/aarch64_generic/base/*3ginfo*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*modemband*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*sms-tool*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*quectel*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*fibocom*.ipk $kmodpkg_name/ + } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true @@ -495,6 +512,13 @@ elif [ "$platform" = "bcm53xx" ]; then rm -f $kmodpkg_name/Packages* cp -a bin/packages/arm_cortex-a9/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/arm_cortex-a9/base/natflow*.ipk $kmodpkg_name/ + [ "$OPENWRT_CORE" = "y" ] && { + cp -a bin/packages/arm_cortex-a9/base/*3ginfo*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/*modemband*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/*sms-tool*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/*quectel*.ipk $kmodpkg_name/ + cp -a bin/packages/arm_cortex-a9/base/*fibocom*.ipk $kmodpkg_name/ + } bash kmod-sign $kmodpkg_name tar zcf bcm53xx-$kmodpkg_name.tar.gz $kmodpkg_name rm -rf $kmodpkg_name @@ -528,6 +552,13 @@ else rm -f $kmodpkg_name/Packages* cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ + [ "$OPENWRT_CORE" = "y" ] && { + cp -a bin/packages/aarch64_generic/base/*3ginfo*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*modemband*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*sms-tool*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*quectel*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*fibocom*.ipk $kmodpkg_name/ + } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true diff --git a/openwrt/generic/config-wwan b/openwrt/generic/config-wwan new file mode 100644 index 000000000..937a090b7 --- /dev/null +++ b/openwrt/generic/config-wwan @@ -0,0 +1,9 @@ + +# wwan +luci-app-3ginfo-lite=m +luci-app-modemband=m +luci-app-sms-tool-js=m +luci-proto-quectel=m +CONFIG_PACKAGE_fibocom-dial=m +CONFIG_PACKAGE_modemband=m +CONFIG_PACKAGE_quectel-cm=m diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 875f5fffe..a9cf4e6eb 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .2 -LINUX_KERNEL_HASH-6.12.2 = bb1e0710c73e877b1f3005be7301734903636be8ef1700d3b12106e8f3403d8b +LINUX_VERSION-6.12 = .3 +LINUX_KERNEL_HASH-6.12.3 = c89809cc777d50f1ea484a118630281a26383707a0e752c96fd834f6e765deae From 6369cbc3a29032be6569b034ec481640d8773539 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 6 Dec 2024 22:50:55 +0800 Subject: [PATCH 166/425] config-wwan: fix typo Signed-off-by: sbwml --- openwrt/generic/config-wwan | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/generic/config-wwan b/openwrt/generic/config-wwan index 937a090b7..4e782ed6d 100644 --- a/openwrt/generic/config-wwan +++ b/openwrt/generic/config-wwan @@ -1,9 +1,9 @@ # wwan -luci-app-3ginfo-lite=m -luci-app-modemband=m -luci-app-sms-tool-js=m -luci-proto-quectel=m +CONFIG_PACKAGE_luci-app-3ginfo-lite=m +CONFIG_PACKAGE_luci-app-modemband=m +CONFIG_PACKAGE_luci-app-sms-tool-js=m +CONFIG_PACKAGE_luci-proto-quectel=m CONFIG_PACKAGE_fibocom-dial=m CONFIG_PACKAGE_modemband=m CONFIG_PACKAGE_quectel-cm=m From ecbcddd842cd519a064e399081dfb40042456aef Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 9 Dec 2024 23:47:22 +0800 Subject: [PATCH 167/425] patch: refresh openwrt patches Signed-off-by: sbwml --- .../generic-24.10/0001-tools-add-upx-tools.patch | 2 +- ...0002-rootfs-add-upx-compression-support.patch | 2 +- ...w-permissions-for-UCI-configuration-fil.patch | 2 +- ...pport-for-local-kmod-installation-sourc.patch | 2 +- ...nel-Add-support-for-llvm-clang-compiler.patch | 2 +- ...ld-kernel-add-out-of-tree-kernel-config.patch | 4 ++-- ...e-kernel-add-miss-config-for-linux-6.11.patch | 4 ++-- ...tform-variable-to-cross-compilation-fil.patch | 4 ++-- ...-add-legacy-cgroup-v1-memory-controller.patch | 6 +++--- ...d-PREEMPT_RT-support-for-aarch64-x86_64.patch | 4 ++-- ...02-toolchain-gcc-add-support-for-GCC-15.patch | 4 ++-- .../linux-6.12-target-linux-generic.patch | 16 ++++++++-------- ...us-firewall-disable-legacy-firewall-rul.patch | 8 ++++---- openwrt/patch/target-modify_for_armsr.patch | 4 ++-- openwrt/patch/target-modify_for_rockchip.patch | 4 ++-- openwrt/patch/target-modify_for_x86_64.patch | 4 ++-- 16 files changed, 36 insertions(+), 36 deletions(-) diff --git a/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch b/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch index 75c737245..51692fcff 100644 --- a/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch +++ b/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch @@ -1,4 +1,4 @@ -From 64bdd05856306c921523395f6c150d796eaa0c02 Mon Sep 17 00:00:00 2001 +From d9fe4db89fcc215510319db72e415a83c861a040 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:39:25 +0800 Subject: [PATCH 01/10] tools: add upx tools diff --git a/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch b/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch index 3e874886c..0b399c14d 100644 --- a/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch +++ b/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch @@ -1,4 +1,4 @@ -From 7cd01d84de61e8642db1c4f8599630290e3997d0 Mon Sep 17 00:00:00 2001 +From a85660738779248ea2c2cd44a11b7f4602875671 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:46:49 +0800 Subject: [PATCH 02/10] rootfs: add upx compression support diff --git a/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch b/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch index 72b5d4f73..0aeddb27b 100644 --- a/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch +++ b/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch @@ -1,4 +1,4 @@ -From abe248ebdb46aa4635487ddf7819772cf22ca03b Mon Sep 17 00:00:00 2001 +From b557005f9d3164de1f23a0239647f25d07b0b389 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:47:41 +0800 Subject: [PATCH 03/10] rootfs: add r/w permissions for UCI configuration files diff --git a/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch b/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch index 2a1ddb365..6f1a2db1a 100644 --- a/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch +++ b/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch @@ -1,4 +1,4 @@ -From b6042a29a66bba6044982aab6c5f241ef45b10b4 Mon Sep 17 00:00:00 2001 +From 5c52ffb8e9e708c663359d5f8a8d609ca8cfd409 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:48:29 +0800 Subject: [PATCH 04/10] rootfs: Add support for local kmod installation sources diff --git a/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch index 4acd62c52..3e7fafb95 100644 --- a/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch +++ b/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch @@ -1,4 +1,4 @@ -From 9b309149f1f96a2163bba1191fcb28f23bbdf162 Mon Sep 17 00:00:00 2001 +From b196c42657703b93c93210bf6743f2aa745a88bc Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:51:22 +0800 Subject: [PATCH 05/10] kernel: Add support for llvm/clang compiler diff --git a/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch index b0a941f2b..e809782a3 100644 --- a/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch +++ b/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch @@ -1,4 +1,4 @@ -From 4142f36de61a4e5074d07e4562e9895874b88459 Mon Sep 17 00:00:00 2001 +From 2ad612d3af7e88120052d1772fdacd6cce109f58 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:56:57 +0800 Subject: [PATCH 06/10] build: kernel: add out-of-tree kernel config @@ -28,7 +28,7 @@ index 9079303..2cbefc2 100644 string "Use external kernel tree" if DEVEL default "" diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index f94ed33..8e9ed74 100644 +index f94ed33..6ec2e75 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk @@ -108,6 +108,78 @@ define Kernel/SetNoInitramfs diff --git a/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch index fbdec2ea2..655ad22d2 100644 --- a/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch +++ b/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch @@ -1,4 +1,4 @@ -From 20ef2e23f6a2a4f4c7f6242486eca8c2b42d49c4 Mon Sep 17 00:00:00 2001 +From 6243d903b853abbc81a3258356155f207e2c0853 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:29 +0800 Subject: [PATCH 07/10] include: kernel: add miss config for linux-6.11 @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 1 insertion(+) diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index 8e9ed74..d703d5d 100644 +index 6ec2e75..ea97998 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk @@ -108,6 +108,7 @@ define Kernel/SetNoInitramfs diff --git a/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch b/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch index 475b2af88..c0dcd162a 100644 --- a/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch +++ b/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch @@ -1,4 +1,4 @@ -From 67ebaba62cc4036ba6d2c8f064b0f40f30acdade Mon Sep 17 00:00:00 2001 +From dc0aa15d94e848f1f96e70a9e8068ad798aaba22 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:54 +0800 Subject: [PATCH 08/10] meson: add platform variable to cross-compilation file @@ -10,7 +10,7 @@ Signed-off-by: sbwml 2 files changed, 2 insertions(+) diff --git a/include/meson.mk b/include/meson.mk -index 2a20c2b..f5333f7 100644 +index ff452d8..8ac801b 100644 --- a/include/meson.mk +++ b/include/meson.mk @@ -90,6 +90,7 @@ define Meson/CreateCrossFile diff --git a/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch b/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch index a3679445f..96fb1065d 100644 --- a/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch +++ b/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch @@ -1,4 +1,4 @@ -From 8c80f36391472bb37848c1485b588dec2ab19a2c Mon Sep 17 00:00:00 2001 +From 360c76c16bb63cd2a7a5eb188c063468ce99073c Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 10 Oct 2024 21:40:05 +0800 Subject: [PATCH 09/10] kernel: add legacy cgroup v1 memory controller @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 10 insertions(+) diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index 0fa039d..a438621 100644 +index 91678cf..eb0f000 100644 --- a/config/Config-kernel.in +++ b/config/Config-kernel.in -@@ -934,6 +934,16 @@ if KERNEL_CGROUPS +@@ -953,6 +953,16 @@ if KERNEL_CGROUPS the kmem extension can use it to guarantee that no group of processes will ever exhaust kernel resources alone. diff --git a/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch b/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch index 1ceff0cb8..a3819d478 100644 --- a/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch +++ b/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch @@ -1,4 +1,4 @@ -From 8576944e698d42b96205e85fff003bd162c0f9c3 Mon Sep 17 00:00:00 2001 +From 53ff6a6a2bdeb5173d5ea0b3795b36737af8abb3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 12 Oct 2024 08:36:46 +0800 Subject: [PATCH 10/10] kernel: add PREEMPT_RT support for aarch64/x86_64 @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 13 insertions(+) diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index a438621..47b7c4c 100644 +index eb0f000..76092d4 100644 --- a/config/Config-kernel.in +++ b/config/Config-kernel.in @@ -20,6 +20,19 @@ config KERNEL_BUILD_DOMAIN diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch index eaab7537f..0e585102d 100644 --- a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -1,7 +1,7 @@ -From 1ed5c775935304f67aff4aa83c85d17c4f31afc4 Mon Sep 17 00:00:00 2001 +From b6419cff44d0e951d3805dcd70f3d462f40baa8f Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 7 Nov 2024 01:13:32 +0800 -Subject: [PATCH] gcc: add support for GCC 15 +Subject: [PATCH] toolchain: gcc: add support for GCC 15 Signed-off-by: sbwml --- diff --git a/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch b/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch index dddee6560..577d92882 100644 --- a/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch +++ b/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch @@ -114,7 +114,7 @@ index a26fd20..c3d50a0 100644 { struct rtl8366_platform_data *pdata = pdev->dev.platform_data; diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c -index 0e01160..88ac9cc 100644 +index 0878ca9..cce9bde 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c @@ -1478,7 +1478,7 @@ static int rtl8366rb_probe(struct platform_device *pdev) @@ -135,7 +135,7 @@ index 0e01160..88ac9cc 100644 } #ifdef CONFIG_OF -@@ -1507,7 +1505,7 @@ static struct platform_driver rtl8366rb_driver = { +@@ -1506,7 +1504,7 @@ static struct platform_driver rtl8366rb_driver = { .of_match_table = of_match_ptr(rtl8366rb_match), }, .probe = rtl8366rb_probe, @@ -145,7 +145,7 @@ index 0e01160..88ac9cc 100644 static int __init rtl8366rb_module_init(void) diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366s.c b/target/linux/generic/files/drivers/net/phy/rtl8366s.c -index 8c74677..e2efac6 100644 +index d4045fc..5458c50 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366s.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366s.c @@ -1266,7 +1266,7 @@ static int rtl8366s_probe(struct platform_device *pdev) @@ -166,7 +166,7 @@ index 8c74677..e2efac6 100644 } #ifdef CONFIG_OF -@@ -1297,7 +1295,7 @@ static struct platform_driver rtl8366s_driver = { +@@ -1296,7 +1294,7 @@ static struct platform_driver rtl8366s_driver = { #endif }, .probe = rtl8366s_probe, @@ -176,7 +176,7 @@ index 8c74677..e2efac6 100644 static int __init rtl8366s_module_init(void) diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367.c b/target/linux/generic/files/drivers/net/phy/rtl8367.c -index 0acfeb5..3b1c870 100644 +index 950e9d2..1b99601 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367.c @@ -1801,7 +1801,7 @@ static int rtl8367_probe(struct platform_device *pdev) @@ -197,7 +197,7 @@ index 0acfeb5..3b1c870 100644 } static void rtl8367_shutdown(struct platform_device *pdev) -@@ -1840,7 +1838,7 @@ static struct platform_driver rtl8367_driver = { +@@ -1839,7 +1837,7 @@ static struct platform_driver rtl8367_driver = { #endif }, .probe = rtl8367_probe, @@ -207,7 +207,7 @@ index 0acfeb5..3b1c870 100644 }; diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c -index 4236912..89aa8d7 100644 +index 5f885aa..5adcf00 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367b.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c @@ -1600,7 +1600,7 @@ static int rtl8367b_probe(struct platform_device *pdev) @@ -228,7 +228,7 @@ index 4236912..89aa8d7 100644 } static void rtl8367b_shutdown(struct platform_device *pdev) -@@ -1639,7 +1637,7 @@ static struct platform_driver rtl8367b_driver = { +@@ -1638,7 +1636,7 @@ static struct platform_driver rtl8367b_driver = { #endif }, .probe = rtl8367b_probe, diff --git a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch index 18b40b8ff..81ae48a53 100644 --- a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch +++ b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch @@ -11,10 +11,10 @@ Signed-off-by: sbwml 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -index be62d91..1718494 100644 +index 406f134..9c083e7 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -@@ -672,26 +672,12 @@ return view.extend({ +@@ -675,26 +675,12 @@ return view.extend({ return node; }, @@ -42,7 +42,7 @@ index be62d91..1718494 100644 return E('em', _('No nftables ruleset loaded.')); diff --git a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json -index 190eef0..e9cf485 100644 +index 79101e9..eceb5e1 100644 --- a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json +++ b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json @@ -39,20 +39,33 @@ @@ -83,5 +83,5 @@ index 190eef0..e9cf485 100644 "type": "view", "path": "status/iptables" -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/target-modify_for_armsr.patch b/openwrt/patch/target-modify_for_armsr.patch index 776b8b369..7eb6e07b4 100644 --- a/openwrt/patch/target-modify_for_armsr.patch +++ b/openwrt/patch/target-modify_for_armsr.patch @@ -1,8 +1,8 @@ diff --git a/include/target.mk b/include/target.mk -index d13902a..72b8059 100644 +index 0108bce..4ceb81e 100644 --- a/include/target.mk +++ b/include/target.mk -@@ -294,6 +294,10 @@ ifeq ($(DUMP),1) +@@ -318,6 +318,10 @@ ifeq ($(DUMP),1) CPU_CFLAGS := -O2 -pipe CPU_CFLAGS_generic:=-march=loongarch64 endif diff --git a/openwrt/patch/target-modify_for_rockchip.patch b/openwrt/patch/target-modify_for_rockchip.patch index 30984c376..9f31ae529 100644 --- a/openwrt/patch/target-modify_for_rockchip.patch +++ b/openwrt/patch/target-modify_for_rockchip.patch @@ -1,8 +1,8 @@ diff --git a/include/target.mk b/include/target.mk -index d13902a..1a85ede 100644 +index 0108bce..5577072 100644 --- a/include/target.mk +++ b/include/target.mk -@@ -294,6 +294,10 @@ ifeq ($(DUMP),1) +@@ -318,6 +318,10 @@ ifeq ($(DUMP),1) CPU_CFLAGS := -O2 -pipe CPU_CFLAGS_generic:=-march=loongarch64 endif diff --git a/openwrt/patch/target-modify_for_x86_64.patch b/openwrt/patch/target-modify_for_x86_64.patch index 7f1cad737..f6927b494 100644 --- a/openwrt/patch/target-modify_for_x86_64.patch +++ b/openwrt/patch/target-modify_for_x86_64.patch @@ -1,8 +1,8 @@ diff --git a/include/target.mk b/include/target.mk -index d13902a..32037b6 100644 +index 0108bce..45ade4b 100644 --- a/include/target.mk +++ b/include/target.mk -@@ -233,7 +233,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt +@@ -257,7 +257,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt ifeq ($(DUMP),1) BuildTarget=$(BuildTargets/DumpCurrent) From eb18f4176d3b10967eccaca358fe1d61fde2c14d Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 9 Dec 2024 23:47:37 +0800 Subject: [PATCH 168/425] linux-6.12: bump to 6.12.4 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index a9cf4e6eb..417f57d89 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .3 -LINUX_KERNEL_HASH-6.12.3 = c89809cc777d50f1ea484a118630281a26383707a0e752c96fd834f6e765deae +LINUX_VERSION-6.12 = .4 +LINUX_KERNEL_HASH-6.12.4 = 6f35f821433d8421be7167990747c7c4a0c451958fb96883446301af13d71152 From 9442c2d373a8ca332d5518cd2c4b2408fe4649ca Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 15 Dec 2024 23:26:03 +0800 Subject: [PATCH 169/425] linux-6.12: bump to 6.12.5 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 417f57d89..3f2cd757d 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .4 -LINUX_KERNEL_HASH-6.12.4 = 6f35f821433d8421be7167990747c7c4a0c451958fb96883446301af13d71152 +LINUX_VERSION-6.12 = .5 +LINUX_KERNEL_HASH-6.12.5 = 39207fce1ce42838e085261bae0af5ce4a0843aa777cfc0f5c49bc7729602bcd From 08e09f830baed243afd3a631cad44642cfb6c2e7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 18 Dec 2024 23:44:23 +0800 Subject: [PATCH 170/425] luci-app-firewall: add fullcone6 option for nftables based fullcone Signed-off-by: sbwml --- ...l-add-fullcone6-option-for-nftables-.patch | 44 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 1 + 2 files changed, 45 insertions(+) create mode 100644 openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch diff --git a/openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch b/openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch new file mode 100644 index 000000000..0fb3ac273 --- /dev/null +++ b/openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch @@ -0,0 +1,44 @@ +From 6d3223164d85f83b7568e0859e4cdcbbb7136f6c Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 18 Dec 2024 23:38:26 +0800 +Subject: [PATCH] luci-app-firewall: add fullcone6 option for nftables based + fullcone + +Signed-off-by: sbwml +--- + .../resources/view/firewall/zones.js | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +index 3fe1065..37dfaf2 100644 +--- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js ++++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +@@ -77,6 +77,25 @@ return view.extend({ + uci.set('firewall', section_id, 'fullcone', value === '0' ? null : '1'); + uci.set('firewall', section_id, 'brcmfullcone', value === '2' ? '1' : null); + }; ++ ++ /* nft-fullcone 6 */ ++ o = s.option(form.RichListValue, "fullcone6", _("Full Cone NAT6")); ++ o.value('0', _("Disable")); ++ o.value('1', _("Enable")); ++ o.optional = false; ++ o.depends('fullcone_type', '1'); ++ o.load = function (section_id) { ++ var fullcone6 = uci.get('firewall', section_id, 'fullcone6'); ++ if (fullcone6 === '1') { ++ return '1'; ++ } else { ++ return '0'; ++ } ++ }; ++ o.write = function(section_id, value) { ++ uci.set('firewall', section_id, 'fullcone6', value === '1' ? '1' : '0'); ++ uci.set('firewall', '@zone[1]', 'fullcone6', value === '1' ? '1' : '0'); ++ }; + } + + if (L.hasSystemFeature('ipv6')) { +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 7f45207ea..ef396cf68 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -152,6 +152,7 @@ pushd feeds/luci curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch | patch -p1 popd # openssl - quictls From c237b1fbdea5773998e3a9a69ea7fc433a332dec Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 20 Dec 2024 12:02:33 +0800 Subject: [PATCH 171/425] linux-6.12: bump to 6.12.6 Signed-off-by: sbwml --- openwrt/build.sh | 2 +- tags/kernel-6.12 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 2a21e7ac9..5fff18773 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -45,7 +45,7 @@ export gitea=git.cooluc.com # github mirror if [ "$isCN" = "CN" ]; then - export github="ghp.ci/github.com" + export github="ghgo.xyz/github.com" else export github="github.com" fi diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 3f2cd757d..1e17fc37c 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .5 -LINUX_KERNEL_HASH-6.12.5 = 39207fce1ce42838e085261bae0af5ce4a0843aa777cfc0f5c49bc7729602bcd +LINUX_VERSION-6.12 = .6 +LINUX_KERNEL_HASH-6.12.6 = d450ab215de4e1f8bb85e0f4216760fa33fd024b4526b144f4ce0d9012b29c9e From 3bed0ad1090f576299f07eefb6c4f7d6cb5fc918 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 23 Dec 2024 11:59:48 +0800 Subject: [PATCH 172/425] OpenWrt 24.10.0-rc3 Signed-off-by: sbwml --- openwrt/build.sh | 3 ++- tags/v24 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 5fff18773..b2af842b7 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -191,7 +191,8 @@ fi # feeds mirror if [ "$1" = "rc2" ]; then packages="^$(grep packages feeds.conf.default | awk -F^ '{print $2}')" - luci="^$(grep luci feeds.conf.default | awk -F^ '{print $2}')" + #luci="^$(grep luci feeds.conf.default | awk -F^ '{print $2}')" + luci="^b43aea743e78bb478495d2bfca046a0417dbdfe7" routing="^$(grep routing feeds.conf.default | awk -F^ '{print $2}')" telephony="^$(grep telephony feeds.conf.default | awk -F^ '{print $2}')" else diff --git a/tags/v24 b/tags/v24 index a9b5877a4..519ed3abf 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.0-rc2 +24.10.0-rc3 From a218bd5934a78ca4f07111fc6c9bfcb9d42b1466 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 23 Dec 2024 21:58:36 +0800 Subject: [PATCH 173/425] OpenWrt 24.10.0-rc4 Signed-off-by: sbwml --- openwrt/build.sh | 3 +-- tags/v24 | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index b2af842b7..5fff18773 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -191,8 +191,7 @@ fi # feeds mirror if [ "$1" = "rc2" ]; then packages="^$(grep packages feeds.conf.default | awk -F^ '{print $2}')" - #luci="^$(grep luci feeds.conf.default | awk -F^ '{print $2}')" - luci="^b43aea743e78bb478495d2bfca046a0417dbdfe7" + luci="^$(grep luci feeds.conf.default | awk -F^ '{print $2}')" routing="^$(grep routing feeds.conf.default | awk -F^ '{print $2}')" telephony="^$(grep telephony feeds.conf.default | awk -F^ '{print $2}')" else diff --git a/tags/v24 b/tags/v24 index 519ed3abf..1b25acfcd 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.0-rc3 +24.10.0-rc4 From 6f3929406191a6ee7fca3a34db7a2e8fb6d2ec15 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Dec 2024 12:49:03 +0800 Subject: [PATCH 174/425] build.sh: delete patch conflict files Signed-off-by: sbwml --- openwrt/build.sh | 1 + .../luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 5fff18773..561f6275a 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -246,6 +246,7 @@ bash 03-convert_translation.sh bash 04-fix_kmod.sh bash 05-fix-source.sh [ -f "10-custom.sh" ] && bash 10-custom.sh +find feeds -type f -name "*.orig" -exec rm -f {} \; [ "$(whoami)" = "runner" ] && endgroup rm -f 0*-*.sh 10-custom.sh diff --git a/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch b/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch index 93ad88e83..c87a1cf28 100644 --- a/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch +++ b/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch @@ -1,6 +1,6 @@ --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js -@@ -847,6 +847,20 @@ return view.extend({ +@@ -854,6 +854,20 @@ return view.extend({ so.depends('ra', 'server'); so.depends({ ra: 'hybrid', master: '0' }); From 1341276f1f76257c0100dc0365cb9fd0071548ec Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 25 Dec 2024 23:16:21 +0800 Subject: [PATCH 175/425] openwrt-24.10-rc4: fix luci-base Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index a1372fc1f..bb3818546 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,5 +1,8 @@ #!/bin/bash +# fix luci-base - rc4 +sed -i 's|\[sid\].hasOwnProperty|\[sid\]?.hasOwnProperty|g' feeds/luci/modules/luci-base/htdocs/luci-static/resources/uci.js + # apk-tools curl -s $mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch From 8fd029ba995d1aa3c7b580b248a00046e108f097 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 3 Jan 2025 21:34:10 +0800 Subject: [PATCH 176/425] linux-6.12: bump to 6.12.8 Signed-off-by: sbwml --- openwrt/24-config-common | 1 + openwrt/24-config-minimal-common | 1 + openwrt/scripts/01-prepare_base-mainline.sh | 5 ++++ tags/kernel-6.12 | 4 +-- ...ockchip-naneng-combphy-fix-phy-reset.patch | 26 +++++++++++++++++++ tags/patches/patch.list | 1 + 6 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch create mode 100644 tags/patches/patch.list diff --git a/openwrt/24-config-common b/openwrt/24-config-common index e563cde3b..45284a687 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -183,6 +183,7 @@ CONFIG_PACKAGE_kmod-usb-net-rndis=y CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules +CONFIG_PACKAGE_kmod-bonding=y CONFIG_PACKAGE_kmod-br-netfilter=y CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index 6114a9384..f7a4a12a7 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -113,6 +113,7 @@ CONFIG_PACKAGE_kmod-usb-net-rndis=y CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules +CONFIG_PACKAGE_kmod-bonding=y CONFIG_PACKAGE_kmod-br-netfilter=y CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 0c715ecd6..8a6140d97 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -57,6 +57,11 @@ else fi cp -a target/linux/generic-6.12/* target/linux/generic +# additional patches +curl -s $mirror/tags/patches/patch.list | while read -r patch_file; do + curl -s $mirror/tags/patches/$patch_file > target/linux/generic/hack-6.12/$patch_file +done + # bcm53xx - fix build kernel with clang [ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch target/linux/generic/hack-6.12/220-arm-gc_sections.patch diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 1e17fc37c..6197298a1 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .6 -LINUX_KERNEL_HASH-6.12.6 = d450ab215de4e1f8bb85e0f4216760fa33fd024b4526b144f4ce0d9012b29c9e +LINUX_VERSION-6.12 = .8 +LINUX_KERNEL_HASH-6.12.8 = 2291da065ca04b715c89ee50362aec3f021a7414bc963f1b56736682c8122979 diff --git a/tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch b/tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch new file mode 100644 index 000000000..cb97b0dc2 --- /dev/null +++ b/tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch @@ -0,0 +1,26 @@ +From 1cee5373b2576bff7e1d072d7a5bfee3081b039d Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 3 Jan 2025 21:24:06 +0800 +Subject: [PATCH] Revert "phy: rockchip: naneng-combphy: fix phy reset" + +This reverts commit 5cdf336412a928ae0f05a3117b3132366a1f7d21. +--- + drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +index 2eb3329ca..0a9989e41 100644 +--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c ++++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +@@ -309,7 +309,7 @@ static int rockchip_combphy_parse_dt(struct device *dev, struct rockchip_combphy + + priv->ext_refclk = device_property_present(dev, "rockchip,ext-refclk"); + +- priv->phy_rst = devm_reset_control_get(dev, "phy"); ++ priv->phy_rst = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(priv->phy_rst)) + return dev_err_probe(dev, PTR_ERR(priv->phy_rst), "failed to get phy reset\n"); + +-- +2.42.0 + diff --git a/tags/patches/patch.list b/tags/patches/patch.list new file mode 100644 index 000000000..bb5da4580 --- /dev/null +++ b/tags/patches/patch.list @@ -0,0 +1 @@ +0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch From 886a9c40b176c6c61971373f8bb3ce1f2e6a33b4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 6 Jan 2025 21:57:46 +0800 Subject: [PATCH 177/425] OpenWrt 24.10.0-rc5 Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 3 --- tags/v24 | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index bb3818546..a1372fc1f 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,8 +1,5 @@ #!/bin/bash -# fix luci-base - rc4 -sed -i 's|\[sid\].hasOwnProperty|\[sid\]?.hasOwnProperty|g' feeds/luci/modules/luci-base/htdocs/luci-static/resources/uci.js - # apk-tools curl -s $mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch diff --git a/tags/v24 b/tags/v24 index 1b25acfcd..17499afca 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.0-rc4 +24.10.0-rc5 From 84f4a3458c0eba8a4f8901830058c2a27051b534 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 10 Jan 2025 12:10:45 +0800 Subject: [PATCH 178/425] linux-6.12: bump to 6.12.9 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 5 ---- tags/kernel-6.12 | 4 +-- ...ockchip-naneng-combphy-fix-phy-reset.patch | 26 ------------------- tags/patches/patch.list | 1 - 4 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch delete mode 100644 tags/patches/patch.list diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 8a6140d97..0c715ecd6 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -57,11 +57,6 @@ else fi cp -a target/linux/generic-6.12/* target/linux/generic -# additional patches -curl -s $mirror/tags/patches/patch.list | while read -r patch_file; do - curl -s $mirror/tags/patches/$patch_file > target/linux/generic/hack-6.12/$patch_file -done - # bcm53xx - fix build kernel with clang [ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch target/linux/generic/hack-6.12/220-arm-gc_sections.patch diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 6197298a1..364947186 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .8 -LINUX_KERNEL_HASH-6.12.8 = 2291da065ca04b715c89ee50362aec3f021a7414bc963f1b56736682c8122979 +LINUX_VERSION-6.12 = .9 +LINUX_KERNEL_HASH-6.12.9 = 87be0360df0931b340d2bac35161a548070fbc3a8c352c49e21e96666c26aeb4 diff --git a/tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch b/tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch deleted file mode 100644 index cb97b0dc2..000000000 --- a/tags/patches/0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 1cee5373b2576bff7e1d072d7a5bfee3081b039d Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Fri, 3 Jan 2025 21:24:06 +0800 -Subject: [PATCH] Revert "phy: rockchip: naneng-combphy: fix phy reset" - -This reverts commit 5cdf336412a928ae0f05a3117b3132366a1f7d21. ---- - drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c -index 2eb3329ca..0a9989e41 100644 ---- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c -+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c -@@ -309,7 +309,7 @@ static int rockchip_combphy_parse_dt(struct device *dev, struct rockchip_combphy - - priv->ext_refclk = device_property_present(dev, "rockchip,ext-refclk"); - -- priv->phy_rst = devm_reset_control_get(dev, "phy"); -+ priv->phy_rst = devm_reset_control_array_get_exclusive(dev); - if (IS_ERR(priv->phy_rst)) - return dev_err_probe(dev, PTR_ERR(priv->phy_rst), "failed to get phy reset\n"); - --- -2.42.0 - diff --git a/tags/patches/patch.list b/tags/patches/patch.list deleted file mode 100644 index bb5da4580..000000000 --- a/tags/patches/patch.list +++ /dev/null @@ -1 +0,0 @@ -0001-Revert-phy-rockchip-naneng-combphy-fix-phy-reset.patch From 715afb1d94604b67ebc3bc39f0b7bc34f47d5027 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 12 Jan 2025 17:49:06 +0800 Subject: [PATCH 179/425] Revert "openwrt-24.10: dnsmasq: fix compatibility issues" This reverts commit 5be0bc52feb3e01cc789882a9cdc9f986e4c7bed. Signed-off-by: sbwml --- ...dnsmasq-drop-extraconftext-parameter.patch | 54 - openwrt/patch/dnsmasq/dnsmasq.init | 1372 ----------------- openwrt/scripts/00-prepare_base.sh | 6 - 3 files changed, 1432 deletions(-) delete mode 100644 openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch delete mode 100644 openwrt/patch/dnsmasq/dnsmasq.init diff --git a/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch b/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch deleted file mode 100644 index 7717b2faa..000000000 --- a/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 01e9c5d991cbe0dad0283e102be9c5570f4549f6 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Tue, 22 Oct 2024 21:00:28 +0800 -Subject: [PATCH] dnsmasq: drop 'extraconftext' parameter - -Signed-off-by: sbwml ---- - .../services/dnsmasq/files/dnsmasq.init | 23 ++++++------------- - 1 file changed, 7 insertions(+), 16 deletions(-) - -diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init -index b864ea9069..96110c2b38 100755 ---- a/package/network/services/dnsmasq/files/dnsmasq.init -+++ b/package/network/services/dnsmasq/files/dnsmasq.init -@@ -12,7 +12,6 @@ ADD_WAN_FQDN=0 - ADD_LOCAL_FQDN="" - - BASECONFIGFILE="/var/etc/dnsmasq.conf" --EXTRACONFFILE="extraconfig.conf" - BASEHOSTFILE="/tmp/hosts/dhcp" - TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf" - TIMEVALIDFILE="/var/state/dnsmasqsec" -@@ -1145,21 +1144,13 @@ dnsmasq_start() - xappend "--dhcp-broadcast=tag:needs-broadcast" - - -- # Create a dnsmasq.d dir for each instance -- config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq${cfg:+.$cfg}.d" -- # Ensure dnsmasqconfdir is an absolute path -- [ "${dnsmasqconfdir:0:1}" = '/' ] && { -- xappend "--conf-dir=$dnsmasqconfdir" -- dnsmasqconfdir="${dnsmasqconfdir%%,*}" -- [ ! -d "$dnsmasqconfdir" ] && mkdir -p "$dnsmasqconfdir" -- xappend "--user=dnsmasq" -- xappend "--group=dnsmasq" -- echo >> "$CONFIGFILE_TMP" -- -- # EXTRACONFFILE allows new dnsmasq parameters before they are natively handled in this init file -- config_get extraconftext "$cfg" extraconftext -- [ -n "$extraconftext" ] && echo -e "$extraconftext" > "$dnsmasqconfdir"/"$EXTRACONFFILE" -- } -+ config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d" -+ xappend "--conf-dir=$dnsmasqconfdir" -+ dnsmasqconfdir="${dnsmasqconfdir%%,*}" -+ [ ! -d "$dnsmasqconfdir" ] && mkdir -p "$dnsmasqconfdir" -+ xappend "--user=dnsmasq" -+ xappend "--group=dnsmasq" -+ echo >> "$CONFIGFILE_TMP" - - config_get_bool enable_tftp "$cfg" enable_tftp 0 - [ "$enable_tftp" -gt 0 ] && { --- -2.42.0 - diff --git a/openwrt/patch/dnsmasq/dnsmasq.init b/openwrt/patch/dnsmasq/dnsmasq.init deleted file mode 100644 index 96110c2b3..000000000 --- a/openwrt/patch/dnsmasq/dnsmasq.init +++ /dev/null @@ -1,1372 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2007-2012 OpenWrt.org - -START=19 - -USE_PROCD=1 -PROG=/usr/sbin/dnsmasq - -ADD_LOCAL_DOMAIN=1 -ADD_LOCAL_HOSTNAME=1 -ADD_WAN_FQDN=0 -ADD_LOCAL_FQDN="" - -BASECONFIGFILE="/var/etc/dnsmasq.conf" -BASEHOSTFILE="/tmp/hosts/dhcp" -TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf" -TIMEVALIDFILE="/var/state/dnsmasqsec" -BASEDHCPSTAMPFILE="/var/run/dnsmasq" -DHCPBOGUSHOSTNAMEFILE="/usr/share/dnsmasq/dhcpbogushostname.conf" -RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf" -DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh" -DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus" - -DNSMASQ_DHCP_VER=4 - -dnsmasq_ignore_opt() { - local opt="$1" - - if [ -z "$dnsmasq_features" ]; then - dnsmasq_features="$(dnsmasq --version | grep -m1 'Compile time options:' | cut -d: -f2) " - [ "${dnsmasq_features#* DHCP }" = "$dnsmasq_features" ] || dnsmasq_has_dhcp=1 - [ "${dnsmasq_features#* DHCPv6 }" = "$dnsmasq_features" ] || dnsmasq_has_dhcp6=1 - [ "${dnsmasq_features#* DNSSEC }" = "$dnsmasq_features" ] || dnsmasq_has_dnssec=1 - [ "${dnsmasq_features#* TFTP }" = "$dnsmasq_features" ] || dnsmasq_has_tftp=1 - [ "${dnsmasq_features#* ipset }" = "$dnsmasq_features" ] || dnsmasq_has_ipset=1 - [ "${dnsmasq_features#* nftset }" = "$dnsmasq_features" ] || dnsmasq_has_nftset=1 - fi - - case "$opt" in - dhcp-duid|\ - ra-param) - [ -z "$dnsmasq_has_dhcp6" ] ;; - dhcp-*|\ - bootp-*|\ - pxe-*) - [ -z "$dnsmasq_has_dhcp" ] ;; - dnssec*|\ - trust-anchor) - if [ -z "$dnsmasq_has_dnssec" ]; then - echo "dnsmasq: \"$opt\" requested, but dnssec support is not available" >&2 - exit 1 - fi - return 1 - ;; - tftp-*) - [ -z "$dnsmasq_has_tftp" ] ;; - ipset) - [ -z "$dnsmasq_has_ipset" ] ;; - nftset) - [ -z "$dnsmasq_has_nftset" ] ;; - *) - return 1 - esac -} - -xappend() { - local value="${1#--}" - local opt="${value%%=*}" - - if ! dnsmasq_ignore_opt "$opt"; then - echo "$value" >>"$CONFIGFILE_TMP" - fi -} - -hex_to_hostid() { - local var="$1" - local hex="${2#0x}" # strip optional "0x" prefix - - if [ -n "${hex//[0-9a-fA-F]/}" ]; then - # is invalid hex literal - return 1 - fi - - # convert into host id - export "$var=$( - printf "%0x:%0x" \ - $(((0x$hex >> 16) % 65536)) \ - $(( 0x$hex % 65536)) - )" - - return 0 -} - -dhcp_calc() { - local ip="$1" - local res=0 - - while [ -n "$ip" ]; do - part="${ip%%.*}" - res="$(($res * 256))" - res="$(($res + $part))" - [ "${ip%.*}" != "$ip" ] && ip="${ip#*.}" || ip= - done - echo "$res" -} - -dhcp_check() { - local ifname="$1" - local stamp="${BASEDHCPSTAMPFILE_CFG}.${ifname}.dhcp" - local rv=0 - - [ -s "$stamp" ] && return $(cat "$stamp") - - # If interface is down, skip it. - # The init script will be called again once the link is up - case "$(devstatus "$ifname" | jsonfilter -e @.up)" in - false) return 1;; - esac - - udhcpc -n -q -s /bin/true -t 1 -i "$ifname" >&- && rv=1 || rv=0 - - echo $rv > "$stamp" - return $rv -} - -log_once() { - pidof dnsmasq >/dev/null || \ - logger -t dnsmasq "$@" -} - -has_handler() { - local file - - for file in /etc/hotplug.d/dhcp/* /etc/hotplug.d/tftp/* /etc/hotplug.d/neigh/*; do - [ -f "$file" ] && return 0 - done - - return 1 -} - -append_bool() { - local section="$1" - local option="$2" - local value="$3" - local default="$4" - local _loctmp - [ -z "$default" ] && default="0" - config_get_bool _loctmp "$section" "$option" "$default" - [ $_loctmp -gt 0 ] && xappend "$value" -} - -append_parm() { - local section="$1" - local option="$2" - local switch="$3" - local default="$4" - local _loctmp - config_get _loctmp "$section" "$option" "$default" - [ -z "$_loctmp" ] && return 0 - xappend "$switch=$_loctmp" -} - -append_server() { - xappend "--server=$1" -} - -append_rev_server() { - xappend "--rev-server=$1" -} - -append_address() { - xappend "--address=$1" -} - -append_connmark_allowlist() { - xappend "--connmark-allowlist=$1" -} - -append_interface() { - network_get_device ifname "$1" || ifname="$1" - xappend "--interface=$ifname" -} - -append_listenaddress() { - xappend "--listen-address=$1" -} - -append_notinterface() { - network_get_device ifname "$1" || ifname="$1" - xappend "--except-interface=$ifname" -} - -ismounted() { - local filename="$1" - local dirname - for dirname in $EXTRA_MOUNT ; do - case "$filename" in - "${dirname}/"* | "${dirname}" ) - return 0 - ;; - esac - done - - return 1 -} - -append_extramount() { - ismounted "$1" || append EXTRA_MOUNT "$1" -} - -append_addnhosts() { - append_extramount "$1" - xappend "--addn-hosts=$1" -} - -append_bogusnxdomain() { - xappend "--bogus-nxdomain=$1" -} - -append_pxe_service() { - xappend "--pxe-service=$1" -} - -append_interface_name() { - xappend "--interface-name=$1,$2" -} - -filter_dnsmasq() { - local cfg="$1" func="$2" match_cfg="$3" found_cfg - - # use entry when no instance entry set, or if it matches - config_get found_cfg "$cfg" "instance" - if [ -z "$found_cfg" ] || [ "$found_cfg" = "$match_cfg" ]; then - $func $cfg - fi -} - -dhcp_subscrid_add() { - local cfg="$1" - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || return 0 - - config_get subscriberid "$cfg" subscriberid - [ -n "$subscriberid" ] || return 0 - - xappend "--dhcp-subscrid=set:$networkid,$subscriberid" - - config_get_bool force "$cfg" force 0 - - dhcp_option_add "$cfg" "$networkid" "$force" -} - -dhcp_remoteid_add() { - local cfg="$1" - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || return 0 - - config_get remoteid "$cfg" remoteid - [ -n "$remoteid" ] || return 0 - - xappend "--dhcp-remoteid=set:$networkid,$remoteid" - - config_get_bool force "$cfg" force 0 - - dhcp_option_add "$cfg" "$networkid" "$force" -} - -dhcp_circuitid_add() { - # TODO: DHCPV6 does not have circuitid; catch "option6:" - local cfg="$1" - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || return 0 - - config_get circuitid "$cfg" circuitid - [ -n "$circuitid" ] || return 0 - - xappend "--dhcp-circuitid=set:$networkid,$circuitid" - - config_get_bool force "$cfg" force 0 - - dhcp_option_add "$cfg" "$networkid" "$force" -} - -dhcp_userclass_add() { - local cfg="$1" - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || return 0 - - config_get userclass "$cfg" userclass - [ -n "$userclass" ] || return 0 - - xappend "--dhcp-userclass=set:$networkid,$userclass" - - config_get_bool force "$cfg" force 0 - - dhcp_option_add "$cfg" "$networkid" "$force" -} - -dhcp_vendorclass_add() { - # TODO: DHCPV6 vendor class has stricter definitions; catch? fixup? - local cfg="$1" - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || return 0 - - config_get vendorclass "$cfg" vendorclass - [ -n "$vendorclass" ] || return 0 - - xappend "--dhcp-vendorclass=set:$networkid,$vendorclass" - - config_get_bool force "$cfg" force 0 - - dhcp_option_add "$cfg" "$networkid" "$force" -} - -dhcp_match_add() { - local cfg="$1" - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || return 0 - - config_get match "$cfg" match - [ -n "$match" ] || return 0 - - xappend "--dhcp-match=set:$networkid,$match" - - config_get_bool force "$cfg" force 0 - - dhcp_option_add "$cfg" "$networkid" "$force" -} - -dhcp_host_add() { - local cfg="$1" - local hosttag nametime addrs duids macs tags mtags - - config_get_bool force "$cfg" force 0 - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] && dhcp_option_add "$cfg" "$networkid" "$force" - - config_get_bool enable "$cfg" enable 1 - [ "$enable" = "0" ] && return 0 - - config_get name "$cfg" name - config_get ip "$cfg" ip - config_get hostid "$cfg" hostid - - [ -z "$ip" ] && [ -z "$name" ] && [ -z "$hostid" ] && return 0 - - config_get_bool dns "$cfg" dns 0 - [ "$dns" = "1" ] && [ -n "$ip" ] && [ -n "$name" ] && { - echo "$ip $name${DOMAIN:+.$DOMAIN}" >> "$HOSTFILE_TMP" - } - - config_get mac "$cfg" mac - config_get duid "$cfg" duid - config_get tag "$cfg" tag - - add_tag() { - mtags="${mtags}tag:$1," - } - config_list_foreach "$cfg" match_tag add_tag - - if [ -n "$mac" ]; then - # --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap - # many MAC are possible to track a laptop ON/OFF dock - for m in $mac; do append macs "$m" ","; done - fi - - if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ -n "$duid" ]; then - # --dhcp-host=id:00:03:00:01:12:00:00:01:02:03,[::beef],lap - # one (virtual) machine gets one DUID per RFC3315 - duids="id:${duid// */}" - fi - - if [ -z "$macs" ] && [ -z "$duids" ]; then - # --dhcp-host=lap,192.168.0.199,[::beef] - [ -n "$name" ] || return 0 - macs="$name" - name="" - fi - - if [ -n "$hostid" ]; then - hex_to_hostid hostid "$hostid" - fi - - if [ -n "$tag" ]; then - for t in $tag; do append tags "$t" ",set:"; done - fi - - config_get_bool broadcast "$cfg" broadcast 0 - config_get leasetime "$cfg" leasetime - - [ "$broadcast" = "0" ] && broadcast= || broadcast=",set:needs-broadcast" - - hosttag="${networkid:+,set:${networkid}}${tags:+,set:${tags}}$broadcast" - nametime="${name:+,$name}${leasetime:+,$leasetime}" - - if [ $DNSMASQ_DHCP_VER -eq 6 ]; then - addrs="${ip:+,$ip}${hostid:+,[::$hostid]}" - xappend "--dhcp-host=$mtags$macs${duids:+,$duids}$hosttag$addrs$nametime" - else - xappend "--dhcp-host=$mtags$macs$hosttag${ip:+,$ip}$nametime" - fi -} - -dhcp_this_host_add() { - local net="$1" - local ifname="$2" - local mode="$3" - local routerstub routername ifdashname - local lanaddr lanaddr6 lanaddrs6 ulaprefix - - if [ "$mode" -gt 0 ] ; then - ifdashname="${ifname//./-}" - routerstub="$( md5sum /etc/os-release )" - routerstub="router-${routerstub// */}" - routername="$( uci_get system @system[0] hostname $routerstub )" - - if [ "$mode" -gt 1 ] ; then - if [ "$mode" -gt 2 ] ; then - if [ "$mode" -gt 3 ] ; then - append_interface_name "$ifdashname.$routername.$DOMAIN" "$ifname" - fi - - append_interface_name "$routername.$DOMAIN" "$ifname" - fi - - # All IP addresses discovered by dnsmasq will be labeled (except fe80::) - append_interface_name "$routername" "$ifname" - - else - # This uses a static host file entry for only limited addresses. - # Use dnsmasq option "--expandhosts" to enable FQDN on host files. - ulaprefix="$(uci_get network @globals[0] ula_prefix)" - network_get_ipaddr lanaddr "$net" - network_get_ipaddrs6 lanaddrs6 "$net" - - if [ -n "$lanaddr" ] ; then - dhcp_domain_add "" "$routername" "$lanaddr" - fi - - if [ -n "$ulaprefix" ] && [ -n "$lanaddrs6" ] ; then - for lanaddr6 in $lanaddrs6 ; do - case "$lanaddr6" in - "${ulaprefix%%:/*}"*) - dhcp_domain_add "" "$routername" "$lanaddr6" - ;; - esac - done - fi - fi - fi -} - -dhcp_tag_add() { - # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions - local cfg="$1" - - tag="$cfg" - - [ -n "$tag" ] || return 0 - - config_get_bool force "$cfg" force 0 - [ "$force" = "0" ] && force= - - config_get option "$cfg" dhcp_option - for o in $option; do - xappend "--dhcp-option${force:+-force}=tag:$tag,$o" - done -} - -dhcp_mac_add() { - local cfg="$1" - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || return 0 - - config_get mac "$cfg" mac - [ -n "$mac" ] || return 0 - - xappend "--dhcp-mac=$networkid,$mac" - - dhcp_option_add "$cfg" "$networkid" -} - -dhcp_boot_add() { - # TODO: BOOTURL is different between DHCPv4 and DHCPv6 - local cfg="$1" - - config_get networkid "$cfg" networkid - - config_get filename "$cfg" filename - [ -n "$filename" ] || return 0 - - config_get servername "$cfg" servername - config_get serveraddress "$cfg" serveraddress - - [ -n "$serveraddress" ] && [ ! -n "$servername" ] && return 0 - - xappend "--dhcp-boot=${networkid:+tag:$networkid,}${filename}${servername:+,$servername}${serveraddress:+,$serveraddress}" - - config_get_bool force "$cfg" force 0 - - dhcp_option_add "$cfg" "$networkid" "$force" -} - -dhcp_add() { - local cfg="$1" - local dhcp6range="::" - local nettag - local tags - - config_get net "$cfg" interface - [ -n "$net" ] || return 0 - - config_get networkid "$cfg" networkid - [ -n "$networkid" ] || networkid="$net" - - network_get_device ifname "$net" || return 0 - - [ "$cachelocal" = "0" ] && network_get_dnsserver dnsserver "$net" && { - DNS_SERVERS="$DNS_SERVERS $dnsserver" - } - - append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && { - # Many ISP do not have useful names for DHCP customers (your WAN). - dhcp_this_host_add "$net" "$ifname" "$ADD_WAN_FQDN" - return 0 - } - - network_get_subnet subnet "$net" || return 0 - network_get_protocol proto "$net" || return 0 - - # Do not support non-static interfaces for now - [ static = "$proto" ] || return 0 - - ipaddr="${subnet%%/*}" - prefix_or_netmask="${subnet##*/}" - - # Override interface netmask with dhcp config if applicable - config_get netmask "$cfg" netmask - - [ -n "$netmask" ] && prefix_or_netmask="$netmask" - - #check for an already active dhcp server on the interface, unless 'force' is set - config_get_bool force "$cfg" force 0 - [ $force -gt 0 ] || dhcp_check "$ifname" || { - logger -t dnsmasq \ - "found already running DHCP-server on interface '$ifname'" \ - "refusing to start, use 'option force 1' to override" - return 0 - } - - config_get start "$cfg" start 100 - config_get limit "$cfg" limit 150 - config_get leasetime "$cfg" leasetime 12h - config_get options "$cfg" options - config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1 - config_get_bool dynamicdhcpv4 "$cfg" dynamicdhcpv4 $dynamicdhcp - config_get_bool dynamicdhcpv6 "$cfg" dynamicdhcpv6 $dynamicdhcp - - config_get dhcpv4 "$cfg" dhcpv4 - config_get dhcpv6 "$cfg" dhcpv6 - - config_get ra "$cfg" ra - config_get ra_management "$cfg" ra_management - config_get ra_preference "$cfg" ra_preference - config_get dns "$cfg" dns - config_get dns_sl "$cfg" domain - - config_list_foreach "$cfg" "interface_name" append_interface_name "$ifname" - - # Put the router host name on this DHCP served interface address(es) - dhcp_this_host_add "$net" "$ifname" "$ADD_LOCAL_FQDN" - - start="$( dhcp_calc "$start" )" - - add_tag() { - tags="${tags}tag:$1," - } - config_list_foreach "$cfg" tag add_tag - - nettag="${networkid:+set:${networkid},}" - - # make sure the DHCP range is not empty - if [ "$dhcpv4" != "disabled" ] && ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit" ; then - [ "$dynamicdhcpv4" = "0" ] && END="static" - - xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}" - fi - - if [ "$dynamicdhcpv6" = "0" ] ; then - dhcp6range="::,static" - else - dhcp6range="::1000,::ffff" - fi - - - if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ "$ra" = "server" ] ; then - # Note: dnsmasq cannot just be a DHCPv6 server (all-in-1) - # and let some other machine(s) send RA pointing to it. - - case $ra_preference in - *high*) - xappend "--ra-param=$ifname,high,0,7200" - ;; - *low*) - xappend "--ra-param=$ifname,low,0,7200" - ;; - *) - # Send UNSOLICITED RA at default interval and live for 2 hours. - # TODO: convert flexible lease time into route life time (only seconds). - xappend "--ra-param=$ifname,0,7200" - ;; - esac - - if [ "$dhcpv6" = "disabled" ] ; then - ra_management="3" - fi - - - case $ra_management in - 0) - # SLACC with DCHP for extended options - xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-stateless,ra-names" - ;; - 2) - # DHCP address and RA only for management redirection - xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,$leasetime" - ;; - 3) - # SLAAC only but dnsmasq attempts to link HOSTNAME, DHCPv4 MAC, and SLAAC - xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-only,ra-names" - ;; - *) - # SLAAC and full DHCP - xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,slaac,ra-names,$leasetime" - ;; - esac - - if [ -n "$dns" ]; then - dnss="" - for d in $dns; do append dnss "[$d]" ","; done - else - dnss="[::]" - fi - - dhcp_option_append "option6:dns-server,$dnss" "$networkid" - - if [ -n "$dns_sl" ]; then - ddssl="" - for dd in $dns_sl; do append ddssl "$dd" ","; done - fi - - dhcp_option_append "option6:domain-search,$ddssl" "$networkid" - fi - - dhcp_option_add "$cfg" "$networkid" 0 - dhcp_option_add "$cfg" "$networkid" 2 -} - -dhcp_option_append() { - local option="$1" - local networkid="$2" - local force="$3" - - xappend "--dhcp-option${force:+-force}=${networkid:+$networkid,}$option" -} - -dhcp_option_add() { - # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions - local cfg="$1" - local networkid="$2" - local force="$3" - local opt="dhcp_option" - - [ "$force" = "0" ] && force= - [ "$force" = "2" ] && opt="dhcp_option_force" - - local list_len - config_get list_len "$cfg" "${opt}_LENGTH" - - if [ -n "$list_len" ]; then - config_list_foreach "$cfg" "$opt" dhcp_option_append "$networkid" "$force" - else - config_get dhcp_option "$cfg" "$opt" - - [ -n "$dhcp_option" ] && echo "Warning: the 'option $opt' syntax is deprecated, use 'list $opt'" >&2 - - local option - for option in $dhcp_option; do - dhcp_option_append "$option" "$networkid" "$force" - done - fi -} - -dhcp_domain_add() { - local cfg="$1" - local ip name names record - - config_get names "$cfg" name "$2" - [ -n "$names" ] || return 0 - - config_get ip "$cfg" ip "$3" - [ -n "$ip" ] || return 0 - - for name in $names; do - record="${record:+$record }$name" - done - - echo "$ip $record" >> "$HOSTFILE_TMP" -} - -dhcp_srv_add() { - local cfg="$1" - - config_get srv "$cfg" srv - [ -n "$srv" ] || return 0 - - config_get target "$cfg" target - [ -n "$target" ] || return 0 - - config_get port "$cfg" port - [ -n "$port" ] || return 0 - - config_get class "$cfg" class - config_get weight "$cfg" weight - - local service="$srv,$target,$port${class:+,$class${weight:+,$weight}}" - - xappend "--srv-host=$service" -} - -dhcp_mx_add() { - local cfg="$1" - local domain relay pref - - config_get domain "$cfg" domain - [ -n "$domain" ] || return 0 - - config_get relay "$cfg" relay - [ -n "$relay" ] || return 0 - - config_get pref "$cfg" pref 0 - - local service="$domain,$relay,$pref" - - xappend "--mx-host=$service" -} - -dhcp_cname_add() { - local cfg="$1" - local cname target - - config_get cname "$cfg" cname - [ -n "$cname" ] || return 0 - - config_get target "$cfg" target - [ -n "$target" ] || return 0 - - xappend "--cname=${cname},${target}" -} - -dhcp_hostrecord_add() { - local cfg="$1" - local names addresses record val - - config_get names "$cfg" name "$2" - if [ -z "$names" ]; then - return 0 - fi - - config_get addresses "$cfg" ip "$3" - if [ -z "$addresses" ]; then - return 0 - fi - - for val in $names $addresses; do - record="${record:+$record,}$val" - done - - xappend "--host-record=$record" -} - -dhcp_dnsrr_add() { - #This adds arbitrary resource record types (of IN class) whose optional data must be hex - local cfg="$1" - local rrname rrnumber hexdata - - config_get rrname "$cfg" rrname - [ -n "$rrname" ] || return 0 - - config_get rrnumber "$cfg" rrnumber - [ -n "$rrnumber" ] && [ "$rrnumber" -gt 0 ] || return 0 - - config_get hexdata "$cfg" hexdata - - # dnsmasq accepts colon XX:XX:.., space XX XX .., or contiguous XXXX.. hex forms or mixtures thereof - if [ -n "${hexdata//[0-9a-fA-F\:\ ]/}" ]; then - # is invalid hex literal - echo "dnsmasq: \"$hexdata\" is malformed hexadecimal (separate hex with colon, space or not at all)." >&2 - return 1 - fi - - xappend "--dns-rr=${rrname},${rrnumber}${hexdata:+,$hexdata}" -} - -dhcp_relay_add() { - local cfg="$1" - local local_addr server_addr interface - - config_get local_addr "$cfg" local_addr - [ -n "$local_addr" ] || return 0 - - config_get server_addr "$cfg" server_addr - [ -n "$server_addr" ] || return 0 - - config_get interface "$cfg" interface - if [ -z "$interface" ]; then - xappend "--dhcp-relay=$local_addr,$server_addr" - else - network_get_device ifname "$interface" || return - xappend "--dhcp-relay=$local_addr,$server_addr,$ifname" - fi -} - -dnsmasq_ipset_add() { - local cfg="$1" - local ipsets nftsets domains - - add_ipset() { - ipsets="${ipsets:+$ipsets,}$1" - } - - add_nftset() { - local IFS=, - for set in $1; do - local fam="$family" - [ -n "$fam" ] || fam=$(echo "$set" | sed -nre \ - 's#^.*[^0-9]([46])$|^.*[-_]([46])[-_].*$|^([46])[^0-9].*$#\1\2\3#p') - [ -n "$fam" ] || \ - fam=$(nft -t list set "$table_family" "$table" "$set" 2>&1 | sed -nre \ - 's#^\t\ttype .*\bipv([46])_addr\b.*$#\1#p') - - [ -n "$fam" ] || \ - logger -t dnsmasq "Cannot infer address family from non-existent nftables set '$set'" - - nftsets="${nftsets:+$nftsets,}${fam:+$fam#}$table_family#$table#$set" - done - } - - add_domain() { - # leading '/' is expected - domains="$domains/$1" - } - - config_get table "$cfg" table 'fw4' - config_get table_family "$cfg" table_family 'inet' - if [ "$table_family" = "ip" ] ; then - family="4" - elif [ "$table_family" = "ip6" ] ; then - family="6" - else - config_get family "$cfg" family - fi - - config_list_foreach "$cfg" "name" add_ipset - config_list_foreach "$cfg" "name" add_nftset - config_list_foreach "$cfg" "domain" add_domain - - if [ -z "$ipsets" ] || [ -z "$nftsets" ] || [ -z "$domains" ]; then - return 0 - fi - - xappend "--ipset=$domains/$ipsets" - xappend "--nftset=$domains/$nftsets" -} - -dnsmasq_start() -{ - local cfg="$1" - local disabled user_dhcpscript logfacility - local resolvfile resolvdir localuse=1 - - config_get_bool disabled "$cfg" disabled 0 - [ "$disabled" -gt 0 ] && return 0 - - # reset list of DOMAINS, DNS servers and EXTRA mounts (for each dnsmasq instance) - DNS_SERVERS="" - DOMAIN="" - EXTRA_MOUNT="" - CONFIGFILE="${BASECONFIGFILE}.${cfg}" - CONFIGFILE_TMP="${CONFIGFILE}.$$" - HOSTFILE="${BASEHOSTFILE}.${cfg}" - HOSTFILE_TMP="${HOSTFILE}.$$" - HOSTFILE_DIR="$(dirname "$HOSTFILE")" - BASEDHCPSTAMPFILE_CFG="${BASEDHCPSTAMPFILE}.${cfg}" - - # before we can call xappend - umask u=rwx,g=rx,o=rx - mkdir -p /var/run/dnsmasq/ - mkdir -p "$(dirname "$CONFIGFILE")" - mkdir -p "$HOSTFILE_DIR" - mkdir -p /var/lib/misc - chown dnsmasq:dnsmasq /var/run/dnsmasq - - echo "# auto-generated config file from /etc/config/dhcp" > "$CONFIGFILE_TMP" - echo "# auto-generated config file from /etc/config/dhcp" > "$HOSTFILE_TMP" - - local dnsmasqconffile="/etc/dnsmasq.${cfg}.conf" - if [ ! -r "$dnsmasqconffile" ]; then - dnsmasqconffile=/etc/dnsmasq.conf - fi - - # if we did this last, we could override auto-generated config - [ -f "${dnsmasqconffile}" ] && { - xappend "--conf-file=${dnsmasqconffile}" - } - - $PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0 - - - if [ -x /usr/sbin/odhcpd ] && [ -x /etc/init.d/odhcpd ] ; then - local odhcpd_is_main odhcpd_is_enabled - config_get odhcpd_is_main odhcpd maindhcp 0 - /etc/init.d/odhcpd enabled && odhcpd_is_enabled=1 || odhcpd_is_enabled=0 - - - if [ "$odhcpd_is_enabled" -eq 0 ] && [ "$DHCPv6CAPABLE" -eq 1 ] ; then - # DHCP V4 and V6 in DNSMASQ - DNSMASQ_DHCP_VER=6 - elif [ "$odhcpd_is_main" -gt 0 ] ; then - # ODHCPD is doing it all - DNSMASQ_DHCP_VER=0 - else - # You have ODHCPD but use DNSMASQ for DHCPV4 - DNSMASQ_DHCP_VER=4 - fi - - elif [ "$DHCPv6CAPABLE" -eq 1 ] ; then - # DHCP V4 and V6 in DNSMASQ - DNSMASQ_DHCP_VER=6 - else - DNSMASQ_DHCP_VER=4 - fi - - # Allow DHCP/DHCPv6 to be handled by ISC DHCPD - if [ -x /usr/sbin/dhcpd ] ; then - if [ -x /etc/init.d/dhcpd ] ; then - /etc/init.d/dhcpd enabled && DNSMASQ_DHCP_VER=0 - fi - if [ -x /etc/init.d/dhcpd6 ] && [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then - /etc/init.d/dhcpd6 enabled && DNSMASQ_DHCP_VER=4 - fi - fi - - append_bool "$cfg" authoritative "--dhcp-authoritative" - append_bool "$cfg" nodaemon "--no-daemon" - append_bool "$cfg" domainneeded "--domain-needed" - append_bool "$cfg" filterwin2k "--filterwin2k" - append_bool "$cfg" nohosts "--no-hosts" - append_bool "$cfg" nonegcache "--no-negcache" - append_bool "$cfg" strictorder "--strict-order" - append_bool "$cfg" logqueries "--log-queries=extra" - append_bool "$cfg" noresolv "--no-resolv" - append_bool "$cfg" localise_queries "--localise-queries" - append_bool "$cfg" readethers "--read-ethers" - - local instance_name="dnsmasq.$cfg" - if [ "$cfg" = "$DEFAULT_INSTANCE" ]; then - instance_name="dnsmasq" - fi - config_get_bool dbus "$cfg" "dbus" 0 - [ $dbus -gt 0 ] && xappend "--enable-dbus=uk.org.thekelleys.$instance_name" - config_get_bool ubus "$cfg" "ubus" 1 - [ $ubus -gt 0 ] && xappend "--enable-ubus=$instance_name" - - append_bool "$cfg" expandhosts "--expand-hosts" - config_get tftp_root "$cfg" "tftp_root" - [ -n "$tftp_root" ] && mkdir -p "$tftp_root" && append_bool "$cfg" enable_tftp "--enable-tftp" - append_bool "$cfg" tftp_no_fail "--tftp-no-fail" - append_bool "$cfg" nonwildcard "--bind-dynamic" 1 - append_bool "$cfg" fqdn "--dhcp-fqdn" - append_bool "$cfg" proxydnssec "--proxy-dnssec" - append_bool "$cfg" localservice "--local-service" - append_bool "$cfg" logdhcp "--log-dhcp" - append_bool "$cfg" quietdhcp "--quiet-dhcp" - append_bool "$cfg" sequential_ip "--dhcp-sequential-ip" - append_bool "$cfg" allservers "--all-servers" - append_bool "$cfg" noping "--no-ping" - append_bool "$cfg" rapidcommit "--dhcp-rapid-commit" - append_bool "$cfg" scriptarp "--script-arp" - - # deprecate or remove filter-X in favor of filter-rr? - append_bool "$cfg" filter_aaaa "--filter-AAAA" - append_bool "$cfg" filter_a "--filter-A" - append_parm "$cfg" filter_rr "--filter-rr" - append_parm "$cfg" cache_rr "--cache-rr" - - append_parm "$cfg" logfacility "--log-facility" - config_get logfacility "$cfg" "logfacility" - append_parm "$cfg" cachesize "--cache-size" - append_parm "$cfg" dnsforwardmax "--dns-forward-max" - append_parm "$cfg" port "--port" - append_parm "$cfg" ednspacket_max "--edns-packet-max" - append_parm "$cfg" dhcpleasemax "--dhcp-lease-max" - append_parm "$cfg" "queryport" "--query-port" - append_parm "$cfg" "minport" "--min-port" - append_parm "$cfg" "maxport" "--max-port" - append_parm "$cfg" "domain" "--domain" - append_parm "$cfg" "local" "--local" - config_list_foreach "$cfg" "listen_address" append_listenaddress - config_list_foreach "$cfg" "server" append_server - config_list_foreach "$cfg" "rev_server" append_rev_server - config_list_foreach "$cfg" "address" append_address - - local connmark_allowlist_enable - config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0 - [ "$connmark_allowlist_enable" -gt 0 ] && { - append_parm "$cfg" "connmark_allowlist_enable" "--connmark-allowlist-enable" - config_list_foreach "$cfg" "connmark_allowlist" append_connmark_allowlist - } - - [ -n "$BOOT" ] || { - config_list_foreach "$cfg" "interface" append_interface - config_list_foreach "$cfg" "notinterface" append_notinterface - } - config_get_bool ignore_hosts_dir "$cfg" ignore_hosts_dir 0 - if [ "$ignore_hosts_dir" = "1" ]; then - xappend "--addn-hosts=$HOSTFILE" - append EXTRA_MOUNT "$HOSTFILE" - else - xappend "--addn-hosts=$HOSTFILE_DIR" - append EXTRA_MOUNT "$HOSTFILE_DIR" - fi - config_list_foreach "$cfg" "addnhosts" append_addnhosts - config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain - append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases" - - local serversfile - config_get serversfile "$cfg" "serversfile" - [ -n "$serversfile" ] && { - xappend "--servers-file=$serversfile" - append EXTRA_MOUNT "$serversfile" - } - - append_parm "$cfg" "tftp_root" "--tftp-root" - append_parm "$cfg" "dhcp_boot" "--dhcp-boot" - append_parm "$cfg" "local_ttl" "--local-ttl" - append_parm "$cfg" "max_ttl" "--max-ttl" - append_parm "$cfg" "min_cache_ttl" "--min-cache-ttl" - append_parm "$cfg" "max_cache_ttl" "--max-cache-ttl" - append_parm "$cfg" "pxe_prompt" "--pxe-prompt" - append_parm "$cfg" "tftp_unique_root" "--tftp-unique-root" - config_list_foreach "$cfg" "pxe_service" append_pxe_service - config_get DOMAIN "$cfg" domain - - config_get_bool ADD_LOCAL_DOMAIN "$cfg" add_local_domain 1 - config_get_bool ADD_LOCAL_HOSTNAME "$cfg" add_local_hostname 1 - config_get ADD_LOCAL_FQDN "$cfg" add_local_fqdn "" - config_get ADD_WAN_FQDN "$cfg" add_wan_fqdn 0 - - if [ -z "$ADD_LOCAL_FQDN" ] ; then - # maintain support for previous UCI - ADD_LOCAL_FQDN="$ADD_LOCAL_HOSTNAME" - fi - - config_get user_dhcpscript $cfg dhcpscript - if has_handler || [ -n "$user_dhcpscript" ]; then - xappend "--dhcp-script=$DHCPSCRIPT" - xappend "--script-arp" - fi - - config_get leasefile $cfg leasefile "/tmp/dhcp.leases" - [ -n "$leasefile" ] && [ ! -e "$leasefile" ] && touch "$leasefile" - config_get_bool cachelocal "$cfg" cachelocal 1 - - config_get_bool noresolv "$cfg" noresolv 0 - if [ "$noresolv" != "1" ]; then - config_get resolvfile "$cfg" resolvfile /tmp/resolv.conf.d/resolv.conf.auto - [ -n "$resolvfile" ] && [ ! -e "$resolvfile" ] && touch "$resolvfile" - xappend "--resolv-file=$resolvfile" - [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0 - resolvdir="$(dirname "$resolvfile")" - fi - config_get_bool localuse "$cfg" localuse "$localuse" - - config_get hostsfile "$cfg" dhcphostsfile - [ -e "$hostsfile" ] && xappend "--dhcp-hostsfile=$hostsfile" - - local rebind - config_get_bool rebind "$cfg" rebind_protection 1 - [ $rebind -gt 0 ] && { - log_once \ - "DNS rebinding protection is active," \ - "will discard upstream RFC1918 responses!" - xappend "--stop-dns-rebind" - - local rebind_localhost - config_get_bool rebind_localhost "$cfg" rebind_localhost 0 - [ $rebind_localhost -gt 0 ] && { - log_once "Allowing 127.0.0.0/8 responses" - xappend "--rebind-localhost-ok" - } - - append_rebind_domain() { - log_once "Allowing RFC1918 responses for domain $1" - xappend "--rebind-domain-ok=$1" - } - - config_list_foreach "$cfg" rebind_domain append_rebind_domain - } - - config_get_bool dnssec "$cfg" dnssec 0 - [ "$dnssec" -gt 0 ] && { - xappend "--conf-file=$TRUSTANCHORSFILE" - xappend "--dnssec" - [ -x /etc/init.d/sysntpd ] && { - if /etc/init.d/sysntpd enabled || [ "$(uci_get system.ntp.enabled)" = "1" ] ; then - [ -f "$TIMEVALIDFILE" ] || xappend "--dnssec-no-timecheck" - fi - } - config_get_bool dnsseccheckunsigned "$cfg" dnsseccheckunsigned 1 - [ "$dnsseccheckunsigned" -eq 0 ] && xappend "--dnssec-check-unsigned=no" - } - - config_get addmac "$cfg" addmac 0 - [ "$addmac" != "0" ] && { - [ "$addmac" = "1" ] && addmac= - xappend "--add-mac${addmac:+="$addmac"}" - } - append_bool "$cfg" stripmac "--strip-mac" - append_parm "$cfg" addsubnet "--add-subnet" - append_bool "$cfg" stripsubnet "--strip-subnet" - - dhcp_option_add "$cfg" "" 0 - dhcp_option_add "$cfg" "" 2 - - xappend "--dhcp-broadcast=tag:needs-broadcast" - - - config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d" - xappend "--conf-dir=$dnsmasqconfdir" - dnsmasqconfdir="${dnsmasqconfdir%%,*}" - [ ! -d "$dnsmasqconfdir" ] && mkdir -p "$dnsmasqconfdir" - xappend "--user=dnsmasq" - xappend "--group=dnsmasq" - echo >> "$CONFIGFILE_TMP" - - config_get_bool enable_tftp "$cfg" enable_tftp 0 - [ "$enable_tftp" -gt 0 ] && { - config_get tftp_root "$cfg" tftp_root - append EXTRA_MOUNT $tftp_root - } - - config_foreach filter_dnsmasq host dhcp_host_add "$cfg" - echo >> "$CONFIGFILE_TMP" - - config_get_bool dhcpbogushostname "$cfg" dhcpbogushostname 1 - [ "$dhcpbogushostname" -gt 0 ] && { - xappend "--dhcp-ignore-names=tag:dhcp_bogus_hostname" - [ -r "$DHCPBOGUSHOSTNAMEFILE" ] && xappend "--conf-file=$DHCPBOGUSHOSTNAMEFILE" - } - - config_foreach filter_dnsmasq boot dhcp_boot_add "$cfg" - config_foreach filter_dnsmasq mac dhcp_mac_add "$cfg" - config_foreach filter_dnsmasq tag dhcp_tag_add "$cfg" - config_foreach filter_dnsmasq vendorclass dhcp_vendorclass_add "$cfg" - config_foreach filter_dnsmasq userclass dhcp_userclass_add "$cfg" - config_foreach filter_dnsmasq circuitid dhcp_circuitid_add "$cfg" - config_foreach filter_dnsmasq remoteid dhcp_remoteid_add "$cfg" - config_foreach filter_dnsmasq subscrid dhcp_subscrid_add "$cfg" - config_foreach filter_dnsmasq match dhcp_match_add "$cfg" - config_foreach filter_dnsmasq domain dhcp_domain_add "$cfg" - config_foreach filter_dnsmasq hostrecord dhcp_hostrecord_add "$cfg" - config_foreach filter_dnsmasq dnsrr dhcp_dnsrr_add "$cfg" - [ -n "$BOOT" ] || config_foreach filter_dnsmasq relay dhcp_relay_add "$cfg" - - echo >> "$CONFIGFILE_TMP" - config_foreach filter_dnsmasq srvhost dhcp_srv_add "$cfg" - config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg" - echo >> "$CONFIGFILE_TMP" - - config_get_bool boguspriv "$cfg" boguspriv 1 - [ "$boguspriv" -gt 0 ] && { - xappend "--bogus-priv" - [ -r "$RFC6761FILE" ] && xappend "--conf-file=$RFC6761FILE" - } - - if [ "$DNSMASQ_DHCP_VER" -gt 4 ] ; then - # Enable RA feature for when/if it is constructed, - # and RA is selected per interface pool (RA, DHCP, or both), - # but no one (should) want RA broadcast in syslog - [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg" - xappend "--enable-ra" - xappend "--quiet-ra" - append_bool "$cfg" quietdhcp "--quiet-dhcp6" - - elif [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then - [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg" - fi - - - echo >> "$CONFIGFILE_TMP" - config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg" - echo >> "$CONFIGFILE_TMP" - - echo >> "$CONFIGFILE_TMP" - config_foreach filter_dnsmasq ipset dnsmasq_ipset_add "$cfg" - echo >> "$CONFIGFILE_TMP" - - mv -f "$CONFIGFILE_TMP" "$CONFIGFILE" - mv -f "$HOSTFILE_TMP" "$HOSTFILE" - - [ "$localuse" -gt 0 ] && { - rm -f /tmp/resolv.conf - [ $ADD_LOCAL_DOMAIN -eq 1 ] && [ -n "$DOMAIN" ] && { - echo "search $DOMAIN" >> /tmp/resolv.conf - } - DNS_SERVERS="$DNS_SERVERS 127.0.0.1" - [ -e /proc/sys/net/ipv6 ] && DNS_SERVERS="$DNS_SERVERS ::1" - for DNS_SERVER in $DNS_SERVERS ; do - echo "nameserver $DNS_SERVER" >> /tmp/resolv.conf - done - } - - config_list_foreach "$cfg" addnmount append_extramount - - procd_open_instance $cfg - procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid - procd_set_param file $CONFIGFILE - [ -n "$user_dhcpscript" ] && procd_set_param env USER_DHCPSCRIPT="$user_dhcpscript" - procd_set_param respawn - - local instance_ifc instance_netdev - config_get instance_ifc "$cfg" interface - [ -n "$instance_ifc" ] && network_get_device instance_netdev "$instance_ifc" && - [ -n "$instance_netdev" ] && procd_set_param netdev $instance_netdev - - procd_add_jail dnsmasq ubus log - procd_add_jail_mount $CONFIGFILE $DHCPBOGUSHOSTNAMEFILE $DHCPSCRIPT $DHCPSCRIPT_DEPENDS - procd_add_jail_mount $EXTRA_MOUNT $RFC6761FILE $TRUSTANCHORSFILE - procd_add_jail_mount $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript - procd_add_jail_mount /etc/passwd /etc/group /etc/TZ /etc/hosts /etc/ethers - procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile - case "$logfacility" in */*) - [ ! -e "$logfacility" ] && touch "$logfacility" - procd_add_jail_mount_rw "$logfacility" - esac - [ -e "$hostsfile" ] && procd_add_jail_mount $hostsfile - - procd_close_instance -} - -dnsmasq_stop() -{ - local cfg="$1" - local noresolv resolvfile localuse=1 - - config_get_bool noresolv "$cfg" noresolv 0 - config_get resolvfile "$cfg" "resolvfile" - - [ "$noresolv" = 0 ] && [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0 - config_get_bool localuse "$cfg" localuse "$localuse" - [ "$localuse" -gt 0 ] && ln -sf "/tmp/resolv.conf.d/resolv.conf.auto" /tmp/resolv.conf - - rm -f ${BASEDHCPSTAMPFILE}.${cfg}.*.dhcp -} - -add_interface_trigger() -{ - local interface ifname ignore - - config_get interface "$1" interface - config_get_bool ignore "$1" ignore 0 - network_get_device ifname "$interface" || ignore=0 - - [ -n "$interface" ] && [ $ignore -eq 0 ] && procd_add_interface_trigger "interface.*" "$interface" /etc/init.d/dnsmasq reload -} - -service_triggers() -{ - procd_add_reload_trigger "dhcp" "system" - - config_load dhcp - config_foreach add_interface_trigger dhcp - config_foreach add_interface_trigger relay -} - -boot() -{ - BOOT=1 - start "$@" -} - -start_service() { - local instance="$1" - local instance_found=0 - local first_instance="" - - . /lib/functions/network.sh - - config_cb() { - local type="$1" - local name="$2" - if [ "$type" = "dnsmasq" ]; then - if [ -n "$instance" ] && [ "$instance" = "$name" ]; then - instance_found=1 - fi - if [ -z "$DEFAULT_INSTANCE" ]; then - local disabled - config_get_bool disabled "$name" disabled 0 - if [ "$disabled" -eq 0 ]; then - # First enabled section will be assigned default instance name. - # Unnamed sections get precedence over named sections. - if expr "$cfg" : 'cfg[0-9a-f]*$' >/dev/null = "9"; then # See uci_fixup_section. - DEFAULT_INSTANCE="$name" # Unnamed config section. - elif [ -z "$first_instance" ]; then - first_instance="$name" - fi - fi - fi - fi - } - - DEFAULT_INSTANCE="" - config_load dhcp - if [ -z "$DEFAULT_INSTANCE" ]; then - DEFAULT_INSTANCE="$first_instance" # No unnamed config section was found. - fi - - if [ -n "$instance" ]; then - [ "$instance_found" -gt 0 ] || return - dnsmasq_start "$instance" - else - config_foreach dnsmasq_start dnsmasq - fi -} - -reload_service() { - rc_procd start_service "$@" - procd_send_signal dnsmasq "$@" -} - -stop_service() { - local instance="$1" - local instance_found=0 - - config_cb() { - local type="$1" - local name="$2" - if [ "$type" = "dnsmasq" ]; then - if [ -n "$instance" ] && [ "$instance" = "$name" ]; then - instance_found=1 - fi - fi - } - - config_load dhcp - - if [ -n "$instance" ]; then - [ "$instance_found" -gt 0 ] || return - dnsmasq_stop "$instance" - else - config_foreach dnsmasq_stop dnsmasq - fi -} diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index ef396cf68..09f5d3115 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -101,12 +101,6 @@ git clone https://$github/sbwml/package_utils_util-linux -b openwrt-24.10 packag # Shortcut Forwarding Engine git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe -# dnsmasq -if [ "$version" = "dev" ]; then - curl -s $mirror/openwrt/patch/dnsmasq/0001-dnsmasq-drop-extraconftext-parameter.patch | patch -p1 - [ "$?" -ne 0 ] && curl -s $mirror/openwrt/patch/dnsmasq/dnsmasq.init > package/network/services/dnsmasq/files/dnsmasq.init -fi - # Patch FireWall 4 if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then # firewall4 From 5c19b37ef57ed74a3c05bd3940dde1d055873444 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 13 Jan 2025 23:01:48 +0800 Subject: [PATCH 180/425] modules: sync openwrt upstream kernel modules Signed-off-by: sbwml --- openwrt/build.sh | 3 +- ...napshot-packets-in-flight-at-transmi.patch | 2 +- ...djust-skb-tx.in_flight-upon-split-in.patch | 4 +-- ...alize-TSO-sizing-in-TCP-CC-module-AP.patch | 2 +- ...ecord-app-limited-status-of-TLP-repa.patch | 2 +- ...-silence-btf-module-warning-messages.patch | 2 +- ...-linux-kernel-to-support-shortcut-fe.patch | 6 ++-- ...83-add-bcm-fullcone-nft_masq-support.patch | 2 +- openwrt/patch/openwrt-6.x/modules/crypto.mk | 20 +++++++++++ openwrt/patch/openwrt-6.x/modules/leds.mk | 35 +++++++++++++++++++ .../patch/openwrt-6.x/modules/netdevices.mk | 24 ++++++++++++- .../patch/openwrt-6.x/modules/netfilter.mk | 34 ++++++++++++++++++ .../patch/openwrt-6.x/modules/netsupport.mk | 3 +- openwrt/patch/openwrt-6.x/modules/usb.mk | 17 +++++++++ openwrt/scripts/01-prepare_base-mainline.sh | 2 +- 15 files changed, 144 insertions(+), 14 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 561f6275a..ae000d164 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -45,7 +45,8 @@ export gitea=git.cooluc.com # github mirror if [ "$isCN" = "CN" ]; then - export github="ghgo.xyz/github.com" + # There is currently no stable gh proxy + export github="github.com" else export github="github.com" fi diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index 85828bb6f..4772241b7 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -56,7 +56,7 @@ Signed-off-by: Alexandre Frade struct rate_sample *rs); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2765,6 +2765,7 @@ static bool tcp_write_xmit(struct sock * +@@ -2767,6 +2767,7 @@ static bool tcp_write_xmit(struct sock * skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); tcp_init_tso_segs(skb, mss_now); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch index 918f5f630..3211647f5 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -55,7 +55,7 @@ Signed-off-by: Alexandre Frade * between different flows. --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -1601,7 +1601,7 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1603,7 +1603,7 @@ int tcp_fragment(struct sock *sk, enum t { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; @@ -64,7 +64,7 @@ Signed-off-by: Alexandre Frade long limit; int nlen; u8 flags; -@@ -1676,6 +1676,30 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1678,6 +1678,30 @@ int tcp_fragment(struct sock *sk, enum t if (diff) tcp_adjust_pcount(sk, skb, diff); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch index 3a6918530..87c7c31c6 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -97,7 +97,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2057,13 +2057,12 @@ static u32 tcp_tso_autosize(const struct +@@ -2059,13 +2059,12 @@ static u32 tcp_tso_autosize(const struct static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) { const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch index 244903840..1a2b75f6b 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -3003,6 +3003,7 @@ void tcp_send_loss_probe(struct sock *sk +@@ -3005,6 +3005,7 @@ void tcp_send_loss_probe(struct sock *sk if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; diff --git a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch index 7eced3763..3dca39e28 100644 --- a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch +++ b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch @@ -10,7 +10,7 @@ Signed-off-by: sbwml --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c -@@ -7884,8 +7884,6 @@ static int btf_module_notify(struct noti +@@ -8028,8 +8028,6 @@ static int btf_module_notify(struct noti pr_warn("failed to validate module [%s] BTF: %ld\n", mod->name, PTR_ERR(btf)); err = PTR_ERR(btf); diff --git a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 363606f3c..fb05283b2 100644 --- a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -111,7 +111,7 @@ Signed-off-by: Xiaoping Fan len = skb->len; trace_net_dev_start_xmit(skb, dev); -@@ -5417,6 +5426,11 @@ void netdev_rx_handler_unregister(struct +@@ -5419,6 +5428,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5465,6 +5479,10 @@ static int __netif_receive_skb_core(stru +@@ -5467,6 +5481,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5503,6 +5521,16 @@ another_round: +@@ -5505,6 +5523,16 @@ another_round: goto out; } diff --git a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch index 0891fbf4d..11294355c 100644 --- a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -30,7 +30,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -11083,6 +11083,24 @@ static int nft_validate_register_load(en +@@ -11101,6 +11101,24 @@ static int nft_validate_register_load(en return 0; } diff --git a/openwrt/patch/openwrt-6.x/modules/crypto.mk b/openwrt/patch/openwrt-6.x/modules/crypto.mk index 2257a36c8..78c971217 100644 --- a/openwrt/patch/openwrt-6.x/modules/crypto.mk +++ b/openwrt/patch/openwrt-6.x/modules/crypto.mk @@ -366,6 +366,26 @@ endef $(eval $(call KernelPackage,crypto-hmac)) +define KernelPackage/crypto-hw-atmel + TITLE:=Microchip / Atmel ECC/SHA/RNG hw accelerator + DEPENDS:=+kmod-i2c-core +kmod-crypto-ecdh +kmod-crypto-sha1 \ + +kmod-crypto-sha256 +kmod-lib-crc16 +kmod-random-core + KCONFIG:= \ + CONFIG_CRYPTO_HW=y \ + CONFIG_CRYPTO_DEV_ATMEL_I2C \ + CONFIG_CRYPTO_DEV_ATMEL_ECC \ + CONFIG_CRYPTO_DEV_ATMEL_SHA204A + FILES:= \ + $(LINUX_DIR)/drivers/crypto/atmel-i2c.ko \ + $(LINUX_DIR)/drivers/crypto/atmel-ecc.ko \ + $(LINUX_DIR)/drivers/crypto/atmel-sha204a.ko + AUTOLOAD:=$(call AutoLoad,09,atmel-i2c atmel-ecc atmel-sha204a) + $(call AddDepends/crypto) +endef + +$(eval $(call KernelPackage,crypto-hw-atmel)) + + define KernelPackage/crypto-hw-ccp TITLE:=AMD Cryptographic Coprocessor DEPENDS:= \ diff --git a/openwrt/patch/openwrt-6.x/modules/leds.mk b/openwrt/patch/openwrt-6.x/modules/leds.mk index 8b24cb0ef..98e6fc884 100644 --- a/openwrt/patch/openwrt-6.x/modules/leds.mk +++ b/openwrt/patch/openwrt-6.x/modules/leds.mk @@ -147,6 +147,24 @@ endef $(eval $(call KernelPackage,leds-apu)) +define KernelPackage/leds-ktd202x + SUBMENU:=LED modules + TITLE:=LED support for KTD202x Chips + DEPENDS:=+kmod-i2c-core +kmod-regmap-i2c + KCONFIG:=CONFIG_LEDS_KTD202X + FILES:= $(LINUX_DIR)/drivers/leds/rgb/leds-ktd202x.ko + AUTOLOAD:=$(call AutoProbe,leds-ktd202x,1) +endef + +define KernelPackage/leds-ktd202x/description + This option enables support for the Kinetic KTD2026/KTD2027 + RGB/White LED driver found in different BQ mobile phones. + It is a 3 or 4 channel LED driver programmed via an I2C interface. +endef + +$(eval $(call KernelPackage,leds-ktd202x)) + + define KernelPackage/leds-mlxcpld SUBMENU:=$(LEDS_MENU) TITLE:=LED support for the Mellanox boards @@ -215,6 +233,23 @@ endef $(eval $(call KernelPackage,leds-pwm)) +define KernelPackage/leds-st1202 + SUBMENU:=LED modules + TITLE:=LED support for ST LED1202 I2C chips + DEPENDS:=+kmod-i2c-core +kmod-ledtrig-pattern + KCONFIG:=CONFIG_LEDS_ST1202 + FILES:= $(LINUX_DIR)/drivers/leds/leds-st1202.ko + AUTOLOAD:=$(call AutoProbe,leds-st1202) +endef + +define KernelPackage/leds-st1202/description + This option enables support for LEDs connected to LED1202 + LED driver chips accessed via the I2C bus. +endef + +$(eval $(call KernelPackage,leds-st1202)) + + define KernelPackage/leds-tlc591xx SUBMENU:=$(LEDS_MENU) TITLE:=LED driver for TLC59108 and TLC59116 controllers diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index 7d1129c99..01007768b 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -953,7 +953,7 @@ $(eval $(call KernelPackage,8139cp)) define KernelPackage/r8169 SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=RealTek RTL-8169 PCI Gigabit Ethernet Adapter kernel support - DEPENDS:=@PCI_SUPPORT +kmod-mii +r8169-firmware +kmod-phy-realtek +kmod-mdio-devres + DEPENDS:=@PCI_SUPPORT +kmod-mii +r8169-firmware +kmod-phy-realtek +kmod-mdio-devres +kmod-hwmon-core KCONFIG:= \ CONFIG_R8169 \ CONFIG_R8169_LEDS=y @@ -1525,6 +1525,28 @@ endef $(eval $(call KernelPackage,bnx2x)) +define KernelPackage/bnxt-en + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Broadcom NetXtreme-C/E network driver + DEPENDS:=@PCI_SUPPORT +kmod-hwmon-core +kmod-lib-crc32c +kmod-mdio +kmod-ptp + FILES:=$(LINUX_DIR)/drivers/net/ethernet/broadcom/bnxt/bnxt_en.ko + KCONFIG:= \ + CONFIG_BNXT \ + CONFIG_BNXT_SRIOV=y \ + CONFIG_BNXT_FLOWER_OFFLOAD=y \ + CONFIG_BNXT_DCB=n \ + CONFIG_BNXT_HWMON=y + AUTOLOAD:=$(call AutoProbe,bnxt_en) +endef + +define KernelPackage/bnxt-en/description + Supports Broadcom NetXtreme-C/E based Ethernet NICs including: + * BCM573xx + * BCM574xx +endef + +$(eval $(call KernelPackage,bnxt-en)) + define KernelPackage/be2net SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Broadcom Emulex OneConnect 10Gbps NIC diff --git a/openwrt/patch/openwrt-6.x/modules/netfilter.mk b/openwrt/patch/openwrt-6.x/modules/netfilter.mk index cf66bd8cd..96531b1e0 100644 --- a/openwrt/patch/openwrt-6.x/modules/netfilter.mk +++ b/openwrt/patch/openwrt-6.x/modules/netfilter.mk @@ -1048,6 +1048,40 @@ endef $(eval $(call KernelPackage,nfnetlink-queue)) +define KernelPackage/nfnetlink-cthelper + TITLE:=Netfilter User space conntrack helpers + FILES:=$(LINUX_DIR)/net/netfilter/nfnetlink_cthelper.ko + KCONFIG:=CONFIG_NF_CT_NETLINK_HELPER + AUTOLOAD:=$(call AutoProbe,nfnetlink_cthelper) + $(call AddDepends/nfnetlink,+kmod-nfnetlink-queue +kmod-nf-conntrack-netlink) +endef + +define KernelPackage/nfnetlink-cthelper/description + Kernel modules support for a netlink-based connection tracking + userspace helpers interface +endef + +$(eval $(call KernelPackage,nfnetlink-cthelper)) + + +define KernelPackage/nfnetlink-cttimeout + TITLE:=Netfilter conntrack expectation timeout + FILES:=$(LINUX_DIR)/net/netfilter/nfnetlink_cttimeout.ko + KCONFIG:=CONFIG_NF_CT_NETLINK_TIMEOUT + AUTOLOAD:=$(call AutoProbe,nfnetlink_cttimeout) + $(call AddDepends/nfnetlink,+kmod-nf-conntrack @KERNEL_NF_CONNTRACK_TIMEOUT) +endef + +define KernelPackage/nfnetlink-cttimeout/description + Kernel modules support for a netlink-based connection tracking + userspace timeout interface + + Requires CONFIG_NF_CONNTRACK_TIMEOUT (only enabled for non-small flash devices) +endef + +$(eval $(call KernelPackage,nfnetlink-cttimeout)) + + define KernelPackage/nf-conntrack-netlink TITLE:=Connection tracking netlink interface FILES:=$(LINUX_DIR)/net/netfilter/nf_conntrack_netlink.ko diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index 49721b151..04180e6c2 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -1026,7 +1026,7 @@ endef $(eval $(call KernelPackage,bpf-test)) -SCHED_MODULES_EXTRA = sch_codel sch_gred sch_multiq sch_sfq sch_teql sch_fq act_pedit act_simple act_skbmod act_csum em_cmp em_nbyte em_meta em_text +SCHED_MODULES_EXTRA = sch_codel sch_gred sch_multiq sch_sfq sch_teql sch_fq sch_ets act_pedit act_simple act_skbmod act_csum em_cmp em_nbyte em_meta em_text SCHED_FILES_EXTRA = $(foreach mod,$(SCHED_MODULES_EXTRA),$(LINUX_DIR)/net/sched/$(mod).ko) define KernelPackage/sched @@ -1040,6 +1040,7 @@ define KernelPackage/sched CONFIG_NET_SCH_SFQ \ CONFIG_NET_SCH_TEQL \ CONFIG_NET_SCH_FQ \ + CONFIG_NET_SCH_ETS \ CONFIG_NET_ACT_PEDIT \ CONFIG_NET_ACT_SIMP \ CONFIG_NET_ACT_SKBMOD \ diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index 734df050c..8f934800f 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -519,6 +519,23 @@ endef $(eval $(call KernelPackage,usb-dwc3)) +define KernelPackage/usb-dwc3-octeon + TITLE:=DWC3 Cavium Octeon USB driver + DEPENDS:=@TARGET_octeon +kmod-usb-dwc3 + KCONFIG:= CONFIG_USB_DWC3_OCTEON + FILES:= $(LINUX_DIR)/drivers/usb/dwc3/dwc3-octeon.ko + AUTOLOAD:=$(call AutoProbe,dwc3-octeon,1) + $(call AddDepends/usb) +endef + +define KernelPackage/usb-dwc3-octeon/description + This driver adds support for Cavium Octeon platforms with DesignWare + Core USB3 IP. +endef + +$(eval $(call KernelPackage,usb-dwc3-octeon)) + + define KernelPackage/usb-dwc3-qcom TITLE:=DWC3 Qualcomm USB driver DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_qualcommax) +kmod-usb-dwc3 diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 0c715ecd6..88d005f63 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -167,7 +167,7 @@ curl -s $mirror/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_o rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware -# mt76 - 2024-10-11 +# mt76 mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch From 33ca1231227f82706933a343ab09099ded59a6df Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 8 Feb 2025 17:24:28 +0800 Subject: [PATCH 181/425] archive 2025-02-08 Signed-off-by: sbwml --- openwrt/files/etc/sysctl.d/10-default.conf | 29 + openwrt/patch/mt76/Makefile | 768 ++++++++++++++++++ ...ix-build-with-mac80211-6.11-backport.patch | 11 - .../patch/openwrt-6.x/modules/netdevices.mk | 9 +- openwrt/scripts/00-prepare_base.sh | 1 + openwrt/scripts/01-prepare_base-mainline.sh | 26 +- openwrt/scripts/02-prepare_package.sh | 3 + tags/kernel-6.12 | 4 +- tags/v24 | 2 +- 9 files changed, 827 insertions(+), 26 deletions(-) create mode 100644 openwrt/files/etc/sysctl.d/10-default.conf create mode 100644 openwrt/patch/mt76/Makefile diff --git a/openwrt/files/etc/sysctl.d/10-default.conf b/openwrt/files/etc/sysctl.d/10-default.conf new file mode 100644 index 000000000..a4c998aad --- /dev/null +++ b/openwrt/files/etc/sysctl.d/10-default.conf @@ -0,0 +1,29 @@ +# Do not edit, changes to this file will be lost on upgrades +# /etc/sysctl.conf can be used to customize sysctl settings + +kernel.panic=3 +kernel.core_pattern=/tmp/%e.%t.%p.%s.core +fs.suid_dumpable=2 + +fs.protected_hardlinks=1 +fs.protected_symlinks=1 + +net.core.bpf_jit_enable=1 +net.core.bpf_jit_kallsyms=1 + +net.ipv4.conf.default.arp_ignore=1 +net.ipv4.conf.all.arp_ignore=1 +net.ipv4.ip_forward=1 +net.ipv4.icmp_echo_ignore_broadcasts=1 +net.ipv4.icmp_ignore_bogus_error_responses=1 +net.ipv4.igmp_max_memberships=100 +net.ipv4.tcp_fin_timeout=30 +net.ipv4.tcp_keepalive_time=120 +net.ipv4.tcp_syncookies=1 +net.ipv4.tcp_timestamps=1 +net.ipv4.tcp_sack=1 +net.ipv4.tcp_dsack=1 +net.ipv4.tcp_max_syn_backlog=8192 + +net.ipv6.conf.default.forwarding=1 +net.ipv6.conf.all.forwarding=1 diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile new file mode 100644 index 000000000..ef2c61988 --- /dev/null +++ b/openwrt/patch/mt76/Makefile @@ -0,0 +1,768 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=mt76 +PKG_RELEASE=1 + +PKG_LICENSE:=GPLv2 +PKG_LICENSE_FILES:= + +PKG_SOURCE_URL:=https://github.com/openwrt/mt76 +PKG_SOURCE_PROTO:=git +PKG_SOURCE_DATE:=2025-01-22 +PKG_SOURCE_VERSION:=a22d59e4ad50c89326342a0736cd2c1ba32e8a0b +PKG_MIRROR_HASH:=e8bbbada2171ea31a6788e3e46e81c409a9fe038eefe4b41f541da848a1b1bcd + +PKG_MAINTAINER:=Felix Fietkau +PKG_USE_NINJA:=0 +PKG_BUILD_PARALLEL:=1 + +PKG_CONFIG_DEPENDS += \ + CONFIG_PACKAGE_kmod-mt76-usb \ + CONFIG_PACKAGE_kmod-mt76x02-common \ + CONFIG_PACKAGE_kmod-mt76x0-common \ + CONFIG_PACKAGE_kmod-mt76x0u \ + CONFIG_PACKAGE_kmod-mt76x2-common \ + CONFIG_PACKAGE_kmod-mt76x2 \ + CONFIG_PACKAGE_kmod-mt76x2u \ + CONFIG_PACKAGE_kmod-mt7603 \ + CONFIG_PACKAGE_CFG80211_TESTMODE + +STAMP_CONFIGURED_DEPENDS := $(STAGING_DIR)/usr/include/mac80211-backport/backport/autoconf.h + +include $(INCLUDE_DIR)/kernel.mk +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +CMAKE_SOURCE_DIR:=$(PKG_BUILD_DIR)/tools +CMAKE_BINARY_DIR:=$(PKG_BUILD_DIR)/tools + +define KernelPackage/mt76-default + SUBMENU:=Wireless Drivers + DEPENDS:= \ + +kmod-mac80211 \ + +@DRIVER_11AC_SUPPORT \ + +@KERNEL_PAGE_POOL +endef + +define KernelPackage/mt76 + SUBMENU:=Wireless Drivers + TITLE:=MediaTek MT76x2/MT7603 wireless driver (metapackage) + DEPENDS:= \ + +kmod-mt76-core +kmod-mt76x2 +kmod-mt7603 +endef + +define KernelPackage/mt76-core + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76xx wireless driver + HIDDEN:=1 + FILES:=\ + $(PKG_BUILD_DIR)/mt76.ko +endef + +define KernelPackage/mt76-usb + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76xx wireless driver USB support + DEPENDS += +kmod-usb-core +kmod-mt76-core + HIDDEN:=1 + FILES:=\ + $(PKG_BUILD_DIR)/mt76-usb.ko +endef + +define KernelPackage/mt76x02-usb + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x0/MT76x2 USB wireless driver common code + DEPENDS+=+kmod-mt76-usb +kmod-mt76x02-common + HIDDEN:=1 + FILES:=$(PKG_BUILD_DIR)/mt76x02-usb.ko +endef + +define KernelPackage/mt76x02-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x0/MT76x2 wireless driver common code + DEPENDS+=+kmod-mt76-core + HIDDEN:=1 + FILES:=$(PKG_BUILD_DIR)/mt76x02-lib.ko +endef + +define KernelPackage/mt76x0-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x0 wireless driver common code + DEPENDS+=+kmod-mt76x02-common + HIDDEN:=1 + FILES:=$(PKG_BUILD_DIR)/mt76x0/mt76x0-common.ko +endef + +define KernelPackage/mt76x0e + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x0E wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt76x0-common + FILES:=\ + $(PKG_BUILD_DIR)/mt76x0/mt76x0e.ko + AUTOLOAD:=$(call AutoProbe,mt76x0e) +endef + +define KernelPackage/mt76x0u + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x0U wireless driver + DEPENDS+=+kmod-mt76x0-common +kmod-mt76x02-usb + FILES:=\ + $(PKG_BUILD_DIR)/mt76x0/mt76x0u.ko + AUTOLOAD:=$(call AutoProbe,mt76x0u) +endef + +define KernelPackage/mt76x2-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x2 wireless driver common code + DEPENDS+=+kmod-mt76-core +kmod-mt76x02-common + HIDDEN:=1 + FILES:=$(PKG_BUILD_DIR)/mt76x2/mt76x2-common.ko +endef + +define KernelPackage/mt76x2u + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x2U wireless driver + DEPENDS+=+kmod-mt76x2-common +kmod-mt76x02-usb + FILES:=\ + $(PKG_BUILD_DIR)/mt76x2/mt76x2u.ko + AUTOLOAD:=$(call AutoProbe,mt76x2u) +endef + +define KernelPackage/mt76x2 + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT76x2 wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt76x2-common + FILES:=\ + $(PKG_BUILD_DIR)/mt76x2/mt76x2e.ko + AUTOLOAD:=$(call AutoProbe,mt76x2e) +endef + +define KernelPackage/mt7603 + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7603 wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt76-core + FILES:=\ + $(PKG_BUILD_DIR)/mt7603/mt7603e.ko + AUTOLOAD:=$(call AutoProbe,mt7603e) +endef + +define KernelPackage/mt76-connac + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615/MT79xx wireless driver common code + HIDDEN:=1 + DEPENDS+=+kmod-mt76-core + FILES:= $(PKG_BUILD_DIR)/mt76-connac-lib.ko +endef + +define KernelPackage/mt76-sdio + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615/MT79xx SDIO driver common code + HIDDEN:=1 + DEPENDS+=+kmod-mt76-core +kmod-mmc + FILES:= $(PKG_BUILD_DIR)/mt76-sdio.ko +endef + +define KernelPackage/mt7615-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615 wireless driver common code + HIDDEN:=1 + DEPENDS+=@PCI_SUPPORT +kmod-mt76-core +kmod-mt76-connac +kmod-hwmon-core + FILES:= $(PKG_BUILD_DIR)/mt7615/mt7615-common.ko +endef + +define KernelPackage/mt7615-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615e firmware + DEPENDS+=+kmod-mt7615e +endef + +define KernelPackage/mt7615e + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615e wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt7615-common + FILES:= $(PKG_BUILD_DIR)/mt7615/mt7615e.ko + AUTOLOAD:=$(call AutoProbe,mt7615e) +endef + +define KernelPackage/mt7622-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7622 firmware + DEPENDS+=+kmod-mt7615e +endef + +define KernelPackage/mt7663-firmware-ap + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663e firmware (optimized for AP) +endef + +define KernelPackage/mt7663-firmware-sta + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663e firmware (client mode offload) +endef + +define KernelPackage/mt7663-usb-sdio + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663 USB/SDIO shared code + DEPENDS+=+kmod-mt7615-common + HIDDEN:=1 + FILES:= \ + $(PKG_BUILD_DIR)/mt7615/mt7663-usb-sdio-common.ko +endef + +define KernelPackage/mt7663s + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663s wireless driver + DEPENDS+=+kmod-mt76-sdio +kmod-mt7615-common +kmod-mt7663-usb-sdio + FILES:= \ + $(PKG_BUILD_DIR)/mt7615/mt7663s.ko + AUTOLOAD:=$(call AutoProbe,mt7663s) +endef + +define KernelPackage/mt7663u + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663u wireless driver + DEPENDS+=+kmod-mt76-usb +kmod-mt7615-common +kmod-mt7663-usb-sdio + FILES:= $(PKG_BUILD_DIR)/mt7615/mt7663u.ko + AUTOLOAD:=$(call AutoProbe,mt7663u) +endef + +define KernelPackage/mt7915-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7915 firmware + DEPENDS+=+kmod-mt7915e +endef + +define KernelPackage/mt7915e + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7915e wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core +kmod-thermal +@DRIVER_11AX_SUPPORT +@KERNEL_RELAY + FILES:= $(PKG_BUILD_DIR)/mt7915/mt7915e.ko + AUTOLOAD:=$(call AutoProbe,mt7915e) +endef + +define KernelPackage/mt7916-firmware + $(KernelPackage/mt76-default) + DEPENDS+=+kmod-mt7915e + TITLE:=MediaTek MT7916 firmware +endef + +define KernelPackage/mt7981-firmware + $(KernelPackage/mt76-default) + DEPENDS:=@TARGET_mediatek_filogic + TITLE:=MediaTek MT7981 firmware +endef + +define KernelPackage/mt7986-firmware + $(KernelPackage/mt76-default) + DEPENDS:=@TARGET_mediatek_filogic + TITLE:=MediaTek MT7986 firmware +endef + +define KernelPackage/mt7921-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7921 firmware +endef + +define KernelPackage/mt7922-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7922 firmware +endef + +define KernelPackage/mt792x-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT792x wireless driver common code + HIDDEN:=1 + DEPENDS+=+kmod-mt76-connac +@DRIVER_11AX_SUPPORT + FILES:= $(PKG_BUILD_DIR)/mt792x-lib.ko +endef + +define KernelPackage/mt792x-usb + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT792x wireless driver USB code + HIDDEN:=1 + DEPENDS+=+kmod-mt792x-common +kmod-mt76-usb +@DRIVER_11AX_SUPPORT + FILES:= $(PKG_BUILD_DIR)/mt792x-usb.ko +endef + +define KernelPackage/mt7921-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7921 wireless driver common code + HIDDEN:=1 + DEPENDS+=+kmod-mt792x-common +kmod-mt7921-firmware +@DRIVER_11AX_SUPPORT +kmod-hwmon-core + FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921-common.ko +endef + +define KernelPackage/mt7921u + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7921U wireless driver + DEPENDS+=+kmod-mt792x-usb +kmod-mt7921-common + FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921u.ko + AUTOLOAD:=$(call AutoProbe,mt7921u) +endef + +define KernelPackage/mt7921s + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7921S wireless driver + DEPENDS+=+kmod-mt76-sdio +kmod-mt7921-common + FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921s.ko + AUTOLOAD:=$(call AutoProbe,mt7921s) +endef + +define KernelPackage/mt7921e + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7921e wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt7921-common + FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921e.ko + AUTOLOAD:=$(call AutoProbe,mt7921e) +endef + +define KernelPackage/mt7996e + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996E wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-hwmon-core +@DRIVER_11AX_SUPPORT \ + +@KERNEL_RELAY +@DRIVER_11BE_SUPPORT + FILES:= $(PKG_BUILD_DIR)/mt7996/mt7996e.ko + AUTOLOAD:=$(call AutoProbe,mt7996e) +endef + +define KernelPackage/mt7992-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7992 firmware + DEPENDS+=+kmod-mt7996e +endef + +define KernelPackage/mt7992-23-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996 firmware (2+3 antenna variant) + DEPENDS+=+kmod-mt7996e +endef + +define KernelPackage/mt7996-firmware-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996 firmware (common files) + HIDDEN:=1 +endef + +define KernelPackage/mt7996-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996 firmware + DEPENDS+=+kmod-mt7996e +kmod-mt7996-firmware-common +endef + +define KernelPackage/mt7996-233-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7996 firmware (2+3+3 antenna variant) + DEPENDS+=+kmod-mt7996e +kmod-mt7996-firmware-common +endef + +define KernelPackage/mt7925-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7925 firmware + DEPENDS+=+kmod-mt7925e +endef + +define KernelPackage/mt7925-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7925 wireless driver common code + HIDDEN:=1 + DEPENDS+=+kmod-mt792x-common +@DRIVER_11AX_SUPPORT +kmod-hwmon-core +@DRIVER_11BE_SUPPORT + FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925-common.ko +endef + +define KernelPackage/mt7925u + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7925U wireless driver + DEPENDS+=+kmod-mt792x-usb +kmod-mt7925-common + FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925u.ko + AUTOLOAD:=$(call AutoProbe,mt7925u) +endef + +define KernelPackage/mt7925e + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7925e wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt7925-common + FILES:= $(PKG_BUILD_DIR)/mt7925/mt7925e.ko + AUTOLOAD:=$(call AutoProbe,mt7925e) +endef + +define Package/mt76-test + SECTION:=devel + CATEGORY:=Development + TITLE:=mt76 testmode CLI + DEPENDS:=kmod-mt76-core +libnl-tiny +endef + +TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny + +NOSTDINC_FLAGS := \ + $(KERNEL_NOSTDINC_FLAGS) \ + -I$(PKG_BUILD_DIR) \ + -I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \ + -I$(STAGING_DIR)/usr/include/mac80211-backport \ + -I$(STAGING_DIR)/usr/include/mac80211/uapi \ + -I$(STAGING_DIR)/usr/include/mac80211 \ + -include backport/autoconf.h \ + -include backport/backport.h + +ifdef CONFIG_PACKAGE_MAC80211_MESH + NOSTDINC_FLAGS += -DCONFIG_MAC80211_MESH +endif + +ifdef CONFIG_PACKAGE_CFG80211_TESTMODE + NOSTDINC_FLAGS += -DCONFIG_NL80211_TESTMODE + PKG_MAKE_FLAGS += CONFIG_NL80211_TESTMODE=y +endif + +ifdef CONFIG_PACKAGE_kmod-mt76-usb + PKG_MAKE_FLAGS += CONFIG_MT76_USB=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x02-common + PKG_MAKE_FLAGS += CONFIG_MT76x02_LIB=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x02-usb + PKG_MAKE_FLAGS += CONFIG_MT76x02_USB=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x0-common + PKG_MAKE_FLAGS += CONFIG_MT76x0_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x0e + PKG_MAKE_FLAGS += CONFIG_MT76x0E=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x0u + PKG_MAKE_FLAGS += CONFIG_MT76x0U=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x2-common + PKG_MAKE_FLAGS += CONFIG_MT76x2_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x2 + PKG_MAKE_FLAGS += CONFIG_MT76x2E=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76x2u + PKG_MAKE_FLAGS += CONFIG_MT76x2U=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7603 + PKG_MAKE_FLAGS += CONFIG_MT7603E=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76-connac + PKG_MAKE_FLAGS += CONFIG_MT76_CONNAC_LIB=m +endif +ifdef CONFIG_PACKAGE_kmod-mt76-sdio + PKG_MAKE_FLAGS += CONFIG_MT76_SDIO=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7615-common + PKG_MAKE_FLAGS += CONFIG_MT7615_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7615e + PKG_MAKE_FLAGS += CONFIG_MT7615E=m + ifdef CONFIG_TARGET_mediatek_mt7622 + PKG_MAKE_FLAGS += CONFIG_MT7622_WMAC=y + NOSTDINC_FLAGS += -DCONFIG_MT7622_WMAC + endif +endif +ifdef CONFIG_PACKAGE_kmod-mt7663-usb-sdio + PKG_MAKE_FLAGS += CONFIG_MT7663_USB_SDIO_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7663s + PKG_MAKE_FLAGS += CONFIG_MT7663S=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7663u + PKG_MAKE_FLAGS += CONFIG_MT7663U=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7915e + PKG_MAKE_FLAGS += CONFIG_MT7915E=m + ifdef CONFIG_TARGET_mediatek_filogic + PKG_MAKE_FLAGS += CONFIG_MT798X_WMAC=y + NOSTDINC_FLAGS += -DCONFIG_MT798X_WMAC + endif +endif +ifdef CONFIG_PACKAGE_kmod-mt792x-common + PKG_MAKE_FLAGS += CONFIG_MT792x_LIB=m +endif +ifdef CONFIG_PACKAGE_kmod-mt792x-usb + PKG_MAKE_FLAGS += CONFIG_MT792x_USB=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7921-common + PKG_MAKE_FLAGS += CONFIG_MT7921_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7921u + PKG_MAKE_FLAGS += CONFIG_MT7921U=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7921s + PKG_MAKE_FLAGS += CONFIG_MT7921S=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7921e + PKG_MAKE_FLAGS += CONFIG_MT7921E=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7996e + PKG_MAKE_FLAGS += CONFIG_MT7996E=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7925-common + PKG_MAKE_FLAGS += CONFIG_MT7925_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7925u + PKG_MAKE_FLAGS += CONFIG_MT7925U=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7925e + PKG_MAKE_FLAGS += CONFIG_MT7925E=m +endif + +define Build/Compile + +$(KERNEL_MAKE) $(PKG_JOBS) \ + $(PKG_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)" \ + NOSTDINC_FLAGS="$(NOSTDINC_FLAGS)" \ + modules + $(MAKE) -C $(PKG_BUILD_DIR)/tools +endef + +define Build/Install + : +endef + +define Package/kmod-mt76/install + true +endef + +define KernelPackage/mt76x0-common/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7610e.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt76x2-common/install + $(INSTALL_DIR) $(1)/lib/firmware + cp \ + $(PKG_BUILD_DIR)/firmware/mt7662_rom_patch.bin \ + $(PKG_BUILD_DIR)/firmware/mt7662.bin \ + $(1)/lib/firmware +endef + +define KernelPackage/mt76x0u/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + ln -sf mt7610e.bin $(1)/lib/firmware/mediatek/mt7610u.bin +endef + +define KernelPackage/mt76x2u/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + ln -sf ../mt7662.bin $(1)/lib/firmware/mediatek/mt7662u.bin + ln -sf ../mt7662_rom_patch.bin $(1)/lib/firmware/mediatek/mt7662u_rom_patch.bin +endef + +define KernelPackage/mt7603/install + $(INSTALL_DIR) $(1)/lib/firmware + cp $(if $(CONFIG_TARGET_ramips_mt76x8), \ + $(PKG_BUILD_DIR)/firmware/mt7628_e1.bin \ + $(PKG_BUILD_DIR)/firmware/mt7628_e2.bin \ + ,\ + $(PKG_BUILD_DIR)/firmware/mt7603_e1.bin \ + $(PKG_BUILD_DIR)/firmware/mt7603_e2.bin \ + ) \ + $(1)/lib/firmware +endef + +define KernelPackage/mt7615-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7615_cr4.bin \ + $(PKG_BUILD_DIR)/firmware/mt7615_n9.bin \ + $(PKG_BUILD_DIR)/firmware/mt7615_rom_patch.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7622-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7622_n9.bin \ + $(PKG_BUILD_DIR)/firmware/mt7622_rom_patch.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7663-firmware-ap/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7663_n9_rebb.bin \ + $(PKG_BUILD_DIR)/firmware/mt7663pr2h_rebb.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7663-firmware-sta/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7663_n9_v3.bin \ + $(PKG_BUILD_DIR)/firmware/mt7663pr2h.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7915-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7915_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7915_wm.bin \ + $(PKG_BUILD_DIR)/firmware/mt7915_rom_patch.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7916-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7916_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7916_wm.bin \ + $(PKG_BUILD_DIR)/firmware/mt7916_rom_patch.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7981-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7981_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7981_wm.bin \ + $(PKG_BUILD_DIR)/firmware/mt7981_rom_patch.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7986-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7986_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7986_wm_mt7975.bin \ + $(PKG_BUILD_DIR)/firmware/mt7986_wm.bin \ + $(PKG_BUILD_DIR)/firmware/mt7986_rom_patch_mt7975.bin \ + $(PKG_BUILD_DIR)/firmware/mt7986_rom_patch.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7921-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/WIFI_MT7961_patch_mcu_1_2_hdr.bin \ + $(PKG_BUILD_DIR)/firmware/WIFI_RAM_CODE_MT7961_1.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7922-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/WIFI_MT7922_patch_mcu_1_1_hdr.bin \ + $(PKG_BUILD_DIR)/firmware/WIFI_RAM_CODE_MT7922_1.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7925-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7925 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin \ + $(PKG_BUILD_DIR)/firmware/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin \ + $(1)/lib/firmware/mediatek/mt7925 +endef + +define KernelPackage/mt7992-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_2i5i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_2i5e.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define KernelPackage/mt7992-23-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_dsp_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_eeprom_23_2i5i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_rom_patch_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wa_23.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7992_wm_23.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define KernelPackage/mt7996-firmware-common/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_dsp.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define KernelPackage/mt7996-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_2i5i6i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_rom_patch.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wm.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define KernelPackage/mt7996-233-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_233.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_eeprom_233_2i5i6i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_rom_patch_233.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wa_233.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7996_wm_233.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + +define Package/mt76-test/install + mkdir -p $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tools/mt76-test $(1)/usr/sbin +endef + +define Build/InstallDev + mkdir -p $(STAGING_DIR_IMAGE) + $(CP) $(PKG_BUILD_DIR)/firmware/mt7981_eeprom_mt7976_dbdc.bin $(STAGING_DIR_IMAGE)/ +endef + +$(eval $(call KernelPackage,mt76-core)) +$(eval $(call KernelPackage,mt76-usb)) +$(eval $(call KernelPackage,mt76x02-usb)) +$(eval $(call KernelPackage,mt76x02-common)) +$(eval $(call KernelPackage,mt76x0-common)) +$(eval $(call KernelPackage,mt76x0e)) +$(eval $(call KernelPackage,mt76x0u)) +$(eval $(call KernelPackage,mt76x2-common)) +$(eval $(call KernelPackage,mt76x2u)) +$(eval $(call KernelPackage,mt76x2)) +$(eval $(call KernelPackage,mt7603)) +$(eval $(call KernelPackage,mt76-connac)) +$(eval $(call KernelPackage,mt76-sdio)) +$(eval $(call KernelPackage,mt7615-common)) +$(eval $(call KernelPackage,mt7615-firmware)) +$(eval $(call KernelPackage,mt7622-firmware)) +$(eval $(call KernelPackage,mt7615e)) +$(eval $(call KernelPackage,mt7663-firmware-ap)) +$(eval $(call KernelPackage,mt7663-firmware-sta)) +$(eval $(call KernelPackage,mt7663-usb-sdio)) +$(eval $(call KernelPackage,mt7663u)) +$(eval $(call KernelPackage,mt7663s)) +$(eval $(call KernelPackage,mt7915-firmware)) +$(eval $(call KernelPackage,mt7915e)) +$(eval $(call KernelPackage,mt7916-firmware)) +$(eval $(call KernelPackage,mt7981-firmware)) +$(eval $(call KernelPackage,mt7986-firmware)) +$(eval $(call KernelPackage,mt7921-firmware)) +$(eval $(call KernelPackage,mt7922-firmware)) +$(eval $(call KernelPackage,mt7925-firmware)) +$(eval $(call KernelPackage,mt792x-common)) +$(eval $(call KernelPackage,mt792x-usb)) +$(eval $(call KernelPackage,mt7921-common)) +$(eval $(call KernelPackage,mt7925-common)) +$(eval $(call KernelPackage,mt7921u)) +$(eval $(call KernelPackage,mt7921s)) +$(eval $(call KernelPackage,mt7921e)) +$(eval $(call KernelPackage,mt7925u)) +$(eval $(call KernelPackage,mt7925e)) +$(eval $(call KernelPackage,mt7996e)) +$(eval $(call KernelPackage,mt7992-firmware)) +$(eval $(call KernelPackage,mt7992-23-firmware)) +$(eval $(call KernelPackage,mt7996-firmware-common)) +$(eval $(call KernelPackage,mt7996-firmware)) +$(eval $(call KernelPackage,mt7996-233-firmware)) +$(eval $(call KernelPackage,mt76)) +$(eval $(call BuildPackage,mt76-test)) diff --git a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch index 0128977c6..3d93637db 100644 --- a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +++ b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch @@ -1,14 +1,3 @@ ---- a/mac80211.c -+++ b/mac80211.c -@@ -613,7 +613,7 @@ int mt76_create_page_pool(struct mt76_de - { - struct page_pool_params pp_params = { - .order = 0, -- .flags = PP_FLAG_PAGE_FRAG, -+ .flags = 0, - .nid = NUMA_NO_NODE, - .dev = dev->dma_dev, - }; --- a/mt7603/soc.c +++ b/mt7603/soc.c @@ -52,15 +52,12 @@ error: diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index 01007768b..fec20abb2 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -447,9 +447,10 @@ $(eval $(call KernelPackage,phy-micrel)) define KernelPackage/phy-realtek SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Realtek Ethernet PHY driver - KCONFIG:=CONFIG_REALTEK_PHY - DEPENDS:=+kmod-libphy - FILES:=$(LINUX_DIR)/drivers/net/phy/realtek.ko + KCONFIG:=CONFIG_REALTEK_PHY \ + CONFIG_REALTEK_PHY_HWMON=y + DEPENDS:=+kmod-libphy +kmod-hwmon-core + FILES:=$(LINUX_DIR)/drivers/net/phy/realtek/realtek.ko AUTOLOAD:=$(call AutoLoad,18,realtek,1) endef @@ -953,7 +954,7 @@ $(eval $(call KernelPackage,8139cp)) define KernelPackage/r8169 SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=RealTek RTL-8169 PCI Gigabit Ethernet Adapter kernel support - DEPENDS:=@PCI_SUPPORT +kmod-mii +r8169-firmware +kmod-phy-realtek +kmod-mdio-devres +kmod-hwmon-core + DEPENDS:=@PCI_SUPPORT +kmod-mii +r8169-firmware +kmod-phy-realtek +kmod-mdio-devres KCONFIG:= \ CONFIG_R8169 \ CONFIG_R8169_LEDS=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 09f5d3115..96e522fc4 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -339,6 +339,7 @@ curl -so files/root/.bashrc $mirror/openwrt/files/root/.bashrc # rootfs files mkdir -p files/etc/sysctl.d +curl -so files/etc/sysctl.d/10-default.conf $mirror/openwrt/files/etc/sysctl.d/10-default.conf curl -so files/etc/sysctl.d/15-vm-swappiness.conf $mirror/openwrt/files/etc/sysctl.d/15-vm-swappiness.conf curl -so files/etc/sysctl.d/16-udp-buffer-size.conf $mirror/openwrt/files/etc/sysctl.d/16-udp-buffer-size.conf if [ "$platform" = "bcm53xx" ]; then diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 88d005f63..1cf518fe6 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -7,7 +7,11 @@ git clone https://$github/sbwml/autocore-arm -b openwrt-24.10 package/system/aut # rockchip - target - r4s/r5s only rm -rf target/linux/rockchip -git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-24.10 +if [ "$(whoami)" = "sbwml" ]; then + git clone https://$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-24.10 +else + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-24.10 +fi # bpf-headers - 6.12 sed -ri "s/(PKG_PATCHVER:=)[^\"]*/\16.12/" package/kernel/bpf-headers/Makefile @@ -26,9 +30,15 @@ curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network # bcm53xx - target rm -rf target/linux/bcm53xx -git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_bcm53xx target/linux/bcm53xx -git clone https://nanopi:nanopi@$gitea/sbwml/brcmfmac-firmware-4366c-pcie package/firmware/brcmfmac-firmware-4366c-pcie -git clone https://nanopi:nanopi@$gitea/sbwml/brcmfmac-firmware-4366b-pcie package/firmware/brcmfmac-firmware-4366b-pcie +if [ "$(whoami)" = "sbwml" ]; then + git clone https://$gitea/sbwml/target_linux_bcm53xx target/linux/bcm53xx + git clone https://$gitea/sbwml/brcmfmac-firmware-4366c-pcie package/firmware/brcmfmac-firmware-4366c-pcie + git clone https://$gitea/sbwml/brcmfmac-firmware-4366b-pcie package/firmware/brcmfmac-firmware-4366b-pcie +else + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_bcm53xx target/linux/bcm53xx + git clone https://"$git_name":"$git_password"@$gitea/sbwml/brcmfmac-firmware-4366c-pcie package/firmware/brcmfmac-firmware-4366c-pcie + git clone https://"$git_name":"$git_password"@$gitea/sbwml/brcmfmac-firmware-4366b-pcie package/firmware/brcmfmac-firmware-4366b-pcie +fi # armsr/armv8 rm -rf target/linux/armsr @@ -48,11 +58,10 @@ release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_bu if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then git clone https://$github/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 else - if [ "$(whoami)" = "runner" ]; then - git_name=private - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 - elif [ "$(whoami)" = "sbwml" ]; then + if [ "$(whoami)" = "sbwml" ]; then git clone https://$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 + else + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 fi fi cp -a target/linux/generic-6.12/* target/linux/generic @@ -169,6 +178,7 @@ git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware # mt76 mkdir -p package/kernel/mt76/patches +curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile curl -s $mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index b3329ed54..110c6670f 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -18,6 +18,9 @@ git clone https://github.com/sbwml/wwan-packages package/new/wwan rm -rf feeds/luci/applications/luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager +# luci-app-airplay2 +git clone https://github.com/sbwml/luci-app-airplay2 package/new/airplay2 + # luci-app-webdav git clone https://$github/sbwml/luci-app-webdav package/new/luci-app-webdav diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 364947186..d590d98c2 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .9 -LINUX_KERNEL_HASH-6.12.9 = 87be0360df0931b340d2bac35161a548070fbc3a8c352c49e21e96666c26aeb4 +LINUX_VERSION-6.12 = .12 +LINUX_KERNEL_HASH-6.12.12 = e98942d17ef7063b3f2d6d7692bf24899e2e021cf832d19b55308ec8e8e08eff diff --git a/tags/v24 b/tags/v24 index 17499afca..21651351e 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.0-rc5 +24.10.0 From 763905c641f9d83bada590fa43d1609dfa16cc33 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 8 Feb 2025 19:22:06 +0800 Subject: [PATCH 182/425] ci: private build * This source code has a backdoor and no one is allowed to build it anymore. * #92 Signed-off-by: sbwml --- .github/workflows/build-release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 311f92e50..fa1b8b02f 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -120,6 +120,9 @@ jobs: working-directory: /builder id: compile continue-on-error: true + env: + git_name: ${{ secrets.username }} + git_password: ${{ secrets.password }} run: | export ${{ github.event.inputs.build_options }} LAN=${{ github.event.inputs.lan_addr }} USE_GCC15=y [ ${{ github.event.inputs.ccache }} = 'true' ] && export ENABLE_CCACHE=y From 073e5cc35fb190a72465e44b21bc155dda56e2ea Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 9 Feb 2025 11:14:37 +0800 Subject: [PATCH 183/425] linux-6.12: bump to 6.12.13 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index d590d98c2..795745f52 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .12 -LINUX_KERNEL_HASH-6.12.12 = e98942d17ef7063b3f2d6d7692bf24899e2e021cf832d19b55308ec8e8e08eff +LINUX_VERSION-6.12 = .13 +LINUX_KERNEL_HASH-6.12.13 = f3ebdeea9e555b4cface44e29670056f4024541e6bd222fbcf776c818974fbba From 9f07215ccb2f2ed8b76b09be67fba119c0978d60 Mon Sep 17 00:00:00 2001 From: Bard <984419930@qq.com> Date: Sun, 9 Feb 2025 11:27:31 +0800 Subject: [PATCH 184/425] docs: authorization --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index bfc40f0f3..5c816706d 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,16 @@ sudo apt-get install -y build-essential flex bison g++ gawk gcc-multilib g++-mul --------------- +## 授权构建 +#### 由于本源码具备后门被证实 [#92](https://github.com/sbwml/r4s_build_script/issues/92),良心发现后,防止毒害社会不再允许任何人~~与狗~~直接构建😏 +#### 如果你得到授权,请在构建前执行以下命令 + +``` +export git_name=账户名 git_password=密码 +``` + +--------------- + ### 启用 [Clang/LLVM](https://docs.kernel.org/kbuild/llvm.html) 构建内核 ##### 脚本支持使用 Clang/LLVM 构建内核,NanoPi & X86_64 设备将同时启用 LLVM LTO 链接时优化,这会增加编译的时间,但会获得更优的性能 ##### 只需在构建固件前执行以下命令即可启用 Clang/LLVM 构建内核与内核模块 From 2eae79de5db5242f82af290dd0eedf7fae6f3876 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Feb 2025 09:07:56 +0800 Subject: [PATCH 185/425] build.sh: check authorization Signed-off-by: sbwml --- openwrt/build.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openwrt/build.sh b/openwrt/build.sh index ae000d164..aed77ca91 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -20,6 +20,13 @@ endgroup() { GROUP= } +# check +if [ "$(whoami)" != "sbwml" ] && [ -z "$git_name" ] && [ -z "$git_password" ]; then + echo -e "\n${RED_COLOR} Not authorized. Execute the following command to provide authorization information:${RES}\n" + echo -e "${BLUE_COLOR} export git_name=your_username git_password=your_password${RES}\n" + exit 1 +fi + ##################################### # NanoPi R4S OpenWrt Build Script # ##################################### From a9fcc230bf860ed9f0c991822440842ff4ea7864 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Feb 2025 09:08:40 +0800 Subject: [PATCH 186/425] libubox: disable O3 optimization Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 96e522fc4..a13adae7f 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -66,6 +66,9 @@ else curl -s $mirror/openwrt/patch/target-modify_for_rockchip.patch | patch -p1 fi +# libubox +sed -i '/TARGET_CFLAGS/ s/$/ -Os/' package/libs/libubox/Makefile + # DPDK & NUMACTL mkdir -p package/new/{dpdk/patches,numactl} curl -s $mirror/openwrt/patch/dpdk/dpdk/Makefile > package/new/dpdk/Makefile From d55467e9ea65216a9b01d5ccbe3817c6ca9344f3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Feb 2025 10:40:36 +0800 Subject: [PATCH 187/425] toolchain: GCC 15-20250209 Snapshot (15.0.1) * This snapshot has been generated from the GCC 15 git branch with the following options: git://gcc.gnu.org/git/gcc.git branch master revision 22e30d60b971eed9a4754ea920d05b1b7e89090a Signed-off-by: sbwml --- openwrt/24-config-common | 1 - ...toolchain-gcc-add-support-for-GCC-15.patch | 10 +-- .../gmp/001-fix-build-with-gcc-15.patch | 11 ++++ ...lation-issues-with-ncurses-on-GCC-15.patch | 20 ++++++ openwrt/scripts/02-prepare_package.sh | 3 - openwrt/scripts/05-fix-source.sh | 64 +++++++++++++++++++ 6 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch create mode 100644 openwrt/patch/openwrt-6.x/gcc-15-c23/htop/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 45284a687..1d57f787b 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -256,7 +256,6 @@ CONFIG_PACKAGE_lrzsz=y CONFIG_PACKAGE_lsblk=y CONFIG_PACKAGE_lscpu=y CONFIG_PACKAGE_lsof=y -CONFIG_PACKAGE_nethogs=y CONFIG_PACKAGE_openssh-sftp-server=y CONFIG_PACKAGE_pciutils=y CONFIG_PACKAGE_qrencode=y diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch index 0e585102d..3e4cdc387 100644 --- a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -76,7 +76,7 @@ index 49bb368..be06df2 100644 default "11.3.0" if GCC_VERSION_11 default "12.3.0" if GCC_VERSION_12 default "14.2.0" if GCC_VERSION_14 -+ default "15.0.0" if GCC_VERSION_15 ++ default "15.0.1" if GCC_VERSION_15 default "13.3.0" config GCC_USE_DEFAULT_VERSION @@ -89,8 +89,8 @@ index 0ccf55b..50e924f 100644 GCC_DIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) -+ifeq ($(PKG_VERSION),15.0.0) -+ PKG_SOURCE_URL:=https://us.cooluc.com/gcc/20241103 ++ifeq ($(PKG_VERSION),15.0.1) ++ PKG_SOURCE_URL:=https://us.cooluc.com/gcc/20250209 +else + PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) +endif @@ -101,8 +101,8 @@ index 0ccf55b..50e924f 100644 PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 endif -+ifeq ($(PKG_VERSION),15.0.0) -+ PKG_HASH:=da4db21566241844d14b5b2caad4e2cfccbcbe656f10c0b929eea68dfe807ca3 ++ifeq ($(PKG_VERSION),15.0.1) ++ PKG_HASH:=fe13d340157821fb8d04193664d420a4f15de0f6f562415c0869fc371421d933 +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x diff --git a/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch b/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch new file mode 100644 index 000000000..8df6a5891 --- /dev/null +++ b/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch @@ -0,0 +1,11 @@ +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -609,7 +609,7 @@ GMP_PROG_CC_WORKS_PART([$1], [long long + + #if defined (__GNUC__) && ! defined (__cplusplus) + typedef unsigned long long t1;typedef t1*t2; +-void g(){} ++void g(int,t1 const*,t1,t2,t1 const*,int){} + void h(){} + static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0) + {t1 c,x,r;int i;if(v0){c=1;for(i=1;i +Date: Mon, 9 Dec 2024 22:18:08 +0100 +Subject: [PATCH] Avoid compilation issues with ncurses on GCC 15 + +Fixes: #1567 +--- + configure.ac | 1 + + 1 file changed, 1 insertion(+) + +--- a/configure.ac ++++ b/configure.ac +@@ -449,6 +449,7 @@ if test "$my_htop_platform" = "solaris"; + fi + AC_CHECK_FUNCS( [set_escdelay] ) + AC_CHECK_FUNCS( [getmouse] ) ++AC_DEFINE([NCURSES_ENABLE_STDBOOL_H], [1], [Define to enable stdbool.h in ncurses]) + + + AC_ARG_ENABLE([affinity], diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 110c6670f..49c98e8f3 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -96,9 +96,6 @@ git clone https://$github/sbwml/luci-app-airconnect package/new/airconnect # netkit-ftp git clone https://$github/sbwml/package_new_ftp package/new/ftp -# nethogs -git clone https://github.com/sbwml/package_new_nethogs package/new/nethogs - # SSRP & Passwall rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index a1372fc1f..82da69034 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -58,6 +58,70 @@ if [ "$USE_GCC15" = y ]; then curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libxcrypt/patches/901-fix-string-initialization-error-on-gcc15.patch fi +# fix gcc-15.0.1 C23 +if [ "$USE_GCC15" = y ]; then + # gmp + mkdir -p package/libs/gmp/patches + curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch > package/libs/gmp/patches/001-fix-build-with-gcc-15.patch + # htop + mkdir -p feeds/packages/admin/htop/patches + curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15-c23/htop/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch > feeds/packages/admin/htop/patches/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch + # libtirpc + sed -i '/TARGET_CFLAGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/libtirpc/Makefile + # libsepol + sed -i '/HOST_MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' package/libs/libsepol/Makefile + # tree + sed -i '/MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/tree/Makefile + # gdbm + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/gdbm/Makefile + # libical + sed -i '/CMAKE_OPTIONS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/libical/Makefile + # libconfig + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' package/feeds/packages/libconfig/Makefile + # lsof + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/lsof/Makefile + # screen + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/screen/Makefile + # ppp + sed -i '/CONFIGURE_VARS/i \\nTARGET_CFLAGS += -std=gnu17\n' package/network/services/ppp/Makefile + # vim + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/vim/Makefile + # mtd + sed -i '/target=/i TARGET_CFLAGS += -std=gnu17\n' package/system/mtd/Makefile + # libselinux + sed -i '/MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' package/libs/libselinux/Makefile + # avahi + sed -i '/TARGET_CFLAGS +=/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/avahi/Makefile + # bash + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/bash/Makefile + # xl2tpd + sed -i '/ifneq (0,0)/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/xl2tpd/Makefile + # dnsmasq + sed -i '/MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' package/network/services/dnsmasq/Makefile + # bluez + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/bluez/Makefile + # e2fsprogs + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' package/utils/e2fsprogs/Makefile + # f2fs-tools + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' package/utils/f2fs-tools/Makefile + # krb5 + sed -i '/CONFIGURE_VARS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/krb5/Makefile + # parted + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/parted/Makefile + # iperf3 + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/iperf3/Makefile + # db + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/db/Makefile + # python3 + sed -i '/TARGET_CONFIGURE_OPTS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/lang/python/python3/Makefile + # uwsgi + sed -i '/MAKE_VARS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/uwsgi/Makefile + # perl + sed -i '/Target perl/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/lang/perl/Makefile + # rsync + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/rsync/Makefile +fi + # ksmbd luci sed -i 's/0666/0644/g;s/0777/0755/g' feeds/luci/applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js From 536a7691a5c2d4c7e6341c6d28bd4f33ede626f2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Feb 2025 11:12:20 +0800 Subject: [PATCH 188/425] openwrt_core: drop build fibocom-dial Signed-off-by: sbwml --- openwrt/build.sh | 4 ---- openwrt/generic/config-wwan | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index aed77ca91..dc9694c16 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -438,7 +438,6 @@ if [ "$platform" = "x86_64" ]; then cp -a bin/packages/x86_64/base/*modemband*.ipk $kmodpkg_name/ cp -a bin/packages/x86_64/base/*sms-tool*.ipk $kmodpkg_name/ cp -a bin/packages/x86_64/base/*quectel*.ipk $kmodpkg_name/ - cp -a bin/packages/x86_64/base/*fibocom*.ipk $kmodpkg_name/ } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true @@ -487,7 +486,6 @@ elif [ "$platform" = "armv8" ]; then cp -a bin/packages/aarch64_generic/base/*modemband*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*sms-tool*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*quectel*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*fibocom*.ipk $kmodpkg_name/ } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true @@ -526,7 +524,6 @@ elif [ "$platform" = "bcm53xx" ]; then cp -a bin/packages/arm_cortex-a9/base/*modemband*.ipk $kmodpkg_name/ cp -a bin/packages/arm_cortex-a9/base/*sms-tool*.ipk $kmodpkg_name/ cp -a bin/packages/arm_cortex-a9/base/*quectel*.ipk $kmodpkg_name/ - cp -a bin/packages/arm_cortex-a9/base/*fibocom*.ipk $kmodpkg_name/ } bash kmod-sign $kmodpkg_name tar zcf bcm53xx-$kmodpkg_name.tar.gz $kmodpkg_name @@ -566,7 +563,6 @@ else cp -a bin/packages/aarch64_generic/base/*modemband*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*sms-tool*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/*quectel*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*fibocom*.ipk $kmodpkg_name/ } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true diff --git a/openwrt/generic/config-wwan b/openwrt/generic/config-wwan index 4e782ed6d..2e9bfbbf5 100644 --- a/openwrt/generic/config-wwan +++ b/openwrt/generic/config-wwan @@ -4,6 +4,6 @@ CONFIG_PACKAGE_luci-app-3ginfo-lite=m CONFIG_PACKAGE_luci-app-modemband=m CONFIG_PACKAGE_luci-app-sms-tool-js=m CONFIG_PACKAGE_luci-proto-quectel=m -CONFIG_PACKAGE_fibocom-dial=m +# CONFIG_PACKAGE_fibocom-dial is not set CONFIG_PACKAGE_modemband=m CONFIG_PACKAGE_quectel-cm=m From 1e2563028f6f59e4d299b36c7996251092083984 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Feb 2025 17:42:09 +0800 Subject: [PATCH 189/425] shine: build with std=gnu17 Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 82da69034..fc5314473 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -120,6 +120,8 @@ if [ "$USE_GCC15" = y ]; then sed -i '/Target perl/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/lang/perl/Makefile # rsync sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/rsync/Makefile + # shine + sed -i '/Build\/InstallDev/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/sound/shine/Makefile fi # ksmbd luci From e48d2a5c83d2bc4bb3a0931bc570a049a7e9f8c3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Feb 2025 22:43:25 +0800 Subject: [PATCH 190/425] build.sh: fix github action Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index dc9694c16..839aa8aa8 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -43,7 +43,7 @@ else fi # github actions - caddy server -if [ "$(whoami)" = "runner" ] && [ -z "$git_password" ]; then +if [ "$(whoami)" = "runner" ] && [ "$git_name" != "private" ]; then export mirror=http://127.0.0.1:8080 fi From e7dc5648abc5604d4019744a1c5ead1cfaada6ae Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 16 Feb 2025 19:11:18 +0800 Subject: [PATCH 191/425] jq: build with std=gnu17 Signed-off-by: sbwml --- openwrt/build.sh | 2 +- openwrt/scripts/05-fix-source.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 839aa8aa8..1425dfd5c 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -153,8 +153,8 @@ get_kernel_version=$(curl -s $mirror/tags/kernel-6.12) kmod_hash=$(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}' | tail -1 | md5sum | awk '{print $1}') kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" - echo -e "${GREEN_COLOR}Date: $CURRENT_DATE${RES}\r\n" +echo -e "${GREEN_COLOR}SCRIPT_URL:${RES} ${BLUE_COLOR}$mirror${RES}\r\n" echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" [ -n "$LAN" ] && echo -e "${GREEN_COLOR}LAN: $LAN${RES}" || echo -e "${GREEN_COLOR}LAN: 10.0.0.1${RES}" [ "$ENABLE_GLIBC" = "y" ] && echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}glibc${RES}" || echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}musl${RES}" diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index fc5314473..3a5caa7eb 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -122,6 +122,8 @@ if [ "$USE_GCC15" = y ]; then sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/rsync/Makefile # shine sed -i '/Build\/InstallDev/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/sound/shine/Makefile + # jq + sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/jq/Makefile fi # ksmbd luci From 5b3f0330816157e5ac08f925cda44cc887c564e4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 18 Feb 2025 02:13:15 +0800 Subject: [PATCH 192/425] linux-6.12: bump to 6.12.14 Signed-off-by: sbwml --- openwrt/scripts/04-fix_kmod.sh | 3 +++ tags/kernel-6.12 | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index 38d306c59..d0a2f79bf 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -85,4 +85,7 @@ if [ "$KERNEL_CLANG_LTO" = "y" ]; then # coova-chilli module rm -rf feeds/packages/net/coova-chilli git clone https://$github/sbwml/kmod_packages_net_coova-chilli feeds/packages/net/coova-chilli +else + # coova-chilli - fix gcc 15 c23 + [ "$USE_GCC15" = y ] && sed -i '/TARGET_CFLAGS/s/$/ -std=gnu17/' feeds/packages/net/coova-chilli/Makefile fi diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 795745f52..0ace4c42b 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .13 -LINUX_KERNEL_HASH-6.12.13 = f3ebdeea9e555b4cface44e29670056f4024541e6bd222fbcf776c818974fbba +LINUX_VERSION-6.12 = .14 +LINUX_KERNEL_HASH-6.12.14 = 9423f4bfb4d875417e39cb0b017b5499fea47da56119f0cd28a201735d898f14 From 7290f9678f8518fae02a471ace7c4ad2208779c6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 19 Feb 2025 17:56:11 +0800 Subject: [PATCH 193/425] linux-6.12: bump to 6.12.15 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 0ace4c42b..2451a9658 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .14 -LINUX_KERNEL_HASH-6.12.14 = 9423f4bfb4d875417e39cb0b017b5499fea47da56119f0cd28a201735d898f14 +LINUX_VERSION-6.12 = .15 +LINUX_KERNEL_HASH-6.12.15 = 5ff5bd84ea0e22c53437302db5d394d0a92d8b8b1a88ce20d1098298e9f7630a From 07e3b4530040d5b94b36227c48de4f7a211ba9d9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 23 Feb 2025 17:54:56 +0800 Subject: [PATCH 194/425] linux-6.12: bump to 6.12.16 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 2451a9658..15d3cb6d6 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .15 -LINUX_KERNEL_HASH-6.12.15 = 5ff5bd84ea0e22c53437302db5d394d0a92d8b8b1a88ce20d1098298e9f7630a +LINUX_VERSION-6.12 = .16 +LINUX_KERNEL_HASH-6.12.16 = 5f81362a694f51520bff9faecb73f1cc9bc7bece6fdd10d5c27e348df39d7dc4 From 3b39d7f0088b74118466813b945536220b778e31 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 27 Feb 2025 22:43:11 +0800 Subject: [PATCH 195/425] golang: update to 1.24.x Signed-off-by: sbwml --- openwrt/build.sh | 2 +- openwrt/scripts/02-prepare_package.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 1425dfd5c..b5138f1f0 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -120,7 +120,7 @@ elif [ "$USE_GCC14" = y ]; then elif [ "$USE_GCC15" = y ]; then export USE_GCC15=y gcc_version=15 else - export USE_GCC13=y gcc_version=13 + export USE_GCC14=y gcc_version=14 fi [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 49c98e8f3..d247b83bc 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -1,8 +1,8 @@ #!/bin/bash -e -# golang 1.23 +# golang 1.24 rm -rf feeds/packages/lang/golang -git clone https://$github/sbwml/packages_lang_golang -b 23.x feeds/packages/lang/golang +git clone https://$github/sbwml/packages_lang_golang -b 24.x feeds/packages/lang/golang # node - prebuilt rm -rf feeds/packages/lang/node From b20569f3b2fcbac71df472ac043d45cc97a1489e Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 27 Feb 2025 22:53:54 +0800 Subject: [PATCH 196/425] linux-6.12: bump to 6.12.17 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- tags/kernel-tag.sh | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 15d3cb6d6..1cec724fa 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .16 -LINUX_KERNEL_HASH-6.12.16 = 5f81362a694f51520bff9faecb73f1cc9bc7bece6fdd10d5c27e348df39d7dc4 +LINUX_VERSION-6.12 = .17 +LINUX_KERNEL_HASH-6.12.17 = 5c205cd34f80974e4973e321cb008f5f6895a8aa8c2577f06a9448cd77de63b3 diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index 262f8400c..b744dcc68 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -1,10 +1,12 @@ #!/bin/bash +set -e + ROOT="./" # LTS -KERNEL_VERSION=`curl -s https://cdn.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc | awk '{print $2}' | grep -E ^linux-6.12 | grep tar.xz | sed 's/linux-//g;s/.tar.xz//g' | tail -n 1` -KERNEL_HASH=`curl -s https://cdn.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc | grep linux-$KERNEL_VERSION | grep tar.xz | awk '{print $1}'` +KERNEL_VERSION=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "6_12") | .version'` +KERNEL_HASH=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "6_12") | .checksum'` TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` [ -z $TAG ] && TAG="" || TAG=.$TAG From 45a27d7b8f1ef5efb89f7c0a7cafaa0e9fbf9a1f Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 7 Mar 2025 21:56:04 +0800 Subject: [PATCH 197/425] libpcap: fix symbol link errors Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index d247b83bc..6c6a8db41 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -167,3 +167,7 @@ git clone https://$github/sbwml/package_kernel_tcp-brutal package/kernel/tcp-bru # watchcat - clean config true > feeds/packages/utils/watchcat/files/watchcat.config + +# libpcap +rm -rf package/libs/libpcap +git clone https://$github/sbwml/package_libs_libpcap package/libs/libpcap From 7d9fd954ce5d12fc288c9638dda19cb323be91d7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 9 Mar 2025 18:52:56 +0800 Subject: [PATCH 198/425] linux-6.12: bump to 6.12.18 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 1cec724fa..5ac943ebb 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .17 -LINUX_KERNEL_HASH-6.12.17 = 5c205cd34f80974e4973e321cb008f5f6895a8aa8c2577f06a9448cd77de63b3 +LINUX_VERSION-6.12 = .18 +LINUX_KERNEL_HASH-6.12.18 = beb902a5f69d9e57710112203db38111dad6d30556ea8ce389284c8077fe944d From 1fcb463966f20f8682e65a4ce6df48e5f369318c Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Mar 2025 22:28:59 +0800 Subject: [PATCH 199/425] opkg: make package conffiles a sysupgrade preserve Signed-off-by: sbwml --- ...tall-copy-conffiles-to-the-system-co.patch | 57 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 1 + 2 files changed, 58 insertions(+) create mode 100644 openwrt/patch/opkg/901-libopkg-opkg_install-copy-conffiles-to-the-system-co.patch diff --git a/openwrt/patch/opkg/901-libopkg-opkg_install-copy-conffiles-to-the-system-co.patch b/openwrt/patch/opkg/901-libopkg-opkg_install-copy-conffiles-to-the-system-co.patch new file mode 100644 index 000000000..e7b6ec0d1 --- /dev/null +++ b/openwrt/patch/opkg/901-libopkg-opkg_install-copy-conffiles-to-the-system-co.patch @@ -0,0 +1,57 @@ +From 74dbda351198a9028a69a912be85cefd72c0cec9 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 13 Mar 2025 22:07:10 +0800 +Subject: [PATCH] libopkg: opkg_install: copy conffiles to the system + configuration preserved list + +Signed-off-by: sbwml +--- + libopkg/opkg_install.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/libopkg/opkg_install.c b/libopkg/opkg_install.c +index 68fb9ea..b4d18a2 100644 +--- a/libopkg/opkg_install.c ++++ b/libopkg/opkg_install.c +@@ -1394,6 +1394,38 @@ int opkg_install_pkg(pkg_t * pkg, int from_upgrade) + } + } + ++ /* Handle conffiles for sysupgrade */ ++ { ++ const char *tmp_dir = pkg_get_string(pkg, PKG_TMP_UNPACK_DIR); ++ if (tmp_dir) { ++ char *conffiles_path; ++ asprintf(&conffiles_path, "%s/conffiles", tmp_dir); ++ if (file_exists(conffiles_path)) { ++ char *keep_dir = "/lib/upgrade/keep.d"; ++ char *keep_file; ++ asprintf(&keep_file, "%s/%s", keep_dir, pkg->name); ++ ++ if (file_mkdir_hier(keep_dir, 0755) != 0) { ++ opkg_msg(ERROR, "Failed to create directory %s: %s\n", ++ keep_dir, strerror(errno)); ++ goto cleanup_conffiles; ++ } ++ ++ if (file_copy(conffiles_path, keep_file) != 0) { ++ opkg_msg(ERROR, "Failed to copy %s to %s\n", ++ conffiles_path, keep_file); ++ goto cleanup_conffiles; ++ } ++ opkg_msg(DEBUG, "Copied conffiles to %s for sysupgrade\n", ++ keep_file); ++ ++ cleanup_conffiles: ++ free(keep_file); ++ } ++ free(conffiles_path); ++ } ++ } ++ + err = update_file_ownership(pkg, old_pkg); + if (err) + return -1; +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index a13adae7f..7d1d5d40a 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -280,6 +280,7 @@ curl -s $mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/ # opkg mkdir -p package/system/opkg/patches curl -s $mirror/openwrt/patch/opkg/900-opkg-download-disable-hsts.patch > package/system/opkg/patches/900-opkg-download-disable-hsts.patch +curl -s $mirror/openwrt/patch/opkg/901-libopkg-opkg_install-copy-conffiles-to-the-system-co.patch > package/system/opkg/patches/901-libopkg-opkg_install-copy-conffiles-to-the-system-co.patch # uwsgi - fix timeout sed -i '$a cgi-timeout = 600' feeds/packages/net/uwsgi/files-luci-support/luci-*.ini From 640e8ee545ccbb6a74c736047c81c779c69aab1a Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Mar 2025 22:42:56 +0800 Subject: [PATCH 200/425] linux-6.12: bump to 6.12.19 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 5ac943ebb..c452ee214 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .18 -LINUX_KERNEL_HASH-6.12.18 = beb902a5f69d9e57710112203db38111dad6d30556ea8ce389284c8077fe944d +LINUX_VERSION-6.12 = .19 +LINUX_KERNEL_HASH-6.12.19 = d73bf057bec04434b169d1b61641936f7d0c97ceb923a281f32e35dd4dcc6531 From 04bf4dfdf47db907a8d08fb517ddd8d26b5ff587 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 20 Mar 2025 20:41:03 +0800 Subject: [PATCH 201/425] patch: kernel-6.12: refresh patches Signed-off-by: sbwml --- ..._bbr-broaden-app-limited-rate-sample-detectio.patch | 2 +- ..._bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch | 4 ++-- ..._bbr-v2-snapshot-packets-in-flight-at-transmi.patch | 8 ++++---- ..._bbr-v2-count-packets-lost-over-TCP-rate-samp.patch | 4 ++-- ..._bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch | 4 ++-- ..._bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch | 4 ++-- ..._bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch | 2 +- ..._bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch | 6 +++--- ...-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 8 ++++---- ...-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch | 4 ++-- ...-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch | 4 ++-- ..._bbr-v2-record-app-limited-status-of-TLP-repa.patch | 2 +- ..._bbr-v2-inform-CC-module-of-losses-repaired-b.patch | 4 ++-- ..._bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch | 10 +++++----- ...roduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch | 8 ++++---- ..._bbr-v3-update-TCP-bbr-congestion-control-mod.patch | 2 +- ..._bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch | 4 ++-- ...ort-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 2 +- .../990-btf-silence-btf-module-warning-messages.patch | 2 +- ...5-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch | 6 +++--- ...LRNG-0012-scheduler-add-entropy-sampling-hook.patch | 2 +- ...-conntrack-events-support-multiple-registrant.patch | 2 +- ...net-patch-linux-kernel-to-support-shortcut-fe.patch | 10 +++++----- .../net/983-add-bcm-fullcone-nft_masq-support.patch | 2 +- 24 files changed, 53 insertions(+), 53 deletions(-) diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index a24a92864..814d89a39 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -32,7 +32,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3961,6 +3961,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -3967,6 +3967,7 @@ static int tcp_ack(struct sock *sk, cons prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; rs.prior_in_flight = tcp_packets_in_flight(tp); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch index 3ebe1d642..69edfe392 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -884,6 +884,11 @@ static inline u32 tcp_stamp_us_delta(u64 +@@ -901,6 +901,11 @@ static inline u32 tcp_stamp_us_delta(u64 return max_t(s64, t1 - t0, 0); } @@ -37,7 +37,7 @@ Signed-off-by: Alexandre Frade /* provide the departure time in us unit */ static inline u64 tcp_skb_timestamp_us(const struct sk_buff *skb) { -@@ -973,9 +978,9 @@ struct tcp_skb_cb { +@@ -990,9 +995,9 @@ struct tcp_skb_cb { /* pkts S/ACKed so far upon tx of skb, incl retrans: */ __u32 delivered; /* start of send pipeline phase */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index 4772241b7..565bbe787 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -981,6 +981,10 @@ struct tcp_skb_cb { +@@ -998,6 +998,10 @@ struct tcp_skb_cb { u32 first_tx_mstamp; /* when we reached the "delivered" count */ u32 delivered_mstamp; @@ -38,7 +38,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1137,6 +1141,7 @@ struct rate_sample { +@@ -1154,6 +1158,7 @@ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ @@ -46,7 +46,7 @@ Signed-off-by: Alexandre Frade s32 delivered; /* number of packets delivered over interval */ s32 delivered_ce; /* number of packets delivered w/ CE marks*/ long interval_us; /* time for tp->delivered to incr "delivered" */ -@@ -1259,6 +1264,7 @@ static inline void tcp_ca_event(struct s +@@ -1276,6 +1281,7 @@ static inline void tcp_ca_event(struct s void tcp_set_ca_state(struct sock *sk, const u8 ca_state); /* From tcp_rate.c */ @@ -56,7 +56,7 @@ Signed-off-by: Alexandre Frade struct rate_sample *rs); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2767,6 +2767,7 @@ static bool tcp_write_xmit(struct sock * +@@ -2770,6 +2770,7 @@ static bool tcp_write_xmit(struct sock * skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); tcp_init_tso_segs(skb, mss_now); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch index 0554f920f..9939f1593 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch @@ -19,7 +19,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -985,6 +985,7 @@ struct tcp_skb_cb { +@@ -1002,6 +1002,7 @@ struct tcp_skb_cb { #define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) u32 in_flight:20, /* packets in flight at transmit */ unused2:12; @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1139,11 +1140,13 @@ struct ack_sample { +@@ -1156,11 +1157,13 @@ struct ack_sample { */ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index fcf83ac0a..72f08ce89 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -18,7 +18,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1158,6 +1158,7 @@ struct rate_sample { +@@ -1175,6 +1175,7 @@ struct rate_sample { bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ bool is_ack_delayed; /* is this (likely) a delayed ACK? */ @@ -28,7 +28,7 @@ Signed-off-by: Alexandre Frade struct tcp_congestion_ops { --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4060,6 +4060,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4066,6 +4066,7 @@ static int tcp_ack(struct sock *sk, cons delivered = tcp_newly_delivered(sk, delivered, flag); lost = tp->lost - lost; /* freshly marked lost */ rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index 99139bcc6..822255b0d 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -30,7 +30,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1185,6 +1185,9 @@ struct tcp_congestion_ops { +@@ -1202,6 +1202,9 @@ struct tcp_congestion_ops { /* override sysctl_tcp_min_tso_segs */ u32 (*min_tso_segs)(struct sock *sk); @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1120,7 +1120,12 @@ static void tcp_verify_retransmit_hint(s +@@ -1126,7 +1126,12 @@ static void tcp_verify_retransmit_hint(s */ static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) { diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch index 85508458a..239e4dad4 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch @@ -39,7 +39,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1506,6 +1506,17 @@ static bool tcp_shifted_skb(struct sock +@@ -1512,6 +1512,17 @@ static bool tcp_shifted_skb(struct sock WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); tcp_skb_pcount_add(skb, -pcount); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch index 3211647f5..84cfd569d 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1284,6 +1284,21 @@ static inline bool tcp_skb_sent_after(u6 +@@ -1301,6 +1301,21 @@ static inline bool tcp_skb_sent_after(u6 return t1 > t2 || (t1 == t2 && after(seq1, seq2)); } @@ -55,7 +55,7 @@ Signed-off-by: Alexandre Frade * between different flows. --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -1603,7 +1603,7 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1606,7 +1606,7 @@ int tcp_fragment(struct sock *sk, enum t { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; @@ -64,7 +64,7 @@ Signed-off-by: Alexandre Frade long limit; int nlen; u8 flags; -@@ -1678,6 +1678,30 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1681,6 +1681,30 @@ int tcp_fragment(struct sock *sk, enum t if (diff) tcp_adjust_pcount(sk, skb, diff); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch index 6bf00dbaf..3cc72d5ae 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch @@ -23,7 +23,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1120,7 +1120,11 @@ enum tcp_ca_ack_event_flags { +@@ -1137,7 +1137,11 @@ enum tcp_ca_ack_event_flags { #define TCP_CONG_NON_RESTRICTED 0x1 /* Requires ECN/ECT set on all packets */ #define TCP_CONG_NEEDS_ECN 0x2 @@ -36,7 +36,7 @@ Signed-off-by: Alexandre Frade union tcp_cc_info; -@@ -1252,6 +1256,14 @@ static inline char *tcp_ca_get_name_by_k +@@ -1269,6 +1273,14 @@ static inline char *tcp_ca_get_name_by_k } #endif @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade const struct inet_connection_sock *icsk = inet_csk(sk); --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -370,7 +370,7 @@ static void __tcp_ecn_check_ce(struct so +@@ -376,7 +376,7 @@ static void __tcp_ecn_check_ce(struct so tcp_enter_quickack_mode(sk, 2); break; case INET_ECN_CE: @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade tcp_ca_event(sk, CA_EVENT_ECN_IS_CE); if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { -@@ -381,7 +381,7 @@ static void __tcp_ecn_check_ce(struct so +@@ -387,7 +387,7 @@ static void __tcp_ecn_check_ce(struct so tp->ecn_flags |= TCP_ECN_SEEN; break; default: diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch index 87c7c31c6..68d2ce1c8 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1186,8 +1186,8 @@ struct tcp_congestion_ops { +@@ -1203,8 +1203,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); @@ -97,7 +97,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2059,13 +2059,12 @@ static u32 tcp_tso_autosize(const struct +@@ -2062,13 +2062,12 @@ static u32 tcp_tso_autosize(const struct static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) { const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 8a0d95145..b3c7afae6 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -3384,6 +3384,7 @@ int tcp_disconnect(struct sock *sk, int +@@ -3397,6 +3397,7 @@ int tcp_disconnect(struct sock *sk, int tp->rx_opt.dsack = 0; tp->rx_opt.num_sacks = 0; tp->rcv_ooopack = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5770,13 +5770,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5776,13 +5776,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch index 1a2b75f6b..43f19d209 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -3005,6 +3005,7 @@ void tcp_send_loss_probe(struct sock *sk +@@ -3008,6 +3008,7 @@ void tcp_send_loss_probe(struct sock *sk if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index 8ff806a39..26a131d04 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1098,6 +1098,7 @@ enum tcp_ca_event { +@@ -1115,6 +1115,7 @@ enum tcp_ca_event { CA_EVENT_LOSS, /* loss timeout */ CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3859,6 +3859,7 @@ static void tcp_process_tlp_ack(struct s +@@ -3865,6 +3865,7 @@ static void tcp_process_tlp_ack(struct s /* ACK advances: there was a loss, so reduce cwnd. Reset * tlp_high_seq in tcp_init_cwnd_reduction() */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index fed5a4aeb..8a0aa731a 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -21,7 +21,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1162,6 +1162,7 @@ struct rate_sample { +@@ -1179,6 +1179,7 @@ struct rate_sample { u32 last_end_seq; /* end_seq of most recently ACKed packet */ bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3842,7 +3842,8 @@ static void tcp_replace_ts_recent(struct +@@ -3848,7 +3848,8 @@ static void tcp_replace_ts_recent(struct /* This routine deals with acks during a TLP episode and ends an episode by * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack */ @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade { struct tcp_sock *tp = tcp_sk(sk); -@@ -3870,6 +3871,11 @@ static void tcp_process_tlp_ack(struct s +@@ -3876,6 +3877,11 @@ static void tcp_process_tlp_ack(struct s FLAG_NOT_DUP | FLAG_DATA_SACKED))) { /* Pure dupack: original and TLP probe arrived; no loss */ tp->tlp_high_seq = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade } } -@@ -4053,7 +4059,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4059,7 +4065,7 @@ static int tcp_ack(struct sock *sk, cons tcp_rack_update_reo_wnd(sk, &rs); if (tp->tlp_high_seq) @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade if (tcp_ack_is_dubious(sk, flag)) { if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4097,7 +4103,7 @@ no_queue: +@@ -4103,7 +4109,7 @@ no_queue: tcp_ack_probe(sk); if (tp->tlp_high_seq) diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch index 3adcf7d60..0e20e6999 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -375,6 +375,7 @@ static inline void tcp_dec_quickack_mode +@@ -376,6 +376,7 @@ static inline void tcp_dec_quickack_mode #define TCP_ECN_QUEUE_CWR 2 #define TCP_ECN_DEMAND_CWR 4 #define TCP_ECN_SEEN 8 @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade enum tcp_tw_status { TCP_TW_SUCCESS = 0, -@@ -777,6 +778,15 @@ static inline void tcp_fast_path_check(s +@@ -794,6 +795,15 @@ static inline void tcp_fast_path_check(s tcp_fast_path_on(tp); } @@ -88,7 +88,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -336,10 +336,9 @@ static void tcp_ecn_send_syn(struct sock +@@ -339,10 +339,9 @@ static void tcp_ecn_send_syn(struct sock bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk); bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 || tcp_ca_needs_ecn(sk) || bpf_needs_ecn; @@ -100,7 +100,7 @@ Signed-off-by: Alexandre Frade if (dst && dst_feature(dst, RTAX_FEATURE_ECN)) use_ecn = true; } -@@ -351,6 +350,9 @@ static void tcp_ecn_send_syn(struct sock +@@ -354,6 +353,9 @@ static void tcp_ecn_send_syn(struct sock tp->ecn_flags = TCP_ECN_OK; if (tcp_ca_needs_ecn(sk) || bpf_needs_ecn) INET_ECN_xmit(sk); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch index 4e3707dfc..0fdc28068 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -153,7 +153,7 @@ Signed-off-by: Alexandre Frade #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -2474,7 +2474,7 @@ struct tcp_plb_state { +@@ -2491,7 +2491,7 @@ struct tcp_plb_state { u8 consec_cong_rounds:5, /* consecutive congested rounds */ unused:3; u32 pause_until; /* jiffies32 when PLB can resume rerouting */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch index 5198547c1..6de675a2c 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -376,6 +376,7 @@ static inline void tcp_dec_quickack_mode +@@ -377,6 +377,7 @@ static inline void tcp_dec_quickack_mode #define TCP_ECN_DEMAND_CWR 4 #define TCP_ECN_SEEN 8 #define TCP_ECN_LOW 16 @@ -47,7 +47,7 @@ Signed-off-by: Alexandre Frade /* BBR marks the current round trip as a loss round. */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -390,7 +390,8 @@ static void tcp_ecn_send(struct sock *sk +@@ -393,7 +393,8 @@ static void tcp_ecn_send(struct sock *sk th->cwr = 1; skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; } diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch index e4e5369fe..cbc7e2f42 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade * Sender's congestion state indicating normal or abnormal situations --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -4111,6 +4111,8 @@ void tcp_get_info(struct sock *sk, struc +@@ -4124,6 +4124,8 @@ void tcp_get_info(struct sock *sk, struc info->tcpi_options |= TCPI_OPT_ECN; if (tp->ecn_flags & TCP_ECN_SEEN) info->tcpi_options |= TCPI_OPT_ECN_SEEN; diff --git a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch index 3dca39e28..92870fe59 100644 --- a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch +++ b/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch @@ -10,7 +10,7 @@ Signed-off-by: sbwml --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c -@@ -8028,8 +8028,6 @@ static int btf_module_notify(struct noti +@@ -8025,8 +8025,6 @@ static int btf_module_notify(struct noti pr_warn("failed to validate module [%s] BTF: %ld\n", mod->name, PTR_ERR(btf)); err = PTR_ERR(btf); diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch index a0e8ab1b6..f0c574903 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch +++ b/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch @@ -71,7 +71,7 @@ Signed-off-by: Sebastian Andrzej Siewior goto out; --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c -@@ -895,13 +895,15 @@ intel_legacy_cursor_update(struct drm_pl +@@ -902,13 +902,15 @@ intel_legacy_cursor_update(struct drm_pl */ intel_psr_wait_for_idle_locked(crtc_state); @@ -89,8 +89,8 @@ Signed-off-by: Sebastian Andrzej Siewior } if (new_plane_state->uapi.visible) { -@@ -911,7 +913,8 @@ intel_legacy_cursor_update(struct drm_pl - intel_plane_disable_arm(plane, crtc_state); +@@ -918,7 +920,8 @@ intel_legacy_cursor_update(struct drm_pl + intel_plane_disable_arm(NULL, plane, crtc_state); } - local_irq_enable(); diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch index 9db498fa6..e75139bbf 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -24,7 +24,7 @@ Signed-off-by: Stephan Mueller #include #include #include -@@ -3611,6 +3612,8 @@ ttwu_stat(struct task_struct *p, int cpu +@@ -3613,6 +3614,8 @@ ttwu_stat(struct task_struct *p, int cpu { struct rq *rq; diff --git a/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch b/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch index 798d456af..6bcc95125 100644 --- a/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch +++ b/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch @@ -123,7 +123,7 @@ Signed-off-by: Zhi Chen depends on NETFILTER_ADVANCED --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c -@@ -2750,6 +2750,10 @@ int nf_conntrack_init_net(struct net *ne +@@ -2753,6 +2753,10 @@ int nf_conntrack_init_net(struct net *ne nf_conntrack_ecache_pernet_init(net); nf_conntrack_proto_pernet_init(net); diff --git a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index fb05283b2..08a9c9c08 100644 --- a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -17,7 +17,7 @@ Signed-off-by: Xiaoping Fan --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h -@@ -71,6 +71,9 @@ void brioctl_set(int (*hook)(struct net +@@ -72,6 +72,9 @@ void brioctl_set(int (*hook)(struct net int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, struct ifreq *ifr, void __user *uarg); @@ -93,7 +93,7 @@ Signed-off-by: Xiaoping Fan struct net_bridge_port *p; --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -3580,8 +3580,17 @@ static int xmit_one(struct sk_buff *skb, +@@ -3643,8 +3643,17 @@ static int xmit_one(struct sk_buff *skb, unsigned int len; int rc; @@ -111,7 +111,7 @@ Signed-off-by: Xiaoping Fan len = skb->len; trace_net_dev_start_xmit(skb, dev); -@@ -5419,6 +5428,11 @@ void netdev_rx_handler_unregister(struct +@@ -5485,6 +5494,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5467,6 +5481,10 @@ static int __netif_receive_skb_core(stru +@@ -5533,6 +5547,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5505,6 +5523,16 @@ another_round: +@@ -5571,6 +5589,16 @@ another_round: goto out; } diff --git a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch index 11294355c..160fd3fb5 100644 --- a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -30,7 +30,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -11101,6 +11101,24 @@ static int nft_validate_register_load(en +@@ -11152,6 +11152,24 @@ static int nft_validate_register_load(en return 0; } From 36923da83eb817584c2264cd17116bd12086e1b1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 22 Mar 2025 02:28:04 +0800 Subject: [PATCH 202/425] zerotier: fix segmentation fault Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 6c6a8db41..a78ae4ab8 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -83,6 +83,10 @@ sed -i 's/0666/0644/g;s/0777/0755/g' feeds/packages/net/samba4/files/smb.conf.te # rk3568 bind cpus [ "$platform" = "rk3568" ] && sed -i 's#/usr/sbin/smbd -F#/usr/bin/taskset -c 1,0 /usr/sbin/smbd -F#' feeds/packages/net/samba4/files/samba.init +# zerotier +rm -rf feeds/packages/net/zerotier +git clone https://$github/sbwml/feeds_packages_net_zerotier feeds/packages/net/zerotier + # aria2 & ariaNG rm -rf feeds/packages/net/ariang rm -rf feeds/luci/applications/luci-app-aria2 From fd612269fae480a67afe999b6690880366b18157 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 23 Mar 2025 19:58:38 +0800 Subject: [PATCH 203/425] linux-6.12 & mac80211: update to 6.12.20 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 2 +- tags/kernel-6.12 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 1cf518fe6..66c4e86ee 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -185,7 +185,7 @@ curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patc # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - 6.11 +# mac80211 - 6.12 rm -rf package/kernel/mac80211 git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index c452ee214..65ba39ecc 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .19 -LINUX_KERNEL_HASH-6.12.19 = d73bf057bec04434b169d1b61641936f7d0c97ceb923a281f32e35dd4dcc6531 +LINUX_VERSION-6.12 = .20 +LINUX_KERNEL_HASH-6.12.20 = 230e89b07b0ab82e74f07ecc1bee3105dca81d0ef4a97f900929c407249b6ac7 From e3965dd4c5151292ce19f0fe4e9b124f8437c9de Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 23 Mar 2025 19:59:16 +0800 Subject: [PATCH 204/425] mt76: update to 2025-02-14 Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index ef2c61988..ca7fe6c15 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2025-01-22 -PKG_SOURCE_VERSION:=a22d59e4ad50c89326342a0736cd2c1ba32e8a0b -PKG_MIRROR_HASH:=e8bbbada2171ea31a6788e3e46e81c409a9fe038eefe4b41f541da848a1b1bcd +PKG_SOURCE_DATE:=2025-02-14 +PKG_SOURCE_VERSION:=e5fef138524e63314cb96ff8314048d175294e95 +PKG_MIRROR_HASH:=4d6ea8669b3034c97f5b341a5473facf4fe21262a2fde71257b57c4d1c86be5e PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 From 151c895c0039cf2014953800650d0a3ee768d515 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 24 Mar 2025 03:55:57 +0800 Subject: [PATCH 205/425] sms-tools: fix incompatible pointer type error for signal function Signed-off-by: sbwml --- ...tible-pointer-type-error-for-signal-function.patch | 11 +++++++++++ openwrt/scripts/05-fix-source.sh | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch diff --git a/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch b/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch new file mode 100644 index 000000000..f1321bb82 --- /dev/null +++ b/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch @@ -0,0 +1,11 @@ +--- a/sms_main.c ++++ b/sms_main.c +@@ -111,7 +111,7 @@ static void resetserial() + close(port); + } + +-static void timeout() ++static void timeout(int signo) + { + fprintf(stderr,"No response from modem.\n"); + exit(2); diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 3a5caa7eb..09b41be89 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -145,6 +145,10 @@ curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Mak # kselftests-bpf curl -s $mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package/devel/kselftests-bpf/Makefile +# sms-tools +mkdir -p feeds/packages/utils/sms-tool/patches +curl -s $mirror/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch > feeds/packages/utils/sms-tool/patches/900-fix-incompatible-pointer-type-error-for-signal-function.patch + # bcm53xx if [ "$platform" = "bcm53xx" ]; then # mtd From 8dc6474d6cfc9c038eb5e10eb07e56f7bcb06024 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 29 Mar 2025 20:10:27 +0800 Subject: [PATCH 206/425] linux-6.12: bump to 6.12.21 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 65ba39ecc..f5952bc6c 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .20 -LINUX_KERNEL_HASH-6.12.20 = 230e89b07b0ab82e74f07ecc1bee3105dca81d0ef4a97f900929c407249b6ac7 +LINUX_VERSION-6.12 = .21 +LINUX_KERNEL_HASH-6.12.21 = 9d1ae39a2ea024d99646f645fdbbbfa4545577132ba2643e01df75e32246d6c7 From 400af6976df113d565b3b4a534043172f27a17fe Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 1 Apr 2025 20:48:20 +0800 Subject: [PATCH 207/425] natmap: disable syslogs by default Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index a78ae4ab8..987fa0c51 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -57,6 +57,7 @@ curl -s $mirror/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc- curl -s $mirror/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch | patch -p1 # natmap +sed -i 's/log_stdout:bool:1/log_stdout:bool:0/g;s/log_stderr:bool:1/log_stderr:bool:0/g' feeds/packages/net/natmap/files/natmap.init pushd feeds/luci curl -s $mirror/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch | patch -p1 popd From 5eb30940e5a967e8b41737367543beac93414a91 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 2 Apr 2025 18:02:06 +0800 Subject: [PATCH 208/425] dev: mbedtls: upstream has fixed the build Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 09b41be89..8bc50031f 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -46,7 +46,7 @@ fi # fix gcc-15 if [ "$USE_GCC15" = y ]; then # Mbedtls - curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch > package/libs/mbedtls/patches/901-tests-fix-string-initialization-error-on-gcc15.patch + [ "$version" != "dev" ] && curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch > package/libs/mbedtls/patches/901-tests-fix-string-initialization-error-on-gcc15.patch sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile # elfutils curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch From f8c0b3704a7c21e4448f8d111fd9c936bc4977dd Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 2 Apr 2025 21:16:56 +0800 Subject: [PATCH 209/425] dockerd: make docker daemon to use cgroup v2 Signed-off-by: sbwml --- openwrt/24-config-common | 1 + openwrt/scripts/00-prepare_base.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 1d57f787b..99c20f97d 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -60,6 +60,7 @@ CONFIG_DOCKER_STO_BTRFS=y CONFIG_DOCKER_STO_EXT4=y CONFIG_PACKAGE_luci-app-dockerman=y CONFIG_PACKAGE_luci-lib-docker=y +# CONFIG_PACKAGE_cgroupfs-mount is not set ### Luci CONFIG_PACKAGE_luci=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 7d1d5d40a..fc378174f 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -223,13 +223,14 @@ git clone https://$github/sbwml/feeds_packages_net_curl feeds/packages/net/curl # Docker rm -rf feeds/luci/applications/luci-app-dockerman -git clone https://$gitea/sbwml/luci-app-dockerman -b openwrt-23.05 feeds/luci/applications/luci-app-dockerman +git clone https://$gitea/sbwml/luci-app-dockerman -b openwrt-24.10 feeds/luci/applications/luci-app-dockerman if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} git clone https://$github/sbwml/packages_utils_docker feeds/packages/utils/docker git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd git clone https://$github/sbwml/packages_utils_containerd feeds/packages/utils/containerd git clone https://$github/sbwml/packages_utils_runc feeds/packages/utils/runc + sed -i '/cgroupfs-mount/d' feeds/packages/utils/dockerd/Config.in fi sed -i '/sysctl.d/d' feeds/packages/utils/dockerd/Makefile pushd feeds/packages From 440855ac503c9544d49004c0cf0e2d906698af6f Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Apr 2025 00:41:52 +0800 Subject: [PATCH 210/425] mac80211: update to 6.14 & mt76: update to 2025-03-19 Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 6 ++-- ...ix-build-with-mac80211-6.14-backport.patch | 34 +++++++++++++++++++ openwrt/scripts/01-prepare_base-mainline.sh | 5 +-- 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index ca7fe6c15..490f99e5b 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2025-02-14 -PKG_SOURCE_VERSION:=e5fef138524e63314cb96ff8314048d175294e95 -PKG_MIRROR_HASH:=4d6ea8669b3034c97f5b341a5473facf4fe21262a2fde71257b57c4d1c86be5e +PKG_SOURCE_DATE:=2025-03-19 +PKG_SOURCE_VERSION:=d5cddf65f7a783969fe4163b4643b144fa672b77 +PKG_MIRROR_HASH:=9af902d27595ddb1d96db156975cf31378ea8434cfac77e3b48f5f31c6eb146a PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 diff --git a/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch b/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch new file mode 100644 index 000000000..162fab1df --- /dev/null +++ b/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch @@ -0,0 +1,34 @@ +--- a/mac80211.c ++++ b/mac80211.c +@@ -1702,7 +1702,7 @@ s8 mt76_get_power_bound(struct mt76_phy + EXPORT_SYMBOL_GPL(mt76_get_power_bound); + + int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- int *dbm) ++ unsigned int link_id, int *dbm) + { + struct mt76_phy *phy = mt76_vif_phy(hw, vif); + int n_chains, delta; +--- a/mt76.h ++++ b/mt76.h +@@ -1496,7 +1496,7 @@ int mt76_get_min_avg_rssi(struct mt76_de + s8 mt76_get_power_bound(struct mt76_phy *phy, s8 txpower); + + int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- int *dbm); ++ unsigned int link_id, int *dbm); + int mt76_init_sar_power(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar); + int mt76_get_sar_power(struct mt76_phy *phy, +--- a/mt7996/main.c ++++ b/mt7996/main.c +@@ -664,7 +664,8 @@ static void mt7996_configure_filter(stru + } + + static int +-mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) ++mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ unsigned int link_id, int *dbm) + { + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 66c4e86ee..6872900f6 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -181,17 +181,18 @@ mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile curl -s $mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch +curl -s $mirror/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch > package/kernel/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - 6.12 +# mac80211 - 6.14 rm -rf package/kernel/mac80211 git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 # ath10k-ct rm -rf package/kernel/ath10k-ct -git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.11 +git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.14 # kernel patch # btf: silence btf module warning messages From e6ad375bb707b72bf21ade0478468305572a3ffd Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 7 Apr 2025 21:33:00 +0800 Subject: [PATCH 211/425] linux-6.12: bump to 6.12.22 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index f5952bc6c..0709678be 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .21 -LINUX_KERNEL_HASH-6.12.21 = 9d1ae39a2ea024d99646f645fdbbbfa4545577132ba2643e01df75e32246d6c7 +LINUX_VERSION-6.12 = .22 +LINUX_KERNEL_HASH-6.12.22 = ab48800ab49985a78d2318ae8ac5f28fd3e123ea17357ef21498105a53337336 From f790c988c61b5e7956e4203cb8524aea338bae09 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Apr 2025 23:55:36 +0800 Subject: [PATCH 212/425] linux-6.12: bump to 6.12.23 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 0709678be..10e007620 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .22 -LINUX_KERNEL_HASH-6.12.22 = ab48800ab49985a78d2318ae8ac5f28fd3e123ea17357ef21498105a53337336 +LINUX_VERSION-6.12 = .23 +LINUX_KERNEL_HASH-6.12.23 = d8d95404f8deeb7ff6992c0df855025062e9e8182bca6daa27ef2e9275d27749 From 88bd36cb1427bdc46bb70962e0051bc8651b75c9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 14 Apr 2025 20:35:44 +0800 Subject: [PATCH 213/425] OpenWrt 24.10.1 Signed-off-by: sbwml --- ...string-initialization-error-on-gcc15.patch | 28 ------------------- openwrt/scripts/05-fix-source.sh | 2 -- tags/v24 | 2 +- 3 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch diff --git a/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch b/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch deleted file mode 100644 index a9baa9757..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 174eb9e201f84530d22c98c21e0c6a9d8d86dfac Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 17 Jul 2024 17:18:48 +0800 -Subject: [PATCH] tests fix string initialization error on gcc15 - -Increase the size of the unsigned char ciphertext array from 32 to 34 to accommodate the full string and the null terminator, thereby fixing the initializer-string for array error in psa_exercise_key.c. - -Signed-off-by: sbwml ---- - tests/src/psa_exercise_key.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c -index 7105324..c1751d7 100644 ---- a/tests/src/psa_exercise_key.c -+++ b/tests/src/psa_exercise_key.c -@@ -150,7 +150,7 @@ static int exercise_cipher_key(mbedtls_svc_key_id_t key, - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_key_type_t key_type; - const unsigned char plaintext[16] = "Hello, world..."; -- unsigned char ciphertext[32] = "(wabblewebblewibblewobblewubble)"; -+ unsigned char ciphertext[34] = "(wabblewebblewibblewobblewubble)"; - size_t ciphertext_length = sizeof(ciphertext); - unsigned char decrypted[sizeof(ciphertext)]; - size_t part_length; --- -2.43.5 - diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 8bc50031f..ba1f62c24 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -45,8 +45,6 @@ fi # fix gcc-15 if [ "$USE_GCC15" = y ]; then - # Mbedtls - [ "$version" != "dev" ] && curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/mbedtls/901-tests-fix-string-initialization-error-on-gcc15.patch > package/libs/mbedtls/patches/901-tests-fix-string-initialization-error-on-gcc15.patch sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile # elfutils curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch diff --git a/tags/v24 b/tags/v24 index 21651351e..169a8dd89 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.0 +24.10.1 From 86c90c1c81928fdf71e1f68c1075c03149c98a85 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 20 Apr 2025 00:56:21 +0800 Subject: [PATCH 214/425] x86: add RTL8127 PCI 10 gigabit ethernet driver Signed-off-by: sbwml --- openwrt/24-config-musl-x86 | 1 + openwrt/scripts/00-prepare_base.sh | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/openwrt/24-config-musl-x86 b/openwrt/24-config-musl-x86 index f9c01bd0e..7e25ae389 100644 --- a/openwrt/24-config-musl-x86 +++ b/openwrt/24-config-musl-x86 @@ -35,6 +35,7 @@ CONFIG_PACKAGE_kmod-ngbe=y CONFIG_PACKAGE_kmod-r8101=y CONFIG_PACKAGE_kmod-r8125=y CONFIG_PACKAGE_kmod-r8126=y +CONFIG_PACKAGE_kmod-r8127=y CONFIG_PACKAGE_kmod-r8168=y CONFIG_PACKAGE_kmod-txgbe=y # CONFIG_PACKAGE_kmod-r8169 is not set diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index fc378174f..8420cb83b 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -49,13 +49,14 @@ if [ "$ENABLE_UHTTPD" != "y" ]; then fi fi -# Realtek driver - R8168 & R8125 & R8126 & R8152 & R8101 -rm -rf package/kernel/r8168 package/kernel/r8101 package/kernel/r8125 package/kernel/r8126 +# Realtek driver - R8168 & R8125 & R8126 & R8152 & R8101 & r8127 +rm -rf package/kernel/{r8168,r8101,r8125,r8126,r8127} git clone https://$github/sbwml/package_kernel_r8168 package/kernel/r8168 git clone https://$github/sbwml/package_kernel_r8152 package/kernel/r8152 git clone https://$github/sbwml/package_kernel_r8101 package/kernel/r8101 git clone https://$github/sbwml/package_kernel_r8125 package/kernel/r8125 git clone https://$github/sbwml/package_kernel_r8126 package/kernel/r8126 +git clone https://$github/sbwml/package_kernel_r8127 package/kernel/r8127 # GCC Optimization level -O3 if [ "$platform" = "x86_64" ]; then From e0bf91fe7f41c662daeae15272ab5eb3dbaeb6ac Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 20 Apr 2025 20:58:43 +0800 Subject: [PATCH 215/425] linux-6.12: bump to 6.12.24 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 10e007620..becb518be 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .23 -LINUX_KERNEL_HASH-6.12.23 = d8d95404f8deeb7ff6992c0df855025062e9e8182bca6daa27ef2e9275d27749 +LINUX_VERSION-6.12 = .24 +LINUX_KERNEL_HASH-6.12.24 = 643142c1b5991560dd12f950825cc19e4497b95b82641918ecff1177f4130c1d From 45b67744a5774e35f8a6a657b44195e0fe45793c Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Apr 2025 23:08:09 +0800 Subject: [PATCH 216/425] linux-6.12: bump to 6.12.25 Signed-off-by: sbwml --- openwrt/24-config-common | 1 + openwrt/scripts/02-prepare_package.sh | 3 +++ tags/kernel-6.12 | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 99c20f97d..88babd8fa 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -257,6 +257,7 @@ CONFIG_PACKAGE_lrzsz=y CONFIG_PACKAGE_lsblk=y CONFIG_PACKAGE_lscpu=y CONFIG_PACKAGE_lsof=y +# CONFIG_PACKAGE_nethogs is not set CONFIG_PACKAGE_openssh-sftp-server=y CONFIG_PACKAGE_pciutils=y CONFIG_PACKAGE_qrencode=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 987fa0c51..4afbb5a44 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -101,6 +101,9 @@ git clone https://$github/sbwml/luci-app-airconnect package/new/airconnect # netkit-ftp git clone https://$github/sbwml/package_new_ftp package/new/ftp +# nethogs +git clone https://github.com/sbwml/package_new_nethogs package/new/nethogs + # SSRP & Passwall rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index becb518be..d31c9b412 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .24 -LINUX_KERNEL_HASH-6.12.24 = 643142c1b5991560dd12f950825cc19e4497b95b82641918ecff1177f4130c1d +LINUX_VERSION-6.12 = .25 +LINUX_KERNEL_HASH-6.12.25 = c8af780f6f613ca24622116e4c512a764335ab66e75c6643003c16e49a8e3b90 From fc36000589b1c33b03fe9c8a92c0ed27120aa14e Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 3 May 2025 06:24:32 +0800 Subject: [PATCH 217/425] linux-6.12: bump to 6.12.26 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index d31c9b412..359010b11 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .25 -LINUX_KERNEL_HASH-6.12.25 = c8af780f6f613ca24622116e4c512a764335ab66e75c6643003c16e49a8e3b90 +LINUX_VERSION-6.12 = .26 +LINUX_KERNEL_HASH-6.12.26 = 402de222c7425893c38102ddd53d2b602c74c2eabcf6631bb0791089c05e3bca From 707c8f31acde5db647ac40817c8cd84f7b1430e1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 3 May 2025 06:26:11 +0800 Subject: [PATCH 218/425] toolchain: gcc: update GCC 15 to 15.1.0 Signed-off-by: sbwml --- ...toolchain-gcc-add-support-for-GCC-15.patch | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch index 3e4cdc387..ba3e90fae 100644 --- a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -7,7 +7,7 @@ Signed-off-by: sbwml --- toolchain/gcc/Config.in | 3 + toolchain/gcc/Config.version | 5 + - toolchain/gcc/common.mk | 10 +- + toolchain/gcc/common.mk | 4 + .../patches-15.x/002-case_insensitive.patch | 24 +++ ...t-choke-when-building-32bit-on-64bit.patch | 13 ++ .../gcc/patches-15.x/010-documentation.patch | 35 +++++ @@ -25,7 +25,7 @@ Signed-off-by: sbwml .../920-specs_nonfatal_getenv.patch | 22 +++ ...mpilation-when-making-cross-compiler.patch | 67 ++++++++ .../970-macos_arm64-building-fix.patch | 45 ++++++ - 20 files changed, 615 insertions(+), 1 deletion(-) + 20 files changed, 610 insertions(+) create mode 100644 toolchain/gcc/patches-15.x/002-case_insensitive.patch create mode 100644 toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch create mode 100644 toolchain/gcc/patches-15.x/010-documentation.patch @@ -59,7 +59,7 @@ index b306040..3ab16a8 100644 config GCC_USE_GRAPHITE diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version -index 49bb368..be06df2 100644 +index 49bb368..9ecca5d 100644 --- a/toolchain/gcc/Config.version +++ b/toolchain/gcc/Config.version @@ -10,12 +10,17 @@ config GCC_VERSION_14 @@ -76,33 +76,20 @@ index 49bb368..be06df2 100644 default "11.3.0" if GCC_VERSION_11 default "12.3.0" if GCC_VERSION_12 default "14.2.0" if GCC_VERSION_14 -+ default "15.0.1" if GCC_VERSION_15 ++ default "15.1.0" if GCC_VERSION_15 default "13.3.0" config GCC_USE_DEFAULT_VERSION diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index 0ccf55b..50e924f 100644 +index 0ccf55b..1dd644f 100644 --- a/toolchain/gcc/common.mk +++ b/toolchain/gcc/common.mk -@@ -26,7 +26,11 @@ PKG_VERSION:=$(firstword $(subst +, ,$(GCC_VERSION))) - GCC_MAJOR_VERSION:=$(word 1,$(subst ., ,$(PKG_VERSION))) - GCC_DIR:=$(PKG_NAME)-$(PKG_VERSION) - --PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) -+ifeq ($(PKG_VERSION),15.0.1) -+ PKG_SOURCE_URL:=https://us.cooluc.com/gcc/20250209 -+else -+ PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION) -+endif - PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz - PKG_CPE_ID:=cpe:/a:gnu:gcc - -@@ -46,6 +50,10 @@ ifeq ($(PKG_VERSION),14.2.0) +@@ -46,6 +46,10 @@ ifeq ($(PKG_VERSION),14.2.0) PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 endif -+ifeq ($(PKG_VERSION),15.0.1) -+ PKG_HASH:=fe13d340157821fb8d04193664d420a4f15de0f6f562415c0869fc371421d933 ++ifeq ($(PKG_VERSION),15.1.0) ++ PKG_HASH:=e2b09ec21660f01fecffb715e0120265216943f038d0e48a9868713e54f06cea +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x @@ -159,7 +146,7 @@ index 0000000..c41f35e + are necessary to overlay a REAL_VALUE_TYPE on them. This could be diff --git a/toolchain/gcc/patches-15.x/010-documentation.patch b/toolchain/gcc/patches-15.x/010-documentation.patch new file mode 100644 -index 0000000..42b816d +index 0000000..b3f0e12 --- /dev/null +++ b/toolchain/gcc/patches-15.x/010-documentation.patch @@ -0,0 +1,35 @@ @@ -177,7 +164,7 @@ index 0000000..42b816d + +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in -+@@ -3566,18 +3566,10 @@ doc/gcc.info: $(TEXI_GCC_FILES) ++@@ -3747,18 +3747,10 @@ doc/gcc.info: $(TEXI_GCC_FILES) + doc/gccint.info: $(TEXI_GCCINT_FILES) + doc/cppinternals.info: $(TEXI_CPPINT_FILES) + @@ -200,13 +187,13 @@ index 0000000..42b816d + doc/gcc.dvi: $(TEXI_GCC_FILES) diff --git a/toolchain/gcc/patches-15.x/230-musl_libssp.patch b/toolchain/gcc/patches-15.x/230-musl_libssp.patch new file mode 100644 -index 0000000..f8dc944 +index 0000000..34eaac4 --- /dev/null +++ b/toolchain/gcc/patches-15.x/230-musl_libssp.patch @@ -0,0 +1,13 @@ +--- a/gcc/gcc.cc ++++ b/gcc/gcc.cc -+@@ -989,7 +989,9 @@ proper position among the other output f ++@@ -992,7 +992,9 @@ proper position among the other output f + #endif + + #ifndef LINK_SSP_SPEC @@ -219,7 +206,7 @@ index 0000000..f8dc944 + #else diff --git a/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch b/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch new file mode 100644 -index 0000000..4e32b75 +index 0000000..27b9657 --- /dev/null +++ b/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch @@ -0,0 +1,21 @@ @@ -235,7 +222,7 @@ index 0000000..4e32b75 + +--- a/gcc/config/mips/mips.cc ++++ b/gcc/config/mips/mips.cc -+@@ -20576,7 +20576,7 @@ mips_option_override (void) ++@@ -20599,7 +20599,7 @@ mips_option_override (void) + flag_pcc_struct_return = 0; + + /* Decide which rtx_costs structure to use. */ @@ -285,7 +272,7 @@ index 0000000..5c9d86a + #define LINUX_TARGET_LINK_SPEC "%{h*} \ diff --git a/toolchain/gcc/patches-15.x/820-libgcc_pic.patch b/toolchain/gcc/patches-15.x/820-libgcc_pic.patch new file mode 100644 -index 0000000..33ae0a9 +index 0000000..f9691e5 --- /dev/null +++ b/toolchain/gcc/patches-15.x/820-libgcc_pic.patch @@ -0,0 +1,44 @@ @@ -322,7 +309,7 @@ index 0000000..33ae0a9 + ifneq ($(LIBUNWIND),) + all: libunwind$(SHLIB_EXT) + libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_EXT) -+@@ -1178,6 +1179,10 @@ install-shared: ++@@ -1181,6 +1182,10 @@ install-shared: + chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a + $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a + @@ -506,7 +493,7 @@ index 0000000..b355545 ++CRTSTUFF_T_CFLAGS_S += -mno-mips16 diff --git a/toolchain/gcc/patches-15.x/910-mbsd_multi.patch b/toolchain/gcc/patches-15.x/910-mbsd_multi.patch new file mode 100644 -index 0000000..07afb52 +index 0000000..c5462e1 --- /dev/null +++ b/toolchain/gcc/patches-15.x/910-mbsd_multi.patch @@ -0,0 +1,146 @@ @@ -529,7 +516,7 @@ index 0000000..07afb52 + +--- a/gcc/c-family/c-opts.cc ++++ b/gcc/c-family/c-opts.cc -+@@ -110,6 +110,9 @@ static size_t include_cursor; ++@@ -109,6 +109,9 @@ static size_t include_cursor; + /* Whether any standard preincluded header has been preincluded. */ + static bool done_preinclude; + @@ -552,7 +539,7 @@ index 0000000..07afb52 + case OPT_fconstant_string_class_: + constant_string_class_name = arg; + break; -+@@ -1332,6 +1341,47 @@ c_common_init (void) ++@@ -1359,6 +1368,47 @@ c_common_init (void) + return false; + } + @@ -602,7 +589,7 @@ index 0000000..07afb52 + +--- a/gcc/c-family/c.opt ++++ b/gcc/c-family/c.opt -+@@ -1987,6 +1987,9 @@ C++ ObjC++ Optimization Alias(fexception ++@@ -2008,6 +2008,9 @@ C++ ObjC++ Optimization Alias(fexception + fhonor-std + C++ ObjC++ WarnRemoved + @@ -614,7 +601,7 @@ index 0000000..07afb52 + Assume normal C execution environment. +--- a/gcc/common.opt ++++ b/gcc/common.opt -+@@ -1908,6 +1908,9 @@ Enum(hardcfr_check_noreturn_calls) Strin ++@@ -1938,6 +1938,9 @@ Enum(hardcfr_check_noreturn_calls) Strin + EnumValue + Enum(hardcfr_check_noreturn_calls) String(always) Value(HCFRNR_ALWAYS) + @@ -626,7 +613,7 @@ index 0000000..07afb52 + ; On SVR4 targets, it also controls whether or not to emit a +--- a/gcc/doc/invoke.texi ++++ b/gcc/doc/invoke.texi -+@@ -10690,6 +10690,17 @@ This option is only supported for C and ++@@ -10897,6 +10897,17 @@ This option is only supported for C and + + This warning is upgraded to an error by @option{-pedantic-errors}. + @@ -646,7 +633,7 @@ index 0000000..07afb52 + @item -Wstack-protector +--- a/gcc/opts.cc ++++ b/gcc/opts.cc -+@@ -2848,6 +2848,9 @@ common_handle_option (struct gcc_options ++@@ -2867,6 +2867,9 @@ common_handle_option (struct gcc_options + add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg); + break; + @@ -658,7 +645,7 @@ index 0000000..07afb52 + break; diff --git a/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch new file mode 100644 -index 0000000..5c9849f +index 0000000..01591d2 --- /dev/null +++ b/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch @@ -0,0 +1,22 @@ @@ -671,7 +658,7 @@ index 0000000..5c9849f + +--- a/gcc/gcc.cc ++++ b/gcc/gcc.cc -+@@ -10339,8 +10339,10 @@ getenv_spec_function (int argc, const ch ++@@ -10357,8 +10357,10 @@ getenv_spec_function (int argc, const ch + } + + if (!value) @@ -759,7 +746,7 @@ index 0000000..b1d7576 + cmdsrcdir = $(libgosrcdir)/cmd diff --git a/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch b/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch new file mode 100644 -index 0000000..a4060d9 +index 0000000..cf0fd74 --- /dev/null +++ b/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch @@ -0,0 +1,45 @@ @@ -782,7 +769,7 @@ index 0000000..a4060d9 + +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h -+@@ -1412,7 +1412,7 @@ extern enum aarch64_code_model aarch64_c ++@@ -1469,7 +1469,7 @@ extern enum aarch64_code_model aarch64_c + + /* Extra specs when building a native AArch64-hosted compiler. + Option rewriting rules based on host system. */ From c025e39c6f094e45ebdc342db8f7e5eccd6dc717 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 5 May 2025 22:01:24 +0800 Subject: [PATCH 219/425] linux-6.12: bump to 6.12.27 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 359010b11..f17e5a141 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .26 -LINUX_KERNEL_HASH-6.12.26 = 402de222c7425893c38102ddd53d2b602c74c2eabcf6631bb0791089c05e3bca +LINUX_VERSION-6.12 = .27 +LINUX_KERNEL_HASH-6.12.27 = 8f4655a4cc7f93d72f515bbca54756de26ddaf5949790da6a17f766e3c33dc79 From f40459d74c799ae6f843ed347746045cbd1c04b1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 5 May 2025 22:01:45 +0800 Subject: [PATCH 220/425] linux-6.12: zram: fix lz4 & zstd compression algorithm Signed-off-by: sbwml --- openwrt/24-config-common | 4 +--- openwrt/24-config-minimal-common | 4 +--- openwrt/patch/openwrt-6.x/modules/other.mk | 9 +++++++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 88babd8fa..e16bd7246 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -30,9 +30,7 @@ CONFIG_PACKAGE_kmod-shortcut-fe-cm=y ### Zram CONFIG_PACKAGE_zram-swap=y -CONFIG_PACKAGE_kmod-lib-lz4=y -CONFIG_PACKAGE_kmod-lib-lzo=y -CONFIG_PACKAGE_kmod-lib-zstd=y +CONFIG_ZRAM_DEF_COMP_LZ4=y ### Busybox CONFIG_BUSYBOX_CUSTOM=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index f7a4a12a7..7446f26be 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -31,9 +31,7 @@ CONFIG_PACKAGE_kmod-shortcut-fe-cm=y ### Zram CONFIG_PACKAGE_zram-swap=y -CONFIG_PACKAGE_kmod-lib-lz4=y -CONFIG_PACKAGE_kmod-lib-lzo=y -CONFIG_PACKAGE_kmod-lib-zstd=y +CONFIG_ZRAM_DEF_COMP_LZ4=y ### Busybox CONFIG_BUSYBOX_CUSTOM=y diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index 75ca9e483..d02eb6e37 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -802,13 +802,18 @@ $(eval $(call KernelPackage,ikconfig)) define KernelPackage/zram SUBMENU:=$(OTHER_MENU) TITLE:=ZRAM - DEPENDS:=+LINUX_6_12:kmod-lib-lzo + DEPENDS:=+LINUX_6_12:kmod-lib-lzo +LINUX_6_12:kmod-lib-lz4 \ + +LINUX_6_12:kmod-lib-lz4hc +LINUX_6_12:kmod-lib-zstd KCONFIG:= \ CONFIG_ZSMALLOC \ CONFIG_ZRAM \ CONFIG_ZRAM_DEBUG=n \ CONFIG_ZRAM_WRITEBACK=n \ - CONFIG_ZSMALLOC_STAT=n + CONFIG_ZSMALLOC_STAT=n \ + CONFIG_ZRAM_BACKEND_LZ4=y \ + CONFIG_ZRAM_BACKEND_LZ4HC=y \ + CONFIG_ZRAM_BACKEND_LZO=y \ + CONFIG_ZRAM_BACKEND_ZSTD=y FILES:= \ $(LINUX_DIR)/mm/zsmalloc.ko \ $(LINUX_DIR)/drivers/block/zram/zram.ko From 2d2b624c8e15c57869f3d2412ada9aeabb0d8a91 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 5 May 2025 22:29:35 +0800 Subject: [PATCH 221/425] luci-base: add ucitrack for zram Signed-off-by: sbwml --- ...add-ucitrack-luci-mod-system-zram.js.patch | 24 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 1 + 2 files changed, 25 insertions(+) create mode 100644 openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch diff --git a/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch b/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch new file mode 100644 index 000000000..430f9b98f --- /dev/null +++ b/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch @@ -0,0 +1,24 @@ +From 433eec85db3ec6ca6185eb077ff694ba9b9db2d8 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Mon, 5 May 2025 22:24:52 +0800 +Subject: [PATCH] luci-mod-system: add ucitrack luci-mod-system-zram.json + +Signed-off-by: sbwml +--- + .../root/usr/share/ucitrack/luci-mod-system-zram.json | 4 ++++ + 1 file changed, 4 insertions(+) + create mode 100644 modules/luci-mod-system/root/usr/share/ucitrack/luci-mod-system-zram.json + +diff --git a/modules/luci-mod-system/root/usr/share/ucitrack/luci-mod-system-zram.json b/modules/luci-mod-system/root/usr/share/ucitrack/luci-mod-system-zram.json +new file mode 100644 +index 0000000..56da09e +--- /dev/null ++++ b/modules/luci-mod-system/root/usr/share/ucitrack/luci-mod-system-zram.json +@@ -0,0 +1,4 @@ ++{ ++ "config": "system", ++ "init": "zram" ++} +-- +2.36.0 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 8420cb83b..e90605499 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -307,6 +307,7 @@ pushd feeds/luci curl -s $mirror/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch | patch -p1 curl -s $mirror/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch | patch -p1 curl -s $mirror/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch | patch -p1 + curl -s $mirror/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch | patch -p1 popd # Luci diagnostics.js From f36a1f80dab06d8747818777e6d7aa0bbb8ad958 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 10 May 2025 12:05:21 +0800 Subject: [PATCH 222/425] linux-6.12: bump to 6.12.28 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index f17e5a141..70a35aa2a 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .27 -LINUX_KERNEL_HASH-6.12.27 = 8f4655a4cc7f93d72f515bbca54756de26ddaf5949790da6a17f766e3c33dc79 +LINUX_VERSION-6.12 = .28 +LINUX_KERNEL_HASH-6.12.28 = e8a099182562aecff781de72ce769461e706d97af42d740dff20eb450dd5771e From 05eabe405ca4465a4ce483ab21c4687dc9a9001b Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 19 May 2025 07:53:44 +0800 Subject: [PATCH 223/425] linux-6.12: bump to 6.12.29 Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/x86/config-6.12 | 1 + tags/kernel-6.12 | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.12 b/openwrt/patch/openwrt-6.x/x86/config-6.12 index 76af18e88..28ea5b3c4 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.12 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.12 @@ -258,6 +258,7 @@ CONFIG_M686=y CONFIG_MICROCODE_LATE_LOADING=y CONFIG_MICROCODE=y CONFIG_MIGRATION=y +CONFIG_MITIGATION_ITS=y # CONFIG_MITIGATION_GDS_FORCE is not set # CONFIG_MITIGATION_IBPB_ENTRY is not set # CONFIG_MITIGATION_IBRS_ENTRY is not set diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 70a35aa2a..19f5f7f47 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .28 -LINUX_KERNEL_HASH-6.12.28 = e8a099182562aecff781de72ce769461e706d97af42d740dff20eb450dd5771e +LINUX_VERSION-6.12 = .29 +LINUX_KERNEL_HASH-6.12.29 = e8b2ec7e2338ccb9c86de7154f6edcaadfce80907493c143e85a82776bb5064d From 38c04e35e9f25f06647b76122e5d3e083c162a89 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 27 May 2025 11:10:00 +0800 Subject: [PATCH 224/425] linux-6.12: bump to 6.12.30 Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/usb.mk | 15 ++++++++++++ .../0002-fix-kernel-6.12-builds.patch | 24 ------------------- openwrt/scripts/02-prepare_package.sh | 5 +--- openwrt/scripts/04-fix_kmod.sh | 10 ++++---- tags/kernel-6.12 | 4 ++-- 5 files changed, 23 insertions(+), 35 deletions(-) delete mode 100644 openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index 8f934800f..aea2228a2 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -1034,6 +1034,21 @@ endef $(eval $(call KernelPackage,usb-serial-qualcomm)) +define KernelPackage/usb-serial-xr + TITLE:=Support for MaxLinear/Exar USB to Serial devices + KCONFIG:=CONFIG_USB_SERIAL_XR + FILES:=$(LINUX_DIR)/drivers/usb/serial/xr_serial.ko + AUTOLOAD:=$(call AutoProbe,xr_serial) + $(call AddDepends/usb-serial) +endef + +define KernelPackage/usb-serial-xr/description + Kernel support for MaxLinear/Exar USB to Serial converter devices +endef + +$(eval $(call KernelPackage,usb-serial-xr)) + + define KernelPackage/usb-storage TITLE:=USB Storage support DEPENDS:= +kmod-scsi-core diff --git a/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch b/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch deleted file mode 100644 index 20553406e..000000000 --- a/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/xr_usb_serial_common-1a/xr_usb_serial_common.c b/xr_usb_serial_common-1a/xr_usb_serial_common.c -index 74bfa93..a948305 100644 ---- a/xr_usb_serial_common-1a/xr_usb_serial_common.c -+++ b/xr_usb_serial_common-1a/xr_usb_serial_common.c -@@ -35,6 +35,7 @@ - #undef VERBOSE_DEBUG - - #include -+#include - #include - #include - #include -@@ -48,7 +49,11 @@ - #include - #include - #include -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) -+#include -+#else - #include -+#endif - #include - #include "linux/version.h" - diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 4afbb5a44..e320ae2f3 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -65,9 +65,6 @@ popd # samba4 - bump version rm -rf feeds/packages/net/samba4 git clone https://$github/sbwml/feeds_packages_net_samba4 feeds/packages/net/samba4 -# liburing - 2.7 (samba-4.21.0) -rm -rf feeds/packages/libs/liburing -git clone https://$github/sbwml/feeds_packages_libs_liburing feeds/packages/libs/liburing # enable multi-channel sed -i '/workgroup/a \\n\t## enable multi-channel' feeds/packages/net/samba4/files/smb.conf.template sed -i '/enable multi-channel/a \\tserver multi channel support = yes' feeds/packages/net/samba4/files/smb.conf.template @@ -139,7 +136,7 @@ sed -i 's/services/network/g' feeds/luci/applications/luci-app-nlbwmon/root/usr/ sed -i 's/services/network/g' feeds/luci/applications/luci-app-nlbwmon/htdocs/luci-static/resources/view/nlbw/config.js # mentohust -git clone https://github.com/sbwml/luci-app-mentohust package/new/mentohust +git clone https://$github/sbwml/luci-app-mentohust package/new/mentohust # custom packages rm -rf feeds/packages/utils/coremark diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index d0a2f79bf..23102094d 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -43,11 +43,11 @@ curl -s $mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5 mkdir -p package/kernel/ubootenv-nvram/patches curl -s $mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.12.patch -# packages -pushd feeds/packages - # xr_usb_serial_common linux-6.12 - curl -s $mirror/openwrt/patch/packages-patches/xr_usb_serial_common/0002-fix-kernel-6.12-builds.patch > libs/xr_usb_serial_common/patches/0002-fix-kernel-6.12-builds.patch -popd +# usb-serial-xr_usb_serial_common: remove package +# Now that we have packaged the upstream driver[1] and only board[2] that +# includes it by default has been switched to it, remove this out-of-tree +# driver that is broken on 6.12 anyway. +rm -rf feeds/packages/libs/xr_usb_serial_common # xtables-addons curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 19f5f7f47..3f710bc5e 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .29 -LINUX_KERNEL_HASH-6.12.29 = e8b2ec7e2338ccb9c86de7154f6edcaadfce80907493c143e85a82776bb5064d +LINUX_VERSION-6.12 = .30 +LINUX_KERNEL_HASH-6.12.30 = df046a48971e40ce0b2e003e7e55b6b1e7da2912120eb216d5d6c8450c9cf82e From c657436f94874aafdfc27d97e92a695137c08aa6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 27 May 2025 21:26:49 +0800 Subject: [PATCH 225/425] luci-app-sqm: switch luci source Signed-off-by: sbwml --- openwrt/patch/sqm/001-help-translation.patch | 48 -------------------- openwrt/scripts/02-prepare_package.sh | 6 +-- 2 files changed, 3 insertions(+), 51 deletions(-) delete mode 100644 openwrt/patch/sqm/001-help-translation.patch diff --git a/openwrt/patch/sqm/001-help-translation.patch b/openwrt/patch/sqm/001-help-translation.patch deleted file mode 100644 index e051dfba8..000000000 --- a/openwrt/patch/sqm/001-help-translation.patch +++ /dev/null @@ -1,48 +0,0 @@ -diff --git a/src/layer_cake.qos.help b/src/layer_cake.qos.help -index 1cab3ed..c75bf8a 100644 ---- a/src/layer_cake.qos.help -+++ b/src/layer_cake.qos.help -@@ -1,4 +1,4 @@ --This uses the cake qdisc as a replacement for both htb as shaper and fq_codel as leaf qdisc. --This exercises cake's diffserv profile(s) as different "layers" of priority. --This script requires that cake is selected as qdisc, and forces its usage. --See: http://www.bufferbloat.net/projects/codel/wiki/Cake for more information -+这个 cake 列队规则使用 HTB 作为过滤器,使用 fq_codel 作为叶列队规则。 -+这个 cake 规则将不同的文件分为不同的“层次”优先级。 -+该脚本需要将该 cake 选为列队规则。 -+请参阅:http://www.bufferbloat.net/projects/codel/wiki/Cake 获取更多信息 -diff --git a/src/piece_of_cake.qos.help b/src/piece_of_cake.qos.help -index b95e9be..8bb0d31 100644 ---- a/src/piece_of_cake.qos.help -+++ b/src/piece_of_cake.qos.help -@@ -1,4 +1,4 @@ --This just uses the cake qdisc as a replacement for both htb as shaper and fq_codel as leaf qdisc. --It just does not come any simpler than this, in other words it truely is a "piece of cake". --This script requires that cake is selected as qdisc, and forces its usage. --See: http://www.bufferbloat.net/projects/codel/wiki/Cake for more information -+这个 cake 列队规则使用 HTB 作为过滤器,使用 fq_codel 作为叶列队规则。 -+它不会比这更简单,换句话说,它真的是“小菜一碟”。 -+该脚本需要将 cake 选为列队规则。 -+请参阅:http://www.bufferbloat.net/projects/codel/wiki/Cake 获取更多信息 -diff --git a/src/simple.qos.help b/src/simple.qos.help -index b3c0096..94a146a 100644 ---- a/src/simple.qos.help -+++ b/src/simple.qos.help -@@ -1 +1 @@ --BW-limited three-tier prioritisation scheme with your qdisc on each queue. (default) -+使用 fq_codel 列队规则在每个列队上进行三层优先级的带宽控制。(默认) -diff --git a/src/simplest.qos.help b/src/simplest.qos.help -index c359256..8b37d9f 100644 ---- a/src/simplest.qos.help -+++ b/src/simplest.qos.help -@@ -1 +1 @@ --Simplest possible configuration: HTB rate limiter with your qdisc attached. -+最简单的配置:使用带有 HTB 过滤器的列队规则来进行速率限制。 -diff --git a/src/simplest_tbf.qos.help b/src/simplest_tbf.qos.help -index 3f93f89..f4936e2 100644 ---- a/src/simplest_tbf.qos.help -+++ b/src/simplest_tbf.qos.help -@@ -1,2 +1 @@ --Simplest possible configuration (TBF): TBF rate limiter with your qdisc attached. --TBF may give better performance than HTB on some architectures. -+最简单的配置(TBF):使用带有 TBF 过滤器的列队规则来进行速率限制。在某些架构上,TBF 可能会比 HTB 提供更好的性能。 diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index e320ae2f3..ec54057b0 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -159,9 +159,9 @@ sed -i 's,发送,Transmission,g' feeds/luci/applications/luci-app-transmission/p sed -i 's,frp 服务器,FRP 服务器,g' feeds/luci/applications/luci-app-frps/po/zh_Hans/frps.po sed -i 's,frp 客户端,FRP 客户端,g' feeds/luci/applications/luci-app-frpc/po/zh_Hans/frpc.po -# SQM Translation -mkdir -p feeds/packages/net/sqm-scripts/patches -curl -s $mirror/openwrt/patch/sqm/001-help-translation.patch > feeds/packages/net/sqm-scripts/patches/001-help-translation.patch +# luci-app-sqm +rm -rf feeds/luci/applications/luci-app-sqm +git clone https://$gitea/sbwml/luci-app-sqm feeds/luci/applications/luci-app-sqm # unzip rm -rf feeds/packages/utils/unzip From 414de20dcf97a06eaa5637a163cb34315d6f5b29 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 28 May 2025 14:01:23 +0800 Subject: [PATCH 226/425] sysctl.d: use `cake` queueing discipline Signed-off-by: sbwml --- openwrt/files/etc/sysctl.d/10-default.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openwrt/files/etc/sysctl.d/10-default.conf b/openwrt/files/etc/sysctl.d/10-default.conf index a4c998aad..627187d7c 100644 --- a/openwrt/files/etc/sysctl.d/10-default.conf +++ b/openwrt/files/etc/sysctl.d/10-default.conf @@ -11,6 +11,8 @@ fs.protected_symlinks=1 net.core.bpf_jit_enable=1 net.core.bpf_jit_kallsyms=1 +net.core.default_qdisc=cake + net.ipv4.conf.default.arp_ignore=1 net.ipv4.conf.all.arp_ignore=1 net.ipv4.ip_forward=1 From e9a51a3a70a1a35c04ba776801395626765c51d5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 28 May 2025 16:46:44 +0800 Subject: [PATCH 227/425] openssl: fix AEAD ciphers benchmark performance degradation Signed-off-by: sbwml --- ...s-IV-to-EVP_CipherInit_ex-for-evp-ru.patch | 22 + ...d.c-Fix-the-benchmarking-for-AEAD-ci.patch | 488 ++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 6 + 3 files changed, 516 insertions(+) create mode 100644 openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch create mode 100644 openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch diff --git a/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch b/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch new file mode 100644 index 000000000..ef9cbe8b3 --- /dev/null +++ b/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch @@ -0,0 +1,22 @@ +From 6cef85935b825ee477553594d36c9627df95a8c6 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 28 May 2025 14:49:44 +0800 +Subject: [PATCH 1/2] Revert "speed: Pass IV to EVP_CipherInit_ex for -evp runs + with non-AEAD ciphers" + +This reverts commit 4836c042d500da503b7f50db2aa65e0bfea1c451. +--- + apps/speed.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/apps/speed.c ++++ b/apps/speed.c +@@ -2378,7 +2378,7 @@ skip_hmac: + + if (!ae_mode) { + if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, +- loopargs[k].key, iv, -1)) { ++ loopargs[k].key, NULL, -1)) { + BIO_printf(bio_err, "\nFailed to set the key\n"); + ERR_print_errors(bio_err); + exit(1); diff --git a/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch b/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch new file mode 100644 index 000000000..699bd0667 --- /dev/null +++ b/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch @@ -0,0 +1,488 @@ +From 28dd8b02baa130d081ae279446f81487f1662907 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Wed, 28 May 2025 14:49:59 +0800 +Subject: [PATCH 2/2] Revert "apps/speed.c: Fix the benchmarking for AEAD + ciphers" + +This reverts commit 336b86f082c7d1041c1c35817024c94c77279437. +--- + apps/speed.c | 358 +++++++++++---------------------------------------- + 1 file changed, 72 insertions(+), 286 deletions(-) + +--- a/apps/speed.c ++++ b/apps/speed.c +@@ -456,14 +456,6 @@ static double sm2_results[SM2_NUM][2]; + #define COND(unused_cond) (run && count < INT_MAX) + #define COUNT(d) (count) + +-#define TAG_LEN 16 +- +-static unsigned int mode_op; /* AE Mode of operation */ +-static unsigned int aead = 0; /* AEAD flag */ +-static unsigned char aead_iv[12]; /* For AEAD modes */ +-static unsigned char aad[EVP_AEAD_TLS1_AAD_LEN] = { 0xcc }; +-static int aead_ivlen = sizeof(aead_iv); +- + typedef struct loopargs_st { + ASYNC_JOB *inprogress_job; + ASYNC_WAIT_CTX *wait_ctx; +@@ -472,7 +464,6 @@ typedef struct loopargs_st { + unsigned char *buf_malloc; + unsigned char *buf2_malloc; + unsigned char *key; +- unsigned char tag[TAG_LEN]; + size_t buflen; + size_t sigsize; + EVP_PKEY_CTX *rsa_sign_ctx[RSA_NUM]; +@@ -736,8 +727,12 @@ static int EVP_Update_loop(void *args) + unsigned char *buf = tempargs->buf; + EVP_CIPHER_CTX *ctx = tempargs->ctx; + int outl, count, rc; ++ unsigned char faketag[16] = { 0xcc }; + + if (decrypt) { ++ if (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) { ++ (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(faketag), faketag); ++ } + for (count = 0; COND(c[D_EVP][testnum]); count++) { + rc = EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); + if (rc != 1) { +@@ -762,159 +757,74 @@ static int EVP_Update_loop(void *args) + } + + /* +- * To make AEAD benchmarking more relevant perform TLS-like operations, +- * 13-byte AAD followed by payload. But don't use TLS-formatted AAD, as +- * payload length is not actually limited by 16KB... + * CCM does not support streaming. For the purpose of performance measurement, + * each message is encrypted using the same (key,iv)-pair. Do not use this + * code in your application. + */ +-static int EVP_Update_loop_aead_enc(void *args) ++static int EVP_Update_loop_ccm(void *args) + { + loopargs_t *tempargs = *(loopargs_t **) args; + unsigned char *buf = tempargs->buf; +- unsigned char *key = tempargs->key; + EVP_CIPHER_CTX *ctx = tempargs->ctx; +- int outl, count, realcount = 0; ++ int outl, count; ++ unsigned char tag[12]; + +- for (count = 0; COND(c[D_EVP][testnum]); count++) { +- /* Set length of iv (Doesn't apply to SIV mode) */ +- if (mode_op != EVP_CIPH_SIV_MODE) { +- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, +- aead_ivlen, NULL)) { +- BIO_printf(bio_err, "\nFailed to set iv length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- /* Set tag_len (Not for GCM/SIV at encryption stage) */ +- if (mode_op != EVP_CIPH_GCM_MODE +- && mode_op != EVP_CIPH_SIV_MODE) { +- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, +- TAG_LEN, NULL)) { +- BIO_printf(bio_err, "\nFailed to set tag length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, aead_iv, -1)) { +- BIO_printf(bio_err, "\nFailed to set key and iv\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- /* Set total length of input. Only required for CCM */ +- if (mode_op == EVP_CIPH_CCM_MODE) { +- if (!EVP_EncryptUpdate(ctx, NULL, &outl, +- NULL, lengths[testnum])) { +- BIO_printf(bio_err, "\nCouldn't set input text length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- if (aead) { +- if (!EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) { +- BIO_printf(bio_err, "\nCouldn't insert AAD when encrypting\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } ++ if (decrypt) { ++ for (count = 0; COND(c[D_EVP][testnum]); count++) { ++ (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(tag), ++ tag); ++ /* reset iv */ ++ (void)EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); ++ /* counter is reset on every update */ ++ (void)EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); + } +- if (!EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum])) { +- BIO_printf(bio_err, "\nFailed to encrypt the data\n"); +- ERR_print_errors(bio_err); +- exit(1); ++ } else { ++ for (count = 0; COND(c[D_EVP][testnum]); count++) { ++ /* restore iv length field */ ++ (void)EVP_EncryptUpdate(ctx, NULL, &outl, NULL, lengths[testnum]); ++ /* counter is reset on every update */ ++ (void)EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); + } +- if (EVP_EncryptFinal_ex(ctx, buf, &outl)) +- realcount++; + } +- return realcount; ++ if (decrypt) ++ (void)EVP_DecryptFinal_ex(ctx, buf, &outl); ++ else ++ (void)EVP_EncryptFinal_ex(ctx, buf, &outl); ++ return count; + } + + /* + * To make AEAD benchmarking more relevant perform TLS-like operations, + * 13-byte AAD followed by payload. But don't use TLS-formatted AAD, as + * payload length is not actually limited by 16KB... +- * CCM does not support streaming. For the purpose of performance measurement, +- * each message is decrypted using the same (key,iv)-pair. Do not use this +- * code in your application. +- * For decryption, we will use buf2 to preserve the input text in buf. + */ +-static int EVP_Update_loop_aead_dec(void *args) ++static int EVP_Update_loop_aead(void *args) + { + loopargs_t *tempargs = *(loopargs_t **) args; + unsigned char *buf = tempargs->buf; +- unsigned char *outbuf = tempargs->buf2; +- unsigned char *key = tempargs->key; +- unsigned char tag[TAG_LEN]; + EVP_CIPHER_CTX *ctx = tempargs->ctx; +- int outl, count, realcount = 0; +- +- for (count = 0; COND(c[D_EVP][testnum]); count++) { +- /* Set the length of iv (Doesn't apply to SIV mode) */ +- if (mode_op != EVP_CIPH_SIV_MODE) { +- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, +- aead_ivlen, NULL)) { +- BIO_printf(bio_err, "\nFailed to set iv length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } ++ int outl, count; ++ unsigned char aad[13] = { 0xcc }; ++ unsigned char faketag[16] = { 0xcc }; + +- /* Set the tag length (Doesn't apply to SIV mode) */ +- if (mode_op != EVP_CIPH_SIV_MODE +- && mode_op != EVP_CIPH_GCM_MODE) { +- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, +- TAG_LEN, NULL)) { +- BIO_printf(bio_err, "\nFailed to set tag length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, aead_iv, -1)) { +- BIO_printf(bio_err, "\nFailed to set key and iv\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- /* Set iv before decryption (Doesn't apply to SIV mode) */ +- if (mode_op != EVP_CIPH_SIV_MODE) { +- if (!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, aead_iv)) { +- BIO_printf(bio_err, "\nFailed to set iv\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- memcpy(tag, tempargs->tag, TAG_LEN); +- +- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, +- TAG_LEN, tag)) { +- BIO_printf(bio_err, "\nFailed to set tag\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- /* Set the total length of cipher text. Only required for CCM */ +- if (mode_op == EVP_CIPH_CCM_MODE) { +- if (!EVP_DecryptUpdate(ctx, NULL, &outl, +- NULL, lengths[testnum])) { +- BIO_printf(bio_err, "\nCouldn't set cipher text length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- if (aead) { +- if (!EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) { +- BIO_printf(bio_err, "\nCouldn't insert AAD when decrypting\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } ++ if (decrypt) { ++ for (count = 0; COND(c[D_EVP][testnum]); count++) { ++ (void)EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); ++ (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, ++ sizeof(faketag), faketag); ++ (void)EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); ++ (void)EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); ++ (void)EVP_DecryptFinal_ex(ctx, buf + outl, &outl); + } +- if (!EVP_DecryptUpdate(ctx, outbuf, &outl, buf, lengths[testnum])) { +- BIO_printf(bio_err, "\nFailed to decrypt the data\n"); +- ERR_print_errors(bio_err); +- exit(1); ++ } else { ++ for (count = 0; COND(c[D_EVP][testnum]); count++) { ++ (void)EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv); ++ (void)EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); ++ (void)EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); ++ (void)EVP_EncryptFinal_ex(ctx, buf + outl, &outl); + } +- if (EVP_DecryptFinal_ex(ctx, outbuf, &outl)) +- realcount++; + } +- return realcount; ++ return count; + } + + static long rsa_c[RSA_NUM][2]; /* # RSA iteration test */ +@@ -1460,11 +1370,11 @@ int speed_main(int argc, char **argv) + OPTION_CHOICE o; + int async_init = 0, multiblock = 0, pr_header = 0; + uint8_t doit[ALGOR_NUM] = { 0 }; +- int ret = 1, misalign = 0, lengths_single = 0; ++ int ret = 1, misalign = 0, lengths_single = 0, aead = 0; + long count = 0; + unsigned int size_num = SIZE_NUM; + unsigned int i, k, loopargs_len = 0, async_jobs = 0; +- int keylen = 0; ++ int keylen; + int buflen; + BIGNUM *bn = NULL; + EVP_PKEY_CTX *genctx = NULL; +@@ -2302,20 +2212,12 @@ skip_hmac: + } + } + +- /*- +- * There are three scenarios for D_EVP: +- * 1- Using authenticated encryption (AE) e.g. CCM, GCM, OCB etc. +- * 2- Using AE + associated data (AD) i.e. AEAD using CCM, GCM, OCB etc. +- * 3- Not using AE or AD e.g. ECB, CBC, CFB etc. +- */ + if (doit[D_EVP]) { + if (evp_cipher != NULL) { +- int (*loopfunc) (void *); +- int outlen = 0; +- unsigned int ae_mode = 0; ++ int (*loopfunc) (void *) = EVP_Update_loop; + +- if (multiblock && (EVP_CIPHER_get_flags(evp_cipher) +- & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) { ++ if (multiblock && (EVP_CIPHER_get_flags(evp_cipher) & ++ EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) { + multiblock_speed(evp_cipher, lengths_single, &seconds); + ret = 0; + goto end; +@@ -2323,26 +2225,16 @@ skip_hmac: + + names[D_EVP] = EVP_CIPHER_get0_name(evp_cipher); + +- mode_op = EVP_CIPHER_get_mode(evp_cipher); +- +- if (aead) { ++ if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_CCM_MODE) { ++ loopfunc = EVP_Update_loop_ccm; ++ } else if (aead && (EVP_CIPHER_get_flags(evp_cipher) & ++ EVP_CIPH_FLAG_AEAD_CIPHER)) { ++ loopfunc = EVP_Update_loop_aead; + if (lengths == lengths_list) { + lengths = aead_lengths_list; + size_num = OSSL_NELEM(aead_lengths_list); + } + } +- if (mode_op == EVP_CIPH_GCM_MODE +- || mode_op == EVP_CIPH_CCM_MODE +- || mode_op == EVP_CIPH_OCB_MODE +- || mode_op == EVP_CIPH_SIV_MODE) { +- ae_mode = 1; +- if (decrypt) +- loopfunc = EVP_Update_loop_aead_dec; +- else +- loopfunc = EVP_Update_loop_aead_enc; +- } else { +- loopfunc = EVP_Update_loop; +- } + + for (testnum = 0; testnum < size_num; testnum++) { + print_message(names[D_EVP], c[D_EVP][testnum], lengths[testnum], +@@ -2354,144 +2246,37 @@ skip_hmac: + BIO_printf(bio_err, "\nEVP_CIPHER_CTX_new failure\n"); + exit(1); + } +- +- /* +- * For AE modes, we must first encrypt the data to get +- * a valid tag that enables us to decrypt. If we don't +- * encrypt first, we won't have a valid tag that enables +- * authenticity and hence decryption will fail. +- */ +- if (!EVP_CipherInit_ex(loopargs[k].ctx, +- evp_cipher, NULL, NULL, NULL, +- ae_mode ? 1 : !decrypt)) { +- BIO_printf(bio_err, "\nCouldn't init the context\n"); ++ if (!EVP_CipherInit_ex(loopargs[k].ctx, evp_cipher, NULL, ++ NULL, iv, decrypt ? 0 : 1)) { ++ BIO_printf(bio_err, "\nEVP_CipherInit_ex failure\n"); + ERR_print_errors(bio_err); + exit(1); + } + +- /* Padding isn't needed */ + EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0); + + keylen = EVP_CIPHER_CTX_get_key_length(loopargs[k].ctx); + loopargs[k].key = app_malloc(keylen, "evp_cipher key"); + EVP_CIPHER_CTX_rand_key(loopargs[k].ctx, loopargs[k].key); +- +- if (!ae_mode) { +- if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, +- loopargs[k].key, NULL, -1)) { +- BIO_printf(bio_err, "\nFailed to set the key\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } else if (mode_op == EVP_CIPH_SIV_MODE) { +- EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, +- EVP_CTRL_SET_SPEED, 1, NULL); +- } +- if (ae_mode && decrypt) { +- /* Set length of iv (Doesn't apply to SIV mode) */ +- if (mode_op != EVP_CIPH_SIV_MODE) { +- if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, +- EVP_CTRL_AEAD_SET_IVLEN, +- aead_ivlen, NULL)) { +- BIO_printf(bio_err, "\nFailed to set iv length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- /* Set tag_len (Not for SIV at encryption stage) */ +- if (mode_op != EVP_CIPH_GCM_MODE +- && mode_op != EVP_CIPH_SIV_MODE) { +- if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, +- EVP_CTRL_AEAD_SET_TAG, +- TAG_LEN, NULL)) { +- BIO_printf(bio_err, +- "\nFailed to set tag length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, +- loopargs[k].key, aead_iv, -1)) { +- BIO_printf(bio_err, "\nFailed to set the key\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- /* Set total length of input. Only required for CCM */ +- if (mode_op == EVP_CIPH_CCM_MODE) { +- if (!EVP_EncryptUpdate(loopargs[k].ctx, NULL, +- &outlen, NULL, +- lengths[testnum])) { +- BIO_printf(bio_err, +- "\nCouldn't set input text length\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- if (aead) { +- if (!EVP_EncryptUpdate(loopargs[k].ctx, NULL, +- &outlen, aad, sizeof(aad))) { +- BIO_printf(bio_err, +- "\nCouldn't insert AAD when encrypting\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- } +- if (!EVP_EncryptUpdate(loopargs[k].ctx, loopargs[k].buf, +- &outlen, loopargs[k].buf, +- lengths[testnum])) { +- BIO_printf(bio_err, +- "\nFailed to to encrypt the data\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- +- if (!EVP_EncryptFinal_ex(loopargs[k].ctx, +- loopargs[k].buf, &outlen)) { +- BIO_printf(bio_err, +- "\nFailed finalize the encryption\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- +- if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, +- EVP_CTRL_AEAD_GET_TAG, +- TAG_LEN, &loopargs[k].tag)) { +- BIO_printf(bio_err, "\nFailed to get the tag\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- +- EVP_CIPHER_CTX_free(loopargs[k].ctx); +- loopargs[k].ctx = EVP_CIPHER_CTX_new(); +- if (loopargs[k].ctx == NULL) { +- BIO_printf(bio_err, +- "\nEVP_CIPHER_CTX_new failure\n"); +- exit(1); +- } +- if (!EVP_CipherInit_ex(loopargs[k].ctx, evp_cipher, +- NULL, NULL, NULL, 0)) { +- BIO_printf(bio_err, +- "\nFailed initializing the context\n"); +- ERR_print_errors(bio_err); +- exit(1); +- } +- +- EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0); +- +- /* SIV only allows for one Update operation */ +- if (mode_op == EVP_CIPH_SIV_MODE) +- EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, +- EVP_CTRL_SET_SPEED, 1, NULL); ++ if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, ++ loopargs[k].key, NULL, -1)) { ++ BIO_printf(bio_err, "\nEVP_CipherInit_ex failure\n"); ++ ERR_print_errors(bio_err); ++ exit(1); + } ++ OPENSSL_clear_free(loopargs[k].key, keylen); ++ ++ /* SIV mode only allows for a single Update operation */ ++ if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_SIV_MODE) ++ (void)EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, ++ EVP_CTRL_SET_SPEED, 1, NULL); + } + + Time_F(START); + count = run_benchmark(async_jobs, loopfunc, loopargs); + d = Time_F(STOP); +- for (k = 0; k < loopargs_len; k++) { +- OPENSSL_clear_free(loopargs[k].key, keylen); ++ for (k = 0; k < loopargs_len; k++) + EVP_CIPHER_CTX_free(loopargs[k].ctx); +- } + print_result(D_EVP, testnum, count, d); + } + } else if (evp_md_name != NULL) { +@@ -3889,6 +3674,7 @@ static void multiblock_speed(const EVP_C + print_message(alg_name, 0, mblengths[j], seconds->sym); + Time_F(START); + for (count = 0; run && count < INT_MAX; count++) { ++ unsigned char aad[EVP_AEAD_TLS1_AAD_LEN]; + EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; + size_t len = mblengths[j]; + int packlen; diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index e90605499..199d7d513 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -201,6 +201,12 @@ pushd package/libs/openssl/patches curl -sO $mirror/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch popd +# openssl benchmarks +pushd package/libs/openssl/patches + curl -sO $mirror/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch + curl -sO $mirror/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch +popd + # openssl urandom sed -i "/-openwrt/iOPENSSL_OPTIONS += enable-ktls '-DDEVRANDOM=\"\\\\\"/dev/urandom\\\\\"\"\'\n" package/libs/openssl/Makefile From 4f935b921faef5d747c56ee7e2a216a718ea9326 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 29 May 2025 11:49:56 +0800 Subject: [PATCH 228/425] miniupnpd: update to 2.3.9 Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 199d7d513..30c7b6682 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -269,8 +269,8 @@ sed -i 's/procd_set_param stderr 1/procd_set_param stderr 0/g' feeds/packages/ut # UPnP rm -rf feeds/{packages/net/miniupnpd,luci/applications/luci-app-upnp} -git clone https://$gitea/sbwml/miniupnpd feeds/packages/net/miniupnpd -b v2.3.7 -git clone https://$gitea/sbwml/luci-app-upnp feeds/luci/applications/luci-app-upnp -b main +git clone https://$gitea/sbwml/miniupnpd feeds/packages/net/miniupnpd -b v2.3.9 +git clone https://$gitea/sbwml/luci-app-upnp feeds/luci/applications/luci-app-upnp -b openwrt-24.10 # nginx - latest version rm -rf feeds/packages/net/nginx From 6247574db00aa36108b74762e92ed2911152f5cd Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 29 May 2025 11:50:54 +0800 Subject: [PATCH 229/425] dockerd: update custom patches Signed-off-by: sbwml --- .../0001-dockerd-fix-bridge-network.patch | 6 +-- ...er-add-buildkit-experimental-support.patch | 19 ++++---- ...ip6tables-for-bridge-network-by-defa.patch | 46 ------------------- openwrt/scripts/00-prepare_base.sh | 1 - 4 files changed, 13 insertions(+), 59 deletions(-) delete mode 100644 openwrt/patch/docker/0003-dockerd-disable-ip6tables-for-bridge-network-by-defa.patch diff --git a/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch b/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch index a853692e0..1c357dad2 100644 --- a/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch +++ b/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch @@ -9,7 +9,7 @@ Subject: [PATCH] dockerd: fix bridge network 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/dockerd/files/dockerd.init b/utils/dockerd/files/dockerd.init -index 111e2cd8db1b..0ae6fd9af403 100755 +index 8835a6d..ec83ec5 100755 --- a/utils/dockerd/files/dockerd.init +++ b/utils/dockerd/files/dockerd.init @@ -91,6 +91,9 @@ uciadd() { @@ -23,10 +23,10 @@ index 111e2cd8db1b..0ae6fd9af403 100755 fi diff --git a/utils/dockerd/files/etc/config/dockerd b/utils/dockerd/files/etc/config/dockerd -index dd7523543c22..414fa6e5c26e 100644 +index 0fa4a56..03fdcf8 100644 --- a/utils/dockerd/files/etc/config/dockerd +++ b/utils/dockerd/files/etc/config/dockerd -@@ -34,5 +34,5 @@ config globals 'globals' +@@ -41,5 +41,5 @@ config proxies 'proxies' # then docker restarted to load in new changes. config firewall 'firewall' option device 'docker0' diff --git a/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch b/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch index 45a521dbb..56394f2b2 100644 --- a/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch +++ b/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch @@ -10,21 +10,22 @@ Signed-off-by: sbwml 2 files changed, 10 insertions(+) diff --git a/utils/dockerd/files/dockerd.init b/utils/dockerd/files/dockerd.init -index 1e45c44..6a3c5f7 100755 +index ec83ec5..5762c11 100755 --- a/utils/dockerd/files/dockerd.init +++ b/utils/dockerd/files/dockerd.init -@@ -187,12 +187,20 @@ process_config() { - config_get ip globals ip "" - config_get fixed_cidr globals fixed_cidr "" - config_get fixed_cidr_v6 globals fixed_cidr_v6 "" +@@ -193,6 +193,8 @@ process_config() { + config_get https_proxy proxies https_proxy "${https_proxy}" + config_get no_proxy proxies no_proxy "${no_proxy}" + config_get storage_driver globals storage_driver "" + config_get buildkit globals buildkit "0" + config_get experimental globals experimental "0" . /usr/share/libubox/jshn.sh json_init - json_add_string "data-root" "${data_root}" +@@ -200,6 +202,12 @@ process_config() { json_add_string "log-level" "${log_level}" json_add_boolean "iptables" "${iptables}" + json_add_boolean "ip6tables" "${ip6tables}" + [ "${buildkit}" = "1" ] && { + json_add_object 'features' + json_add_boolean "buildkit" "${buildkit}" @@ -35,7 +36,7 @@ index 1e45c44..6a3c5f7 100755 [ -z "${bip}" ] || json_add_string "bip" "${bip}" [ -z "${registry_mirrors}" ] || json_add_array "registry-mirrors" diff --git a/utils/dockerd/files/etc/config/dockerd b/utils/dockerd/files/etc/config/dockerd -index 414fa6e..8958b95 100644 +index 03fdcf8..8cb08fc 100644 --- a/utils/dockerd/files/etc/config/dockerd +++ b/utils/dockerd/files/etc/config/dockerd @@ -20,6 +20,8 @@ config globals 'globals' @@ -45,8 +46,8 @@ index 414fa6e..8958b95 100644 + option buildkit '0' + option experimental '0' - # Docker doesn't work well out of the box with fw4. This is because Docker relies on a compatibility layer that - # naively translates iptables rules. For the best compatibility replace the following dependencies: + # If your organization uses a proxy server to connect to the internet, you may need to configure the proxy. + # See https://docs.docker.com/engine/daemon/proxy/ for more details -- 2.42.0 diff --git a/openwrt/patch/docker/0003-dockerd-disable-ip6tables-for-bridge-network-by-defa.patch b/openwrt/patch/docker/0003-dockerd-disable-ip6tables-for-bridge-network-by-defa.patch deleted file mode 100644 index 31b6c317d..000000000 --- a/openwrt/patch/docker/0003-dockerd-disable-ip6tables-for-bridge-network-by-defa.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 6d0c70c705f9ece064eee9a8b2e0293147c4abae Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 30 Jun 2024 11:17:42 +0800 -Subject: [PATCH] dockerd: disable ip6tables for bridge network by default - -Signed-off-by: sbwml ---- - utils/dockerd/files/dockerd.init | 2 ++ - utils/dockerd/files/etc/config/dockerd | 1 + - 2 files changed, 3 insertions(+) - -diff --git a/utils/dockerd/files/dockerd.init b/utils/dockerd/files/dockerd.init -index 6a3c5f7..17dd9d1 100755 ---- a/utils/dockerd/files/dockerd.init -+++ b/utils/dockerd/files/dockerd.init -@@ -175,6 +175,7 @@ process_config() { - config_get data_root globals data_root "/opt/docker/" - config_get log_level globals log_level "warn" - config_get_bool iptables globals iptables "1" -+ config_get_bool ip6tables globals ip6tables "0" - - # Don't add these options by default - # omission == docker defaults -@@ -195,6 +196,7 @@ process_config() { - json_add_string "data-root" "${data_root}" - json_add_string "log-level" "${log_level}" - json_add_boolean "iptables" "${iptables}" -+ json_add_boolean "ip6tables" "${ip6tables}" - [ "${buildkit}" = "1" ] && { - json_add_object 'features' - json_add_boolean "buildkit" "${buildkit}" -diff --git a/utils/dockerd/files/etc/config/dockerd b/utils/dockerd/files/etc/config/dockerd -index 8958b95..9035c13 100644 ---- a/utils/dockerd/files/etc/config/dockerd -+++ b/utils/dockerd/files/etc/config/dockerd -@@ -11,6 +11,7 @@ config globals 'globals' - # option log_driver 'local' - option log_level 'warn' - option iptables '1' -+ option ip6tables '0' - # list hosts 'unix:///var/run/docker.sock' - # option bip '172.18.0.1/24' - # option fixed_cidr '172.17.0.0/16' --- -2.42.0 - diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 30c7b6682..bacb2b670 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -243,7 +243,6 @@ sed -i '/sysctl.d/d' feeds/packages/utils/dockerd/Makefile pushd feeds/packages curl -s $mirror/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch | patch -p1 curl -s $mirror/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch | patch -p1 - curl -s $mirror/openwrt/patch/docker/0003-dockerd-disable-ip6tables-for-bridge-network-by-defa.patch | patch -p1 popd # cgroupfs-mount From c3a3f16a61e1b487ba67900fc86f78cd3b9b314b Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 29 May 2025 22:15:14 +0800 Subject: [PATCH 230/425] [WIP] images: add squashfs zstd compression support Signed-off-by: sbwml --- ...hfs4-enable-zstd-compression-support.patch | 124 ++++++++++++++++++ ...mage-add-support-for-squashfs-zstd-c.patch | 47 +++++++ openwrt/scripts/00-prepare_base.sh | 2 + 3 files changed, 173 insertions(+) create mode 100644 openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch create mode 100644 openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch diff --git a/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch b/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch new file mode 100644 index 000000000..6dc62030b --- /dev/null +++ b/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch @@ -0,0 +1,124 @@ +From baebc1fe503f69e2e0cdd3d932dc328a86be1b7d Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 29 May 2025 17:11:26 +0800 +Subject: [PATCH 11/12] tools: squashfs4: enable zstd compression support + +Signed-off-by: sbwml +--- + tools/Makefile | 2 +- + tools/squashfs4/Makefile | 1 + + ...negative-levels-for-zstd-compression.patch | 77 +++++++++++++++++++ + 3 files changed, 79 insertions(+), 1 deletion(-) + create mode 100644 tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch + +diff --git a/tools/Makefile b/tools/Makefile +index 702184a..d706c13 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -129,7 +129,7 @@ $(curdir)/pkgconf/compile := $(curdir)/meson/compile + $(curdir)/quilt/compile := $(curdir)/autoconf/compile $(curdir)/findutils/compile + $(curdir)/sdcc/compile := $(curdir)/bison/compile + $(curdir)/squashfs3-lzma/compile := $(curdir)/lzma-old/compile +-$(curdir)/squashfs4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile ++$(curdir)/squashfs4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile $(curdir)/zstd/compile + $(curdir)/util-linux/compile := $(curdir)/bison/compile $(curdir)/automake/compile + $(curdir)/yafut/compile := $(curdir)/cmake/compile + +diff --git a/tools/squashfs4/Makefile b/tools/squashfs4/Makefile +index 38c3e52..e3065bf 100644 +--- a/tools/squashfs4/Makefile ++++ b/tools/squashfs4/Makefile +@@ -27,6 +27,7 @@ define Host/Compile + XZ_SUPPORT=1 \ + LZMA_XZ_SUPPORT=1 \ + XZ_EXTENDED_OPTIONS=1 \ ++ ZSTD_SUPPORT=1 \ + EXTRA_CFLAGS="-I$(STAGING_DIR_HOST)/include" \ + mksquashfs unsquashfs + endef +diff --git a/tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch b/tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch +new file mode 100644 +index 0000000..b219d9f +--- /dev/null ++++ b/tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch +@@ -0,0 +1,77 @@ ++From 31f103dc9b0cce526adc35a5f49437d58b6799c0 Mon Sep 17 00:00:00 2001 ++From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= ++Date: Sun, 16 Feb 2025 13:42:53 +0100 ++Subject: [PATCH] Support negative levels for zstd compression ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++These levels correspond to the --fast option of the zstd program, ++and offers better compression speed for worse compression rate. ++ ++Signed-off-by: Anders F Björklund ++--- ++ squashfs-tools/zstd_wrapper.c | 27 +++++++++++++++++++++------ ++ 1 file changed, 21 insertions(+), 6 deletions(-) ++ ++--- a/squashfs-tools/zstd_wrapper.c +++++ b/squashfs-tools/zstd_wrapper.c ++@@ -51,12 +51,25 @@ static int zstd_options(char *argv[], in ++ fprintf(stderr, "zstd: -Xcompression-level missing " ++ "compression level\n"); ++ fprintf(stderr, "zstd: -Xcompression-level it should " ++- "be 1 <= n <= %d\n", ZSTD_maxCLevel()); +++ "be %d <= n <= -1 or 1 <= n <= %d\n", +++ ZSTD_minCLevel(), ZSTD_maxCLevel()); ++ goto failed; ++ } ++ ++ compression_level = atoi(argv[1]); ++- if (compression_level < 1 || +++ if (compression_level == 0) { +++ fprintf(stderr, "zstd: -Xcompression-level invalid, it " +++ "should be %d <= n <= -1 or 1 <= n <= %d\n", +++ ZSTD_minCLevel(), ZSTD_maxCLevel()); +++ goto failed; +++ } +++ if (compression_level < 0 && +++ compression_level < ZSTD_minCLevel()) { +++ fprintf(stderr, "zstd: -Xcompression-level invalid, it " +++ "should be %d <= n <= -1\n", ZSTD_minCLevel()); +++ goto failed; +++ } +++ if (compression_level > 0 && ++ compression_level > ZSTD_maxCLevel()) { ++ fprintf(stderr, "zstd: -Xcompression-level invalid, it " ++ "should be 1 <= n <= %d\n", ZSTD_maxCLevel()); ++@@ -132,7 +145,8 @@ static int zstd_extract_options(int bloc ++ ++ SQUASHFS_INSWAP_COMP_OPTS(comp_opts); ++ ++- if (comp_opts->compression_level < 1 || +++ if (comp_opts->compression_level == 0 || +++ comp_opts->compression_level < ZSTD_minCLevel() || ++ comp_opts->compression_level > ZSTD_maxCLevel()) { ++ fprintf(stderr, "zstd: bad compression level in compression " ++ "options structure\n"); ++@@ -160,7 +174,8 @@ static void zstd_display_options(void *b ++ ++ SQUASHFS_INSWAP_COMP_OPTS(comp_opts); ++ ++- if (comp_opts->compression_level < 1 || +++ if (comp_opts->compression_level == 0 || +++ comp_opts->compression_level < ZSTD_minCLevel() || ++ comp_opts->compression_level > ZSTD_maxCLevel()) { ++ fprintf(stderr, "zstd: bad compression level in compression " ++ "options structure\n"); ++@@ -235,8 +250,8 @@ static int zstd_uncompress(void *dest, v ++ static void zstd_usage(FILE *stream) ++ { ++ fprintf(stream, "\t -Xcompression-level \n"); ++- fprintf(stream, "\t\t should be 1 .. %d (default " ++- "%d)\n", ZSTD_maxCLevel(), ZSTD_DEFAULT_COMPRESSION_LEVEL); +++ fprintf(stream, "\t\t should be %d .. -1 or 1 .. %d (default %d). Negative compression levels correspond to the zstd --fast option.\n", +++ ZSTD_minCLevel(), ZSTD_maxCLevel(), ZSTD_DEFAULT_COMPRESSION_LEVEL); ++ } ++ ++ +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch b/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch new file mode 100644 index 000000000..5e7b874f3 --- /dev/null +++ b/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch @@ -0,0 +1,47 @@ +From 6b33c9bae79c972a711da6b719c2e924ba76b16a Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 29 May 2025 17:12:37 +0800 +Subject: [PATCH 12/12] config/include: image: add support for squashfs zstd + compression algorithm + +Signed-off-by: sbwml +--- + config/Config-images.in | 7 +++++++ + include/image.mk | 3 +++ + 2 files changed, 10 insertions(+) + +diff --git a/config/Config-images.in b/config/Config-images.in +index ed9ecb2..8b91b7f 100644 +--- a/config/Config-images.in ++++ b/config/Config-images.in +@@ -160,6 +160,13 @@ menu "Target Images" + Select squashfs block size, must be one of: + 4, 8, 16, 32, 64, 128, 256, 512, 1024 + ++ config TARGET_ROOTFS_SQUASHFS_ZSTD ++ bool "SquashFS Zstd" ++ depends on TARGET_ROOTFS_SQUASHFS ++ default n ++ help ++ Build a squashfs root filesystem using zstd compression. ++ + menuconfig TARGET_ROOTFS_UBIFS + bool "ubifs" + default y if USES_UBIFS +diff --git a/include/image.mk b/include/image.mk +index 9a4dff2..b121622 100644 +--- a/include/image.mk ++++ b/include/image.mk +@@ -94,6 +94,9 @@ ifeq ($(CONFIG_SQUASHFS_XZ),y) + endif + SQUASHFSCOMP := xz $(LZMA_XZ_OPTIONS) $(BCJ_FILTER) + endif ++ifeq ($(CONFIG_TARGET_ROOTFS_SQUASHFS_ZSTD),y) ++ SQUASHFSCOMP := zstd -Xcompression-level 22 ++endif + + JFFS2_BLOCKSIZE ?= 64k 128k + +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index bacb2b670..7c5eebb74 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -21,6 +21,8 @@ curl -s $mirror/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config- curl -s $mirror/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 +#curl -s $mirror/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch | patch -p1 +#curl -s $mirror/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch | patch -p1 # attr no-mold [ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile From 0e5ec04f40a35be4848de846bee81f66073389b3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 29 May 2025 22:20:55 +0800 Subject: [PATCH 231/425] config: set squashfs block size to 1024 in build config Signed-off-by: sbwml --- openwrt/24-config-musl-armsr-armv8 | 1 + openwrt/24-config-musl-r4s | 1 + openwrt/24-config-musl-r5s | 1 + openwrt/24-config-musl-x86 | 1 + 4 files changed, 4 insertions(+) diff --git a/openwrt/24-config-musl-armsr-armv8 b/openwrt/24-config-musl-armsr-armv8 index c4da496ef..9fef4b2d7 100644 --- a/openwrt/24-config-musl-armsr-armv8 +++ b/openwrt/24-config-musl-armsr-armv8 @@ -19,5 +19,6 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=64 CONFIG_TARGET_ROOTFS_PARTSIZE=944 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=16 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r4s b/openwrt/24-config-musl-r4s index 2bd107954..573149569 100644 --- a/openwrt/24-config-musl-r4s +++ b/openwrt/24-config-musl-r4s @@ -19,6 +19,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r5s b/openwrt/24-config-musl-r5s index c5224bfee..a04f154c3 100644 --- a/openwrt/24-config-musl-r5s +++ b/openwrt/24-config-musl-r5s @@ -22,6 +22,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=6 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-x86 b/openwrt/24-config-musl-x86 index 7e25ae389..7bc1f3ed2 100644 --- a/openwrt/24-config-musl-x86 +++ b/openwrt/24-config-musl-x86 @@ -20,6 +20,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=32 CONFIG_TARGET_ROOTFS_PARTSIZE=944 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 # CONFIG_KERNEL_KALLSYMS is not set ### Kernel driver From 6749728f1c0b5e1c3928657c0f6e1827ba4e49a0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 29 May 2025 22:36:23 +0800 Subject: [PATCH 232/425] linux-6.12: bump to 6.12.31 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 3f710bc5e..343c2148f 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .30 -LINUX_KERNEL_HASH-6.12.30 = df046a48971e40ce0b2e003e7e55b6b1e7da2912120eb216d5d6c8450c9cf82e +LINUX_VERSION-6.12 = .31 +LINUX_KERNEL_HASH-6.12.31 = b04c5b3e5df6e0aa5e9cd1efe527fac99f9dd39a43b97f13b22f8ca93e524ba7 From b9e349fd878937c49ae862078ff74a286937ece9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 30 May 2025 11:10:56 +0800 Subject: [PATCH 233/425] mac80211 & ath10k-ct: update to 6.15 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 6872900f6..dfbb1772c 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -186,13 +186,13 @@ curl -s $mirror/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-back # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - 6.14 +# mac80211 - 6.15 rm -rf package/kernel/mac80211 git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 # ath10k-ct rm -rf package/kernel/ath10k-ct -git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.14 +git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.15 # kernel patch # btf: silence btf module warning messages From 06b2115555c51e1dcde4e74c6a559b7559c3d303 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 30 May 2025 11:11:41 +0800 Subject: [PATCH 234/425] mt76: update to 2025-05-21 Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 6 +++--- .../patches/102-fix-build-with-mac80211-6.14-backport.patch | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 490f99e5b..ef12fe5f0 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2025-03-19 -PKG_SOURCE_VERSION:=d5cddf65f7a783969fe4163b4643b144fa672b77 -PKG_MIRROR_HASH:=9af902d27595ddb1d96db156975cf31378ea8434cfac77e3b48f5f31c6eb146a +PKG_SOURCE_DATE:=2025-05-21 +PKG_SOURCE_VERSION:=3e161d0cf3c74bbb39e221d5aee37c50d013d052 +PKG_MIRROR_HASH:=3e5145eb65e170e62cee4e6b5cc2c17ee27a519272945536221ac733cd208204 PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 diff --git a/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch b/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch index 162fab1df..b34345c09 100644 --- a/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch +++ b/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch @@ -1,6 +1,6 @@ --- a/mac80211.c +++ b/mac80211.c -@@ -1702,7 +1702,7 @@ s8 mt76_get_power_bound(struct mt76_phy +@@ -1704,7 +1704,7 @@ s8 mt76_get_power_bound(struct mt76_phy EXPORT_SYMBOL_GPL(mt76_get_power_bound); int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -11,7 +11,7 @@ int n_chains, delta; --- a/mt76.h +++ b/mt76.h -@@ -1496,7 +1496,7 @@ int mt76_get_min_avg_rssi(struct mt76_de +@@ -1508,7 +1508,7 @@ int mt76_get_min_avg_rssi(struct mt76_de s8 mt76_get_power_bound(struct mt76_phy *phy, s8 txpower); int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -22,7 +22,7 @@ int mt76_get_sar_power(struct mt76_phy *phy, --- a/mt7996/main.c +++ b/mt7996/main.c -@@ -664,7 +664,8 @@ static void mt7996_configure_filter(stru +@@ -668,7 +668,8 @@ static void mt7996_configure_filter(stru } static int From 38b6c8c71e8e472c2833b67e9447ebc07e56a5ad Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 30 May 2025 13:01:38 +0800 Subject: [PATCH 235/425] config: set squashfs block size to 512 in build config Signed-off-by: sbwml --- openwrt/24-config-musl-armsr-armv8 | 2 +- openwrt/24-config-musl-r4s | 2 +- openwrt/24-config-musl-r5s | 2 +- openwrt/24-config-musl-x86 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/24-config-musl-armsr-armv8 b/openwrt/24-config-musl-armsr-armv8 index 9fef4b2d7..7a5a86be6 100644 --- a/openwrt/24-config-musl-armsr-armv8 +++ b/openwrt/24-config-musl-armsr-armv8 @@ -19,6 +19,6 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=64 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 CONFIG_COREMARK_NUMBER_OF_THREADS=16 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r4s b/openwrt/24-config-musl-r4s index 573149569..11d56d244 100644 --- a/openwrt/24-config-musl-r4s +++ b/openwrt/24-config-musl-r4s @@ -19,7 +19,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r5s b/openwrt/24-config-musl-r5s index a04f154c3..f3ae1c64a 100644 --- a/openwrt/24-config-musl-r5s +++ b/openwrt/24-config-musl-r5s @@ -22,7 +22,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 CONFIG_COREMARK_NUMBER_OF_THREADS=6 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-x86 b/openwrt/24-config-musl-x86 index 7bc1f3ed2..a04d7538b 100644 --- a/openwrt/24-config-musl-x86 +++ b/openwrt/24-config-musl-x86 @@ -20,7 +20,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=32 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 # CONFIG_KERNEL_KALLSYMS is not set ### Kernel driver From 7fc460357f2fee6005e890d347aa1dc653875382 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 30 May 2025 21:15:10 +0800 Subject: [PATCH 236/425] Revert "config: set squashfs block size to 512 in build config" This reverts commit 38b6c8c71e8e472c2833b67e9447ebc07e56a5ad. --- openwrt/24-config-musl-armsr-armv8 | 2 +- openwrt/24-config-musl-r4s | 2 +- openwrt/24-config-musl-r5s | 2 +- openwrt/24-config-musl-x86 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/24-config-musl-armsr-armv8 b/openwrt/24-config-musl-armsr-armv8 index 7a5a86be6..9fef4b2d7 100644 --- a/openwrt/24-config-musl-armsr-armv8 +++ b/openwrt/24-config-musl-armsr-armv8 @@ -19,6 +19,6 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=64 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=16 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r4s b/openwrt/24-config-musl-r4s index 11d56d244..573149569 100644 --- a/openwrt/24-config-musl-r4s +++ b/openwrt/24-config-musl-r4s @@ -19,7 +19,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r5s b/openwrt/24-config-musl-r5s index f3ae1c64a..a04f154c3 100644 --- a/openwrt/24-config-musl-r5s +++ b/openwrt/24-config-musl-r5s @@ -22,7 +22,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=6 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-x86 b/openwrt/24-config-musl-x86 index a04d7538b..7bc1f3ed2 100644 --- a/openwrt/24-config-musl-x86 +++ b/openwrt/24-config-musl-x86 @@ -20,7 +20,7 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=32 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 +CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 # CONFIG_KERNEL_KALLSYMS is not set ### Kernel driver From 6152dcad2ce3ba9e8aa14ef20929b899dd3f7fc9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 30 May 2025 21:15:18 +0800 Subject: [PATCH 237/425] Revert "config: set squashfs block size to 1024 in build config" This reverts commit 0e5ec04f40a35be4848de846bee81f66073389b3. --- openwrt/24-config-musl-armsr-armv8 | 1 - openwrt/24-config-musl-r4s | 1 - openwrt/24-config-musl-r5s | 1 - openwrt/24-config-musl-x86 | 1 - 4 files changed, 4 deletions(-) diff --git a/openwrt/24-config-musl-armsr-armv8 b/openwrt/24-config-musl-armsr-armv8 index 9fef4b2d7..c4da496ef 100644 --- a/openwrt/24-config-musl-armsr-armv8 +++ b/openwrt/24-config-musl-armsr-armv8 @@ -19,6 +19,5 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=64 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=16 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r4s b/openwrt/24-config-musl-r4s index 573149569..2bd107954 100644 --- a/openwrt/24-config-musl-r4s +++ b/openwrt/24-config-musl-r4s @@ -19,7 +19,6 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r5s b/openwrt/24-config-musl-r5s index a04f154c3..c5224bfee 100644 --- a/openwrt/24-config-musl-r5s +++ b/openwrt/24-config-musl-r5s @@ -22,7 +22,6 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=16 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 CONFIG_COREMARK_NUMBER_OF_THREADS=6 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-x86 b/openwrt/24-config-musl-x86 index 7bc1f3ed2..7e25ae389 100644 --- a/openwrt/24-config-musl-x86 +++ b/openwrt/24-config-musl-x86 @@ -20,7 +20,6 @@ CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y CONFIG_TARGET_KERNEL_PARTSIZE=32 CONFIG_TARGET_ROOTFS_PARTSIZE=944 -CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 # CONFIG_KERNEL_KALLSYMS is not set ### Kernel driver From 6ac32dee499f9aada87e79095b38c3eb73b31267 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 2 Jun 2025 16:41:52 +0800 Subject: [PATCH 238/425] linux-6.12: fix build warnings in bbr3 with Clang Signed-off-by: sbwml --- ...den-app-limited-rate-sample-detectio.patch | 2 +- ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 2 +- ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 2 +- ...djust-skb-tx.in_flight-upon-merge-in.patch | 2 +- ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 2 +- ...nform-CC-module-of-losses-repaired-b.patch | 2 +- ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 10 ++-- ...v3-silence-Wconstant-logical-operand.patch | 53 +++++++++++++++++++ openwrt/scripts/01-prepare_base-mainline.sh | 1 + 9 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index 814d89a39..a50a97df0 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -32,7 +32,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3967,6 +3967,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -3983,6 +3983,7 @@ static int tcp_ack(struct sock *sk, cons prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; rs.prior_in_flight = tcp_packets_in_flight(tp); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index 72f08ce89..dd03edc9d 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -28,7 +28,7 @@ Signed-off-by: Alexandre Frade struct tcp_congestion_ops { --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4066,6 +4066,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4073,6 +4073,7 @@ static int tcp_ack(struct sock *sk, cons delivered = tcp_newly_delivered(sk, delivered, flag); lost = tp->lost - lost; /* freshly marked lost */ rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index 822255b0d..c83072f3c 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1126,7 +1126,12 @@ static void tcp_verify_retransmit_hint(s +@@ -1140,7 +1140,12 @@ static void tcp_verify_retransmit_hint(s */ static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) { diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch index 239e4dad4..a915ec403 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch @@ -39,7 +39,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1512,6 +1512,17 @@ static bool tcp_shifted_skb(struct sock +@@ -1517,6 +1517,17 @@ static bool tcp_shifted_skb(struct sock WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); tcp_skb_pcount_add(skb, -pcount); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index b3c7afae6..e64af261e 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5776,13 +5776,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5784,13 +5784,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index 26a131d04..a4288b085 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3865,6 +3865,7 @@ static void tcp_process_tlp_ack(struct s +@@ -3870,6 +3870,7 @@ static void tcp_process_tlp_ack(struct s /* ACK advances: there was a loss, so reduce cwnd. Reset * tlp_high_seq in tcp_init_cwnd_reduction() */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index 8a0aa731a..f4ed58e7f 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3848,7 +3848,8 @@ static void tcp_replace_ts_recent(struct +@@ -3853,7 +3853,8 @@ static void tcp_replace_ts_recent(struct /* This routine deals with acks during a TLP episode and ends an episode by * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack */ @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade { struct tcp_sock *tp = tcp_sk(sk); -@@ -3876,6 +3877,11 @@ static void tcp_process_tlp_ack(struct s +@@ -3881,6 +3882,11 @@ static void tcp_process_tlp_ack(struct s FLAG_NOT_DUP | FLAG_DATA_SACKED))) { /* Pure dupack: original and TLP probe arrived; no loss */ tp->tlp_high_seq = 0; @@ -53,8 +53,8 @@ Signed-off-by: Alexandre Frade } } -@@ -4059,7 +4065,7 @@ static int tcp_ack(struct sock *sk, cons - tcp_rack_update_reo_wnd(sk, &rs); +@@ -4066,7 +4072,7 @@ static int tcp_ack(struct sock *sk, cons + tcp_in_ack_event(sk, flag); if (tp->tlp_high_seq) - tcp_process_tlp_ack(sk, ack, flag); @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade if (tcp_ack_is_dubious(sk, flag)) { if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4103,7 +4109,7 @@ no_queue: +@@ -4111,7 +4117,7 @@ no_queue: tcp_ack_probe(sk); if (tp->tlp_high_seq) diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch new file mode 100644 index 000000000..520924fa1 --- /dev/null +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch @@ -0,0 +1,53 @@ +From 0557c352fdbb0981be50d82059d1841e10bc55b0 Mon Sep 17 00:00:00 2001 +From: Oleksandr Natalenko +Date: Tue, 18 Mar 2025 09:47:46 +0100 +Subject: [PATCH 3/4] net-tcp_bbr: v3: silence -Wconstant-logical-operand + +The `ecn_thresh` and `ecn_factor` params are just consts in a public +version of BBRv3, so evaluating them in conditions as booleans triggers +`-Wconstant-logical-operand` with Clang. + +Prepend relevant invocations with double negation to convert values to +booleans explicitly. + +The values are always `true`, so these parts of conditions can also be +dropped. Keeping them instead since they are used in an internal version +of BBRv3 to stay as close to the original code as possible. + +Link: https://lore.kernel.org/lkml/4616579.LvFx2qVVIh@natalenko.name/T/#u +Link: https://groups.google.com/g/bbr-dev/c/4vwZGw0nxdQ/m/fWt9xmbzAwAJ +Closes: https://codeberg.org/pf-kernel/linux/issues/11 +Signed-off-by: Oleksandr Natalenko +--- + net/ipv4/tcp_bbr.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/net/ipv4/tcp_bbr.c ++++ b/net/ipv4/tcp_bbr.c +@@ -1077,7 +1077,7 @@ static int bbr_update_ecn_alpha(struct s + + /* See if we should use ECN sender logic for this connection. */ + if (!bbr->ecn_eligible && bbr_can_use_ecn(sk) && +- bbr_param(sk, ecn_factor) && ++ !!bbr_param(sk, ecn_factor) && + (bbr->min_rtt_us <= bbr_ecn_max_rtt_us || + !bbr_ecn_max_rtt_us)) + bbr->ecn_eligible = 1; +@@ -1184,7 +1184,7 @@ static bool bbr_is_inflight_too_high(con + } + + if (rs->delivered_ce > 0 && rs->delivered > 0 && +- bbr->ecn_eligible && bbr_param(sk, ecn_thresh)) { ++ bbr->ecn_eligible && !!bbr_param(sk, ecn_thresh)) { + ecn_thresh = (u64)rs->delivered * bbr_param(sk, ecn_thresh) >> + BBR_SCALE; + if (rs->delivered_ce > ecn_thresh) { +@@ -1382,7 +1382,7 @@ static void bbr_adapt_lower_bounds(struc + return; + + /* ECN response. */ +- if (bbr->ecn_in_round && bbr_param(sk, ecn_factor)) { ++ if (bbr->ecn_in_round && !!bbr_param(sk, ecn_factor)) { + bbr_init_lower_bounds(sk, false); + bbr_ecn_lower_bounds(sk, &ecn_inflight_lo); + } diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index dfbb1772c..91f708ac5 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -124,6 +124,7 @@ pushd target/linux/generic/backport-6.12 curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch + curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch popd # LRNG - 6.12 From 045a3a53c2842e447d21e5d54228816c0f2e52b0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Jun 2025 01:48:12 +0800 Subject: [PATCH 239/425] config: add kmod-sched-cake * fix network issues caused by missing sch_cake module Signed-off-by: sbwml --- openwrt/24-config-common | 1 + openwrt/24-config-minimal-common | 1 + 2 files changed, 2 insertions(+) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index e16bd7246..cd7436088 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -208,6 +208,7 @@ CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y CONFIG_PACKAGE_kmod-nls-cp936=y CONFIG_PACKAGE_kmod-nls-cp950=y +CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-bpf=y CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index 7446f26be..981d4b574 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -135,6 +135,7 @@ CONFIG_PACKAGE_kmod-nft-fullcone=y CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y +CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-bpf=y CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y From ce51c061832a88fe1af189bb76ce929227470d32 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Jun 2025 14:38:31 +0800 Subject: [PATCH 240/425] config: r8500: add kmod-sched-cake Signed-off-by: sbwml --- openwrt/24-config-musl-r8500 | 1 + openwrt/24-config-musl-r8500-minimal | 1 + 2 files changed, 2 insertions(+) diff --git a/openwrt/24-config-musl-r8500 b/openwrt/24-config-musl-r8500 index 35916bd16..7c31409f0 100644 --- a/openwrt/24-config-musl-r8500 +++ b/openwrt/24-config-musl-r8500 @@ -191,6 +191,7 @@ CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y diff --git a/openwrt/24-config-musl-r8500-minimal b/openwrt/24-config-musl-r8500-minimal index d4b58f3c4..96e119ab6 100644 --- a/openwrt/24-config-musl-r8500-minimal +++ b/openwrt/24-config-musl-r8500-minimal @@ -144,6 +144,7 @@ CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y From 02ecf57b999a8eae145ec68fd8c7f489c065e2c6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 5 Jun 2025 20:35:23 +0800 Subject: [PATCH 241/425] linux-6.12: bump to 6.12.32 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 343c2148f..f30c6f52e 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .31 -LINUX_KERNEL_HASH-6.12.31 = b04c5b3e5df6e0aa5e9cd1efe527fac99f9dd39a43b97f13b22f8ca93e524ba7 +LINUX_VERSION-6.12 = .32 +LINUX_KERNEL_HASH-6.12.32 = a9b020721778384507010177d3929e7d4058f7f6120f05a99d56b5c5c0346a70 From ac3ee012d8741991b387ce98412e061a1ae85881 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Jun 2025 21:03:15 +0800 Subject: [PATCH 242/425] config: minimal: remove oaf Signed-off-by: sbwml --- openwrt/24-config-common | 2 +- openwrt/24-config-minimal-common | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index cd7436088..e9acde2a9 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -208,8 +208,8 @@ CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y CONFIG_PACKAGE_kmod-nls-cp936=y CONFIG_PACKAGE_kmod-nls-cp950=y -CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index 981d4b574..f1a030e16 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -82,7 +82,6 @@ CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-filemanager=y -CONFIG_PACKAGE_luci-app-oaf=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y @@ -135,15 +134,14 @@ CONFIG_PACKAGE_kmod-nft-fullcone=y CONFIG_PACKAGE_kmod-nft-offload=y CONFIG_PACKAGE_kmod-nft-socket=y CONFIG_PACKAGE_kmod-nft-tproxy=y -CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-cake=y CONFIG_PACKAGE_kmod-sched-core=y CONFIG_PACKAGE_kmod-sched=y CONFIG_PACKAGE_kmod-tcp-bbr3=y CONFIG_PACKAGE_kmod-tcp-brutal=y CONFIG_PACKAGE_kmod-tls=y CONFIG_PACKAGE_kmod-tun=y -CONFIG_PACKAGE_kmod-usb-audio=y CONFIG_PACKAGE_kmod-usb-hid=y CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb2-pci=y From bc16947da1351d06d732560c02655028676ca00d Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Jun 2025 21:17:40 +0800 Subject: [PATCH 243/425] build.sh: add support for custom default password Signed-off-by: sbwml --- openwrt/build.sh | 4 +++- openwrt/scripts/00-prepare_base.sh | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index b5138f1f0..1caa43713 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -130,7 +130,8 @@ export \ ENABLE_DPDK=$ENABLE_DPDK \ ENABLE_GLIBC=$ENABLE_GLIBC \ ENABLE_LRNG=$ENABLE_LRNG \ - KERNEL_CLANG_LTO=$KERNEL_CLANG_LTO + KERNEL_CLANG_LTO=$KERNEL_CLANG_LTO \ + ROOT_PASSWORD=$ROOT_PASSWORD # print version echo -e "\r\n${GREEN_COLOR}Building $branch${RES}\r\n" @@ -157,6 +158,7 @@ echo -e "${GREEN_COLOR}Date: $CURRENT_DATE${RES}\r\n" echo -e "${GREEN_COLOR}SCRIPT_URL:${RES} ${BLUE_COLOR}$mirror${RES}\r\n" echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" [ -n "$LAN" ] && echo -e "${GREEN_COLOR}LAN: $LAN${RES}" || echo -e "${GREEN_COLOR}LAN: 10.0.0.1${RES}" +[ -n "$ROOT_PASSWORD" ] && echo -e "${GREEN_COLOR}Default Password:${RES} ${BLUE_COLOR}$ROOT_PASSWORD${RES}" || echo -e "${GREEN_COLOR}Default Password: (${RES}${YELLOW_COLOR}No password${RES}${GREEN_COLOR})${RES}" [ "$ENABLE_GLIBC" = "y" ] && echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}glibc${RES}" || echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}musl${RES}" [ "$ENABLE_OTA" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_OTA: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_OTA:${RES} ${YELLOW_COLOR}false${RES}" [ "$ENABLE_DPDK" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_DPDK: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_DPDK:${RES} ${YELLOW_COLOR}false${RES}" diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 7c5eebb74..39d24f7e7 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -37,6 +37,13 @@ sed -i 's/noinitrd/noinitrd mitigations=off/g' target/linux/x86/image/grub-efi.c # default LAN IP sed -i "s/192.168.1.1/$LAN/g" package/base-files/files/bin/config_generate +# default password +if [ -n "$ROOT_PASSWORD" ]; then + # sha256 encryption + default_password=$(openssl passwd -5 $ROOT_PASSWORD) + sed -i "s|^root:[^:]*:|root:${default_password}:|" package/base-files/files/etc/shadow +fi + # Use nginx instead of uhttpd if [ "$ENABLE_UHTTPD" != "y" ]; then sed -i 's/+uhttpd /+luci-nginx /g' feeds/luci/collections/luci/Makefile From 51114ecfbd2f5880dcfcf4cba61052fb227335bc Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Jun 2025 21:24:30 +0800 Subject: [PATCH 244/425] ci/docs: add custom default password Signed-off-by: sbwml --- .github/workflows/build-release.yml | 6 ++++++ README.md | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index fa1b8b02f..d36ca5c0b 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -31,6 +31,11 @@ on: required: true default: '10.0.0.1' type: string + root_password: + description: 'Setting default root password (Optional, No password by default)' + required: false + default: '' + type: string build_options: description: 'Build options (separate multiple options with spaces)' required: false @@ -126,6 +131,7 @@ jobs: run: | export ${{ github.event.inputs.build_options }} LAN=${{ github.event.inputs.lan_addr }} USE_GCC15=y [ ${{ github.event.inputs.ccache }} = 'true' ] && export ENABLE_CCACHE=y + [ -n ${{ github.event.inputs.root_password }} ] && export ROOT_PASSWORD="${{ github.event.inputs.root_password }}" bash <(curl -sS http://127.0.0.1:8080/build.sh) ${{ env.build_version }} ${{ github.event.inputs.device }} cd openwrt if [ "${{ github.event.inputs.version }}" = release ]; then diff --git a/README.md b/README.md index 5c816706d..92b0d9e5b 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,13 @@ export MINIMAL_BUILD=y export LAN=10.0.0.1 ``` +### 更改默认 ROOT 密码 +##### 只需在构建固件前执行以下命令即可设置默认 ROOT 密码(默认:无密码) + +``` +export ROOT_PASSWORD=12345678 +``` + ### 使用 uhttpd 轻量 web 引擎 ##### 固件默认使用 Nginx(quic) 作为页面引擎,只需在构建固件前执行以下命令即可使用 uhttpd 取代 nginx ##### Nginx 在具备公网的环境下可以提供更丰富的功能支持 From 7f3814619682a187ab79d09a6381e65c50654d48 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 9 Jun 2025 23:07:29 +0800 Subject: [PATCH 245/425] Revert "sysctl.d: use `cake` queueing discipline" This reverts commit 414de20dcf97a06eaa5637a163cb34315d6f5b29. * ARM architecture CPU usage is too high --- openwrt/files/etc/sysctl.d/10-default.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/openwrt/files/etc/sysctl.d/10-default.conf b/openwrt/files/etc/sysctl.d/10-default.conf index 627187d7c..a4c998aad 100644 --- a/openwrt/files/etc/sysctl.d/10-default.conf +++ b/openwrt/files/etc/sysctl.d/10-default.conf @@ -11,8 +11,6 @@ fs.protected_symlinks=1 net.core.bpf_jit_enable=1 net.core.bpf_jit_kallsyms=1 -net.core.default_qdisc=cake - net.ipv4.conf.default.arp_ignore=1 net.ipv4.conf.all.arp_ignore=1 net.ipv4.ip_forward=1 From 5faf35d07b185d020783fdc889d1e116cfbddfb0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 10 Jun 2025 00:19:36 +0800 Subject: [PATCH 246/425] config-common: drop samba4-admin Signed-off-by: sbwml --- openwrt/24-config-common | 1 - 1 file changed, 1 deletion(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index e9acde2a9..1bd2b0ea3 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -263,7 +263,6 @@ CONFIG_PACKAGE_qrencode=y CONFIG_PACKAGE_rename=y CONFIG_PACKAGE_resize2fs=y CONFIG_PACKAGE_rsync=y -CONFIG_PACKAGE_samba4-admin=y CONFIG_PACKAGE_screen=y CONFIG_PACKAGE_sed=y CONFIG_PACKAGE_sshpass=y From f8639d4d8a2d59dd52a46fc4ea99792390a8eaba Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Jun 2025 20:43:02 +0800 Subject: [PATCH 247/425] linux-6.12: bump to 6.12.33 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index f30c6f52e..abb61cf84 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .32 -LINUX_KERNEL_HASH-6.12.32 = a9b020721778384507010177d3929e7d4058f7f6120f05a99d56b5c5c0346a70 +LINUX_VERSION-6.12 = .33 +LINUX_KERNEL_HASH-6.12.33 = c0a575630f2603a20bb0641f8df8f955e46c9d7ac1fae8b54b21316e6b52a254 From da12fa1fd5a36f7d47bf5400f0c9bae7bbac6eac Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Jun 2025 20:43:58 +0800 Subject: [PATCH 248/425] mt76: fix build for mediatek/filogic Signed-off-by: sbwml --- ...ix-build-with-mac80211-6.11-backport.patch | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch index 3d93637db..910a8bd3b 100644 --- a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +++ b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch @@ -74,6 +74,32 @@ wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) #define DEV_PR_FMT "%s" #define DEV_PR_ARG __entry->wiphy_name +--- a/mt7915/soc.c ++++ b/mt7915/soc.c +@@ -1283,13 +1283,11 @@ free_device: + return ret; + } + +-static int mt798x_wmac_remove(struct platform_device *pdev) ++static void mt798x_wmac_remove(struct platform_device *pdev) + { + struct mt7915_dev *dev = platform_get_drvdata(pdev); + + mt7915_unregister_device(dev); +- +- return 0; + } + + static const struct of_device_id mt798x_wmac_of_match[] = { +@@ -1306,7 +1304,7 @@ struct platform_driver mt798x_wmac_drive + .of_match_table = mt798x_wmac_of_match, + }, + .probe = mt798x_wmac_probe, +- .remove = mt798x_wmac_remove, ++ .remove_new = mt798x_wmac_remove, + }; + + MODULE_FIRMWARE(MT7986_FIRMWARE_WA); --- a/trace.h +++ b/trace.h @@ -14,7 +14,7 @@ From c2b375ad006b4a93f9cf9a923d28433f790153a1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Jun 2025 20:45:57 +0800 Subject: [PATCH 249/425] config-common: drop luci-app-alist package Signed-off-by: sbwml --- openwrt/24-config-common | 2 -- openwrt/24-config-minimal-common | 1 - openwrt/24-config-musl-r8500 | 5 +---- openwrt/24-config-musl-r8500-minimal | 5 +---- openwrt/scripts/02-prepare_package.sh | 8 ++------ 5 files changed, 4 insertions(+), 17 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 1bd2b0ea3..b764dcb2d 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -95,7 +95,6 @@ CONFIG_NGINX_STREAM_REAL_IP=y ### APPS CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y -CONFIG_PACKAGE_luci-app-alist=y CONFIG_PACKAGE_luci-app-argon-config=y CONFIG_PACKAGE_luci-app-aria2=y CONFIG_PACKAGE_luci-app-autoreboot=y @@ -141,7 +140,6 @@ CONFIG_PACKAGE_luci-app-passwall_INCLUDE_ShadowsocksR_Libev_Client=y CONFIG_PACKAGE_luci-app-passwall_INCLUDE_SingBox=y CONFIG_PACKAGE_luci-app-passwall_INCLUDE_V2ray_Geodata=y CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Xray_Plugin=y -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Brook is not set # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Hysteria is not set # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Libev_Server is not set # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_tuic_client is not set diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index f1a030e16..c92ee8dc9 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -85,7 +85,6 @@ CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y -CONFIG_PACKAGE_luci-app-webdav=y ### DDNS Scripts CONFIG_PACKAGE_ddns-scripts=y diff --git a/openwrt/24-config-musl-r8500 b/openwrt/24-config-musl-r8500 index 7c31409f0..1bf957c84 100644 --- a/openwrt/24-config-musl-r8500 +++ b/openwrt/24-config-musl-r8500 @@ -46,9 +46,7 @@ CONFIG_PACKAGE_kmod-shortcut-fe-cm=y ### Zram CONFIG_PACKAGE_zram-swap=y -CONFIG_PACKAGE_kmod-lib-lz4=y -CONFIG_PACKAGE_kmod-lib-lzo=y -CONFIG_PACKAGE_kmod-lib-zstd=y +CONFIG_ZRAM_DEF_COMP_LZ4=y ### Busybox CONFIG_BUSYBOX_CUSTOM=y @@ -128,7 +126,6 @@ CONFIG_PACKAGE_luci-app-passwall=y CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Libev_Client=y CONFIG_PACKAGE_luci-app-passwall_INCLUDE_V2ray_Geodata=y CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Xray_Plugin=y -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Brook is not set # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Hysteria is not set # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_NaiveProxy is not set # CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Libev_Server is not set diff --git a/openwrt/24-config-musl-r8500-minimal b/openwrt/24-config-musl-r8500-minimal index 96e119ab6..0425b112c 100644 --- a/openwrt/24-config-musl-r8500-minimal +++ b/openwrt/24-config-musl-r8500-minimal @@ -46,9 +46,7 @@ CONFIG_PACKAGE_kmod-shortcut-fe-cm=y ### Zram CONFIG_PACKAGE_zram-swap=y -CONFIG_PACKAGE_kmod-lib-lz4=y -CONFIG_PACKAGE_kmod-lib-lzo=y -CONFIG_PACKAGE_kmod-lib-zstd=y +CONFIG_ZRAM_DEF_COMP_LZ4=y ### Busybox CONFIG_BUSYBOX_CUSTOM=y @@ -98,7 +96,6 @@ CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y -CONFIG_PACKAGE_luci-app-webdav=y ### DDNS Scripts CONFIG_PACKAGE_ddns-scripts=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index ec54057b0..a22eeac89 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -105,10 +105,6 @@ git clone https://github.com/sbwml/package_new_nethogs package/new/nethogs rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 -# alist -rm -rf feeds/packages/net/alist feeds/luci/applications/luci-app-alist -git clone https://$github/sbwml/openwrt-alist package/new/alist - # netdata sed -i 's/syslog/none/g' feeds/packages/admin/netdata/files/netdata.conf @@ -156,8 +152,8 @@ sed -i 's/<%:Down%>/<%:Move down%>/g' feeds/luci/modules/luci-compat/luasrc/view # frpc translation sed -i 's,发送,Transmission,g' feeds/luci/applications/luci-app-transmission/po/zh_Hans/transmission.po -sed -i 's,frp 服务器,FRP 服务器,g' feeds/luci/applications/luci-app-frps/po/zh_Hans/frps.po -sed -i 's,frp 客户端,FRP 客户端,g' feeds/luci/applications/luci-app-frpc/po/zh_Hans/frpc.po +sed -i 's,frp 服务器,Frp 服务器,g' feeds/luci/applications/luci-app-frps/po/zh_Hans/frps.po +sed -i 's,frp 客户端,Frp 客户端,g' feeds/luci/applications/luci-app-frpc/po/zh_Hans/frpc.po # luci-app-sqm rm -rf feeds/luci/applications/luci-app-sqm From 114a782df768d6e41dc5ac6a64870064a061691c Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 17 Jun 2025 02:45:39 +0800 Subject: [PATCH 250/425] package: add luci-app-openlist Signed-off-by: sbwml --- openwrt/24-config-common | 1 + openwrt/build.sh | 1 - openwrt/scripts/02-prepare_package.sh | 3 +++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index b764dcb2d..cf3b11447 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -111,6 +111,7 @@ CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y CONFIG_PACKAGE_luci-app-oaf=y +# CONFIG_PACKAGE_luci-app-openlist is not set CONFIG_PACKAGE_luci-app-qbittorrent=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-samba4=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 1caa43713..c9c49d102 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -252,7 +252,6 @@ chmod 0755 *sh bash 00-prepare_base.sh bash 01-prepare_base-mainline.sh bash 02-prepare_package.sh -bash 03-convert_translation.sh bash 04-fix_kmod.sh bash 05-fix-source.sh [ -f "10-custom.sh" ] && bash 10-custom.sh diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index a22eeac89..ed6ba529e 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -105,6 +105,9 @@ git clone https://github.com/sbwml/package_new_nethogs package/new/nethogs rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 +# openlist +git clone https://$github/sbwml/luci-app-openlist package/new/openlist + # netdata sed -i 's/syslog/none/g' feeds/packages/admin/netdata/files/netdata.conf From 73b5772bc2e432c28594181679f42fd3b8584d22 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Jun 2025 20:15:00 +0800 Subject: [PATCH 251/425] golang: update to 1.25.x Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index ed6ba529e..f0ecf3972 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -1,8 +1,8 @@ #!/bin/bash -e -# golang 1.24 +# golang 1.25 rm -rf feeds/packages/lang/golang -git clone https://$github/sbwml/packages_lang_golang -b 24.x feeds/packages/lang/golang +git clone https://$github/sbwml/packages_lang_golang -b 25.x feeds/packages/lang/golang # node - prebuilt rm -rf feeds/packages/lang/node From 7d610382832b24cc982f0d3b9b39d9e0646ca2e8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Jun 2025 20:15:32 +0800 Subject: [PATCH 252/425] config-conmon: add luci-app-openlist Signed-off-by: sbwml --- openwrt/24-config-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index cf3b11447..3a6bb8447 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -111,7 +111,7 @@ CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y CONFIG_PACKAGE_luci-app-oaf=y -# CONFIG_PACKAGE_luci-app-openlist is not set +CONFIG_PACKAGE_luci-app-openlist=y CONFIG_PACKAGE_luci-app-qbittorrent=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-samba4=y From 5fa8ae582e4ba9c97caacd524867962b91433eb6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Jun 2025 20:15:58 +0800 Subject: [PATCH 253/425] linux-6.12: bump to 6.12.34 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index abb61cf84..dbe7bc857 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .33 -LINUX_KERNEL_HASH-6.12.33 = c0a575630f2603a20bb0641f8df8f955e46c9d7ac1fae8b54b21316e6b52a254 +LINUX_VERSION-6.12 = .34 +LINUX_KERNEL_HASH-6.12.34 = a7f3fe381f67eca4172e9b63efb61a14bd7f9e1278e03603d0ff5a93f270c24d From 478f2842e28f32b3ab14af89f9f6578a53b6160c Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 24 Jun 2025 20:16:18 +0800 Subject: [PATCH 254/425] OpenWrt 24.10.2 Signed-off-by: sbwml --- tags/v24 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v24 b/tags/v24 index 169a8dd89..957950647 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.1 +24.10.2 From 77839bdf473972c6d6364e75156640bec548232d Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 3 Jul 2025 14:57:55 +0800 Subject: [PATCH 255/425] linux-6.12: bump to 6.12.35 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index dbe7bc857..91260b8a1 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .34 -LINUX_KERNEL_HASH-6.12.34 = a7f3fe381f67eca4172e9b63efb61a14bd7f9e1278e03603d0ff5a93f270c24d +LINUX_VERSION-6.12 = .35 +LINUX_KERNEL_HASH-6.12.35 = 05f4e0b01dde578c3328eb539d305cccec7b84e939f6dd5f21fdaf5f313da748 From 4af72134aaa282f910ca29fa2f44398f299b9aba Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 3 Jul 2025 14:58:27 +0800 Subject: [PATCH 256/425] dockerd: remove obsolete patches Signed-off-by: sbwml --- .../0001-dockerd-fix-bridge-network.patch | 35 ------------ ...er-add-buildkit-experimental-support.patch | 53 ------------------- openwrt/scripts/00-prepare_base.sh | 6 --- openwrt/scripts/02-prepare_package.sh | 18 +++---- 4 files changed, 9 insertions(+), 103 deletions(-) delete mode 100644 openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch delete mode 100644 openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch diff --git a/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch b/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch deleted file mode 100644 index 1c357dad2..000000000 --- a/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 52fd8d3590e62a7a1949e1236cce362fbd7f33c6 Mon Sep 17 00:00:00 2001 -From: sbwml <984419930@qq.com> -Date: Fri, 9 Dec 2022 13:01:48 +0800 -Subject: [PATCH] dockerd: fix bridge network - ---- - utils/dockerd/files/dockerd.init | 3 +++ - utils/dockerd/files/etc/config/dockerd | 2 +- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/utils/dockerd/files/dockerd.init b/utils/dockerd/files/dockerd.init -index 8835a6d..ec83ec5 100755 ---- a/utils/dockerd/files/dockerd.init -+++ b/utils/dockerd/files/dockerd.init -@@ -91,6 +91,9 @@ uciadd() { - uci_quiet set firewall.@zone[-1].output="ACCEPT" - uci_quiet set firewall.@zone[-1].forward="ACCEPT" - uci_quiet set firewall.@zone[-1].name="${zone}" -+ uci_quiet set firewall.dockerd=forwarding -+ uci_quiet set firewall.@forwarding[-1].src="${zone}" -+ uci_quiet set firewall.@forwarding[-1].dest='wan' - uci_quiet commit firewall - fi - -diff --git a/utils/dockerd/files/etc/config/dockerd b/utils/dockerd/files/etc/config/dockerd -index 0fa4a56..03fdcf8 100644 ---- a/utils/dockerd/files/etc/config/dockerd -+++ b/utils/dockerd/files/etc/config/dockerd -@@ -41,5 +41,5 @@ config proxies 'proxies' - # then docker restarted to load in new changes. - config firewall 'firewall' - option device 'docker0' -- list blocked_interfaces 'wan' -+# list blocked_interfaces 'wan' - # option extra_iptables_args '--match conntrack ! --ctstate RELATED,ESTABLISHED' # allow outbound connections diff --git a/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch b/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch deleted file mode 100644 index 56394f2b2..000000000 --- a/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 342451357cc3718748d4a2fed40b480044adb1a7 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 3 Apr 2024 02:38:08 +0800 -Subject: [PATCH] docker: add buildkit & experimental support - -Signed-off-by: sbwml ---- - utils/dockerd/files/dockerd.init | 8 ++++++++ - utils/dockerd/files/etc/config/dockerd | 2 ++ - 2 files changed, 10 insertions(+) - -diff --git a/utils/dockerd/files/dockerd.init b/utils/dockerd/files/dockerd.init -index ec83ec5..5762c11 100755 ---- a/utils/dockerd/files/dockerd.init -+++ b/utils/dockerd/files/dockerd.init -@@ -193,6 +193,8 @@ process_config() { - config_get https_proxy proxies https_proxy "${https_proxy}" - config_get no_proxy proxies no_proxy "${no_proxy}" - config_get storage_driver globals storage_driver "" -+ config_get buildkit globals buildkit "0" -+ config_get experimental globals experimental "0" - - . /usr/share/libubox/jshn.sh - json_init -@@ -200,6 +202,12 @@ process_config() { - json_add_string "log-level" "${log_level}" - json_add_boolean "iptables" "${iptables}" - json_add_boolean "ip6tables" "${ip6tables}" -+ [ "${buildkit}" = "1" ] && { -+ json_add_object 'features' -+ json_add_boolean "buildkit" "${buildkit}" -+ json_close_object -+ } -+ [ "${experimental}" = "1" ] && json_add_boolean "experimental" "${experimental}" - [ -z "${log_driver}" ] || json_add_string "log-driver" "${log_driver}" - [ -z "${bip}" ] || json_add_string "bip" "${bip}" - [ -z "${registry_mirrors}" ] || json_add_array "registry-mirrors" -diff --git a/utils/dockerd/files/etc/config/dockerd b/utils/dockerd/files/etc/config/dockerd -index 03fdcf8..8cb08fc 100644 ---- a/utils/dockerd/files/etc/config/dockerd -+++ b/utils/dockerd/files/etc/config/dockerd -@@ -20,6 +20,8 @@ config globals 'globals' - # list dns '172.17.0.1' - # list registry_mirrors 'https://' - # list registry_mirrors 'https://hub.docker.com' -+ option buildkit '0' -+ option experimental '0' - - # If your organization uses a proxy server to connect to the internet, you may need to configure the proxy. - # See https://docs.docker.com/engine/daemon/proxy/ for more details --- -2.42.0 - diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 39d24f7e7..fd1c6d76f 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -246,13 +246,7 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd git clone https://$github/sbwml/packages_utils_containerd feeds/packages/utils/containerd git clone https://$github/sbwml/packages_utils_runc feeds/packages/utils/runc - sed -i '/cgroupfs-mount/d' feeds/packages/utils/dockerd/Config.in fi -sed -i '/sysctl.d/d' feeds/packages/utils/dockerd/Makefile -pushd feeds/packages - curl -s $mirror/openwrt/patch/docker/0001-dockerd-fix-bridge-network.patch | patch -p1 - curl -s $mirror/openwrt/patch/docker/0002-docker-add-buildkit-experimental-support.patch | patch -p1 -popd # cgroupfs-mount # fix unmount hierarchical mount diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index f0ecf3972..2574d9744 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -12,14 +12,14 @@ git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages git clone https://$github/sbwml/default-settings package/new/default-settings -b openwrt-24.10 # wwan -git clone https://github.com/sbwml/wwan-packages package/new/wwan +git clone https://$github/sbwml/wwan-packages package/new/wwan --depth=1 # luci-app-filemanager rm -rf feeds/luci/applications/luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager # luci-app-airplay2 -git clone https://github.com/sbwml/luci-app-airplay2 package/new/airplay2 +git clone https://$github/sbwml/luci-app-airplay2 package/new/airplay2 # luci-app-webdav git clone https://$github/sbwml/luci-app-webdav package/new/luci-app-webdav @@ -93,36 +93,36 @@ rm -rf feeds/packages/net/aria2 git clone https://$github/sbwml/feeds_packages_net_aria2 -b 22.03 feeds/packages/net/aria2 # airconnect -git clone https://$github/sbwml/luci-app-airconnect package/new/airconnect +git clone https://$github/sbwml/luci-app-airconnect package/new/airconnect --depth=1 # netkit-ftp git clone https://$github/sbwml/package_new_ftp package/new/ftp # nethogs -git clone https://github.com/sbwml/package_new_nethogs package/new/nethogs +git clone https://$github/sbwml/package_new_nethogs package/new/nethogs # SSRP & Passwall rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 # openlist -git clone https://$github/sbwml/luci-app-openlist package/new/openlist +git clone https://$github/sbwml/luci-app-openlist package/new/openlist --depth=1 # netdata sed -i 's/syslog/none/g' feeds/packages/admin/netdata/files/netdata.conf # qBittorrent -git clone https://$github/sbwml/luci-app-qbittorrent package/new/qbittorrent +git clone https://$github/sbwml/luci-app-qbittorrent package/new/qbittorrent --depth=1 # unblockneteasemusic -git clone https://$github/UnblockNeteaseMusic/luci-app-unblockneteasemusic package/new/luci-app-unblockneteasemusic +git clone https://$github/UnblockNeteaseMusic/luci-app-unblockneteasemusic package/new/luci-app-unblockneteasemusic --depth=1 sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new/luci-app-unblockneteasemusic/root/usr/share/luci/menu.d/luci-app-unblockneteasemusic.json # Theme -git clone --depth 1 https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon +git clone --depth 1 https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon --depth=1 # Mosdns -git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns +git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 # OpenAppFilter git clone https://$github/sbwml/OpenAppFilter --depth=1 package/new/OpenAppFilter From 6b7b9e9a936fc12ad3e7192728f81e935a1e7c63 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 7 Jul 2025 10:27:36 +0800 Subject: [PATCH 257/425] package: add luci-app-quickfile Signed-off-by: sbwml --- openwrt/24-config-common | 2 +- openwrt/scripts/02-prepare_package.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 3a6bb8447..d99cccbf7 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -103,7 +103,7 @@ CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y -CONFIG_PACKAGE_luci-app-filemanager=y +CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-frpc=y CONFIG_PACKAGE_luci-app-mentohust=y CONFIG_PACKAGE_luci-app-mosdns=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 2574d9744..df160ea47 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -18,6 +18,9 @@ git clone https://$github/sbwml/wwan-packages package/new/wwan --depth=1 rm -rf feeds/luci/applications/luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager +# luci-app-quickfile +git clone https://$github/sbwml/luci-app-quickfile package/new/quickfile + # luci-app-airplay2 git clone https://$github/sbwml/luci-app-airplay2 package/new/airplay2 From c70184f588207e4a90d4905af911345974723376 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 7 Jul 2025 10:28:21 +0800 Subject: [PATCH 258/425] build.sh: add openwrt code cn mirror Signed-off-by: sbwml --- openwrt/build.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index c9c49d102..b53c35a2b 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -48,14 +48,16 @@ if [ "$(whoami)" = "runner" ] && [ "$git_name" != "private" ]; then fi # private gitea -export gitea=git.cooluc.com +export gitea="git.cooluc.com" # github mirror if [ "$isCN" = "CN" ]; then # There is currently no stable gh proxy export github="github.com" + code_mirror="git.cooluc.com" else export github="github.com" + code_mirror="github.com" fi # Check root @@ -177,7 +179,7 @@ rm -rf openwrt master # openwrt - releases [ "$(whoami)" = "runner" ] && group "source code" -git clone --depth=1 https://$github/openwrt/openwrt -b $branch +git clone --depth=1 https://$code_mirror/openwrt/openwrt -b $branch # immortalwrt master git clone https://$github/immortalwrt/packages master/immortalwrt_packages --depth=1 @@ -211,10 +213,10 @@ else telephony=";$branch" fi cat > feeds.conf < Date: Mon, 7 Jul 2025 10:32:43 +0800 Subject: [PATCH 259/425] linux-6.12: bump to 6.12.36 Signed-off-by: sbwml --- ...br-broaden-app-limited-rate-sample-detectio.patch | 2 +- ...br-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch | 2 +- ...br-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch | 2 +- ...br-v2-adjust-skb-tx.in_flight-upon-merge-in.patch | 2 +- ...dd-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch | 2 +- ...br-v2-inform-CC-module-of-losses-repaired-b.patch | 2 +- ...br-v2-introduce-is_acking_tlp_retrans_seq-i.patch | 8 ++++---- ...NG-0012-scheduler-add-entropy-sampling-hook.patch | 2 +- ...t-patch-linux-kernel-to-support-shortcut-fe.patch | 12 ++++++------ .../net/983-add-bcm-fullcone-nft_masq-support.patch | 2 +- tags/kernel-6.12 | 4 ++-- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index a50a97df0..736b718a7 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -32,7 +32,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3983,6 +3983,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -3992,6 +3992,7 @@ static int tcp_ack(struct sock *sk, cons prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; rs.prior_in_flight = tcp_packets_in_flight(tp); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index dd03edc9d..a1ac02d76 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -28,7 +28,7 @@ Signed-off-by: Alexandre Frade struct tcp_congestion_ops { --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4073,6 +4073,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4082,6 +4082,7 @@ static int tcp_ack(struct sock *sk, cons delivered = tcp_newly_delivered(sk, delivered, flag); lost = tp->lost - lost; /* freshly marked lost */ rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index c83072f3c..cd225523e 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1140,7 +1140,12 @@ static void tcp_verify_retransmit_hint(s +@@ -1136,7 +1136,12 @@ static void tcp_verify_retransmit_hint(s */ static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) { diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch index a915ec403..e97e7abe9 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch @@ -39,7 +39,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1517,6 +1517,17 @@ static bool tcp_shifted_skb(struct sock +@@ -1513,6 +1513,17 @@ static bool tcp_shifted_skb(struct sock WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); tcp_skb_pcount_add(skb, -pcount); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index e64af261e..39f15b4a1 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5784,13 +5784,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5793,13 +5793,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index a4288b085..543d3b468 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3870,6 +3870,7 @@ static void tcp_process_tlp_ack(struct s +@@ -3879,6 +3879,7 @@ static void tcp_process_tlp_ack(struct s /* ACK advances: there was a loss, so reduce cwnd. Reset * tlp_high_seq in tcp_init_cwnd_reduction() */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index f4ed58e7f..b6e0d063d 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3853,7 +3853,8 @@ static void tcp_replace_ts_recent(struct +@@ -3862,7 +3862,8 @@ static void tcp_replace_ts_recent(struct /* This routine deals with acks during a TLP episode and ends an episode by * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack */ @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade { struct tcp_sock *tp = tcp_sk(sk); -@@ -3881,6 +3882,11 @@ static void tcp_process_tlp_ack(struct s +@@ -3890,6 +3891,11 @@ static void tcp_process_tlp_ack(struct s FLAG_NOT_DUP | FLAG_DATA_SACKED))) { /* Pure dupack: original and TLP probe arrived; no loss */ tp->tlp_high_seq = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade } } -@@ -4066,7 +4072,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4075,7 +4081,7 @@ static int tcp_ack(struct sock *sk, cons tcp_in_ack_event(sk, flag); if (tp->tlp_high_seq) @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade if (tcp_ack_is_dubious(sk, flag)) { if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4111,7 +4117,7 @@ no_queue: +@@ -4120,7 +4126,7 @@ no_queue: tcp_ack_probe(sk); if (tp->tlp_high_seq) diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch index e75139bbf..686dd485c 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ b/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -24,7 +24,7 @@ Signed-off-by: Stephan Mueller #include #include #include -@@ -3613,6 +3614,8 @@ ttwu_stat(struct task_struct *p, int cpu +@@ -3620,6 +3621,8 @@ ttwu_stat(struct task_struct *p, int cpu { struct rq *rq; diff --git a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 08a9c9c08..40dea69c3 100644 --- a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -52,7 +52,7 @@ Signed-off-by: Xiaoping Fan const struct nf_ct_event_notifier *nb); --- a/net/Kconfig +++ b/net/Kconfig -@@ -512,6 +512,9 @@ config FAILOVER +@@ -518,6 +518,9 @@ config FAILOVER migration of VMs with direct attached VFs by failing over to the paravirtual datapath when the VF is unplugged. @@ -109,9 +109,9 @@ Signed-off-by: Xiaoping Fan + } +#endif - len = skb->len; - trace_net_dev_start_xmit(skb, dev); -@@ -5485,6 +5494,11 @@ void netdev_rx_handler_unregister(struct + #ifdef CONFIG_ETHERNET_PACKET_MANGLE + if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) +@@ -5493,6 +5502,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5533,6 +5547,10 @@ static int __netif_receive_skb_core(stru +@@ -5541,6 +5555,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5571,6 +5589,16 @@ another_round: +@@ -5579,6 +5597,16 @@ another_round: goto out; } diff --git a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch index 160fd3fb5..f9ad88e36 100644 --- a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -30,7 +30,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -11152,6 +11152,24 @@ static int nft_validate_register_load(en +@@ -11153,6 +11153,24 @@ static int nft_validate_register_load(en return 0; } diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 91260b8a1..536c404c2 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .35 -LINUX_KERNEL_HASH-6.12.35 = 05f4e0b01dde578c3328eb539d305cccec7b84e939f6dd5f21fdaf5f313da748 +LINUX_VERSION-6.12 = .36 +LINUX_KERNEL_HASH-6.12.36 = 4a168aed2de5a81aadd90ba2b153860a98d99bfc34651936e17f18e54f01ba8c From 2d12557f920f17228183b82fbb81226eff97075d Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 7 Jul 2025 13:58:17 +0800 Subject: [PATCH 260/425] modules: fix kmod-hwmon-lm92 dependencies Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/hwmon.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index 6978c5df9..913d139d7 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -362,7 +362,7 @@ define KernelPackage/hwmon-lm92 KCONFIG:=CONFIG_SENSORS_LM92 FILES:=$(LINUX_DIR)/drivers/hwmon/lm92.ko AUTOLOAD:=$(call AutoProbe,lm92) - $(call AddDepends/hwmon,+kmod-i2c-core) + $(call AddDepends/hwmon,+kmod-i2c-core +kmod-regmap-core) endef define KernelPackage/hwmon-lm92/description From 3bfdf3e2bed81b15a4779af0c1d0352f6e97fd8a Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 7 Jul 2025 17:05:47 +0800 Subject: [PATCH 261/425] modules: fix kmod-hwmon-sch5627 dependencies Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/hwmon.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index 913d139d7..09a077fde 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -548,7 +548,7 @@ define KernelPackage/hwmon-sch5627 $(LINUX_DIR)/drivers/hwmon/sch5627.ko \ $(LINUX_DIR)/drivers/hwmon/sch56xx-common.ko AUTOLOAD:=$(call AutoProbe,sch5627) - $(call AddDepends/hwmon,+kmod-i2c-core) + $(call AddDepends/hwmon,+kmod-i2c-core +kmod-regmap-core) endef define KernelPackage/hwmon-sch5627/description From 6d105c6b55f7a4e1c61905f245200aa9fb7736a6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Jul 2025 01:00:37 +0800 Subject: [PATCH 262/425] linux-6.12: bump to 6.12.37 & mac80211: update to 6.15.6 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 2 +- tags/kernel-6.12 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 91f708ac5..03ab2a80f 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -187,7 +187,7 @@ curl -s $mirror/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-back # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - 6.15 +# mac80211 - 6.15.6 rm -rf package/kernel/mac80211 git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 536c404c2..e40f0f569 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .36 -LINUX_KERNEL_HASH-6.12.36 = 4a168aed2de5a81aadd90ba2b153860a98d99bfc34651936e17f18e54f01ba8c +LINUX_VERSION-6.12 = .37 +LINUX_KERNEL_HASH-6.12.37 = 936fdfd2405b5e0ac38d4e094b07772610c22cd478f4bb257c9bf929e762ff95 From 96d4c481a9d45d8f77c589d9e8d1885b9b419f19 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Jul 2025 11:27:49 +0800 Subject: [PATCH 263/425] openssl: refresh patches for 3.0.17 Signed-off-by: sbwml --- ...-Add-support-for-BoringSSL-QUIC-APIs.patch | 23 ++++++++++--------- ...-quic_transport-constructors-parsers.patch | 4 ++-- ...ndle-EndOfEarlyData-and-MaxEarlyData.patch | 2 +- ...me-cleanup-for-the-main-QUIC-changes.patch | 8 +++---- .../0022-QUIC-Test-KeyUpdate-rejection.patch | 2 +- ...UIC-add-v1-quic_transport_parameters.patch | 18 +++++++-------- ...-remove-SSL_R_BAD_DATA_LENGTH-unused.patch | 2 +- .../0031-QUIC-Add-early-data-support.patch | 6 ++--- ...tiple-post-handshake-messages-in-a-s.patch | 4 ++-- .../patch/openssl/quic/0034-QUIC-Fix-CI.patch | 6 ++--- .../0037-QUIC-Update-RFC-references.patch | 2 +- ...-Update-SSL_clear-to-clear-quic-data.patch | 10 ++++---- .../quic/0042-QUIC-Better-SSL_clear.patch | 10 ++++---- openwrt/scripts/00-prepare_base.sh | 5 ++++ 14 files changed, 54 insertions(+), 48 deletions(-) diff --git a/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch b/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch index 9c197f286..f66140741 100644 --- a/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch +++ b/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch @@ -53,7 +53,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 --- a/Configure +++ b/Configure -@@ -467,6 +467,7 @@ my @disablables = ( +@@ -468,6 +468,7 @@ my @disablables = ( "poly1305", "posix-io", "psk", @@ -61,7 +61,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 "rc2", "rc4", "rc5", -@@ -635,6 +636,7 @@ my @disable_cascades = ( +@@ -636,6 +637,7 @@ my @disable_cascades = ( "legacy" => [ "md2" ], "cmp" => [ "crmf" ], @@ -84,7 +84,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 Don't use hardware RDRAND capabilities. --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt -@@ -1251,6 +1251,7 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_ +@@ -1253,6 +1253,7 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_ SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec SSL_R_BAD_CIPHER:186:bad cipher SSL_R_BAD_DATA:390:bad data @@ -92,7 +92,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback SSL_R_BAD_DECOMPRESSION:107:bad decompression SSL_R_BAD_DH_VALUE:102:bad dh value -@@ -1538,6 +1539,7 @@ SSL_R_VERSION_TOO_LOW:396:version too lo +@@ -1540,6 +1541,7 @@ SSL_R_VERSION_TOO_LOW:396:version too lo SSL_R_WRONG_CERTIFICATE_TYPE:383:wrong certificate type SSL_R_WRONG_CIPHER_RETURNED:261:wrong cipher returned SSL_R_WRONG_CURVE:378:wrong curve @@ -1103,7 +1103,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 +#endif --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1237,6 +1237,33 @@ int tls_parse_ctos_post_handshake_auth(S +@@ -1249,6 +1249,33 @@ int tls_parse_ctos_post_handshake_auth(S return 1; } @@ -1137,7 +1137,7 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 /* * Add the server's renegotiation binding */ -@@ -1920,3 +1947,27 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s +@@ -1932,3 +1959,27 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s return EXT_RETURN_SENT; } @@ -1554,10 +1554,10 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 * This will ensure we have received the NewSessionTicket in TLSv1.3 where --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10764,6 +10764,134 @@ static int test_multi_resume(int idx) - SSL_SESSION_free(sess); +@@ -10765,6 +10765,135 @@ static int test_multi_resume(int idx) return testresult; } + +#ifndef OPENSSL_NO_QUIC +static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, + const uint8_t *read_secret, @@ -1686,13 +1686,14 @@ Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 + return testresult; +} +#endif /* OPENSSL_NO_QUIC */ - ++ static struct next_proto_st { int serverlen; -@@ -11407,6 +11535,9 @@ int setup_tests(void) - ADD_ALL_TESTS(test_npn, 5); + unsigned char server[40]; +@@ -11482,6 +11611,9 @@ int setup_tests(void) #endif ADD_ALL_TESTS(test_alpn, 4); + ADD_ALL_TESTS(test_no_renegotiation, 2); +#ifndef OPENSSL_NO_QUIC + ADD_TEST(test_quic_api); +#endif diff --git a/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch b/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch index 7cccda434..6200042f1 100644 --- a/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch +++ b/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch @@ -46,7 +46,7 @@ Subject: [PATCH 07/43] QUIC: Fix quic_transport constructors/parsers SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1242,19 +1242,11 @@ int tls_parse_ctos_post_handshake_auth(S +@@ -1254,19 +1254,11 @@ int tls_parse_ctos_post_handshake_auth(S int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { @@ -67,7 +67,7 @@ Subject: [PATCH 07/43] QUIC: Fix quic_transport constructors/parsers &s->ext.peer_quic_transport_params, &s->ext.peer_quic_transport_params_len)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -@@ -1960,10 +1952,8 @@ EXT_RETURN tls_construct_stoc_quic_trans +@@ -1972,10 +1964,8 @@ EXT_RETURN tls_construct_stoc_quic_trans } if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) diff --git a/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch b/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch index 1c33b23d0..bb9370d8a 100644 --- a/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch +++ b/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch @@ -32,7 +32,7 @@ Subject: [PATCH 18/43] QUIC: Handle EndOfEarlyData and MaxEarlyData return 1; --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1896,12 +1896,20 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1908,12 +1908,20 @@ EXT_RETURN tls_construct_stoc_early_data size_t chainidx) { if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) { diff --git a/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch b/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch index ff12006d2..4be49613e 100644 --- a/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch +++ b/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch @@ -315,7 +315,7 @@ Update referenced I-D versions. SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1902,7 +1902,7 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1914,7 +1914,7 @@ EXT_RETURN tls_construct_stoc_early_data return EXT_RETURN_NOT_SENT; #ifndef OPENSSL_NO_QUIC @@ -598,9 +598,9 @@ Update referenced I-D versions. unsigned char *iv; --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10765,9 +10765,11 @@ static int test_multi_resume(int idx) - return testresult; +@@ -10766,9 +10766,11 @@ static int test_multi_resume(int idx) } + #ifndef OPENSSL_NO_QUIC -static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, +static int test_quic_set_encryption_secrets(SSL *ssl, @@ -612,7 +612,7 @@ Update referenced I-D versions. { test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n", ssl->server ? "server" : "client", level, secret_len); -@@ -10779,11 +10781,12 @@ static int test_quic_add_handshake_data( +@@ -10780,11 +10782,12 @@ static int test_quic_add_handshake_data( { SSL *peer = (SSL*)SSL_get_app_data(ssl); diff --git a/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch b/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch index 03f5ef565..8d252fca0 100644 --- a/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch +++ b/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch @@ -12,7 +12,7 @@ integrated into the TLSProxy setup. --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10889,6 +10889,17 @@ static int test_quic_api(void) +@@ -10890,6 +10890,17 @@ static int test_quic_api(void) || !TEST_true(SSL_process_quic_post_handshake(clientssl))) goto end; diff --git a/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch b/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch index 44ff85d70..952e835b2 100644 --- a/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch +++ b/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch @@ -23,7 +23,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt -@@ -1389,6 +1389,8 @@ SSL_R_MISSING_ECDSA_SIGNING_CERT:381:mis +@@ -1391,6 +1391,8 @@ SSL_R_MISSING_ECDSA_SIGNING_CERT:381:mis SSL_R_MISSING_FATAL:256:missing fatal SSL_R_MISSING_PARAMETERS:290:missing parameters SSL_R_MISSING_PSK_KEX_MODES_EXTENSION:310:missing psk kex modes extension @@ -359,7 +359,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters { --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1238,7 +1238,22 @@ int tls_parse_ctos_post_handshake_auth(S +@@ -1250,7 +1250,22 @@ int tls_parse_ctos_post_handshake_auth(S } #ifndef OPENSSL_NO_QUIC @@ -383,7 +383,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { -@@ -1949,13 +1964,36 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s +@@ -1961,13 +1976,36 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s } #ifndef OPENSSL_NO_QUIC @@ -472,7 +472,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters #endif --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10815,7 +10815,13 @@ static SSL_QUIC_METHOD quic_method = { +@@ -10816,7 +10816,13 @@ static SSL_QUIC_METHOD quic_method = { test_quic_send_alert, }; @@ -487,7 +487,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; -@@ -10826,29 +10832,7 @@ static int test_quic_api(void) +@@ -10827,29 +10833,7 @@ static int test_quic_api(void) const uint8_t *peer_str; size_t peer_str_len; @@ -518,7 +518,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -10867,6 +10851,8 @@ static int test_quic_api(void) +@@ -10868,6 +10852,8 @@ static int test_quic_api(void) sizeof(client_str))) || !TEST_true(SSL_set_app_data(serverssl, clientssl)) || !TEST_true(SSL_set_app_data(clientssl, serverssl)) @@ -527,7 +527,7 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) -@@ -10900,11 +10886,85 @@ static int test_quic_api(void) +@@ -10901,11 +10887,85 @@ static int test_quic_api(void) || !TEST_int_le(SSL_do_handshake(serverssl), 0)) goto end; @@ -613,9 +613,9 @@ Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters #endif /* OPENSSL_NO_QUIC */ static struct next_proto_st { -@@ -11550,7 +11610,7 @@ int setup_tests(void) - #endif +@@ -11626,7 +11686,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_alpn, 4); + ADD_ALL_TESTS(test_no_renegotiation, 2); #ifndef OPENSSL_NO_QUIC - ADD_TEST(test_quic_api); + ADD_ALL_TESTS(test_quic_api, 9); diff --git a/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch b/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch index dda5f9ac6..4a922741b 100644 --- a/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch +++ b/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch @@ -11,7 +11,7 @@ Subject: [PATCH 28/43] QUIC: remove SSL_R_BAD_DATA_LENGTH (unused) --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt -@@ -1251,7 +1251,6 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_ +@@ -1253,7 +1253,6 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_ SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec SSL_R_BAD_CIPHER:186:bad cipher SSL_R_BAD_DATA:390:bad data diff --git a/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch b/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch index 818f4ca76..dde67aa6c 100644 --- a/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch +++ b/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch @@ -306,7 +306,7 @@ support to QUIC. ret = 1; --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10965,6 +10965,159 @@ end: +@@ -10966,6 +10966,159 @@ end: serverssl = NULL; return testresult; } @@ -466,8 +466,8 @@ support to QUIC. #endif /* OPENSSL_NO_QUIC */ static struct next_proto_st { -@@ -11611,6 +11764,9 @@ int setup_tests(void) - ADD_ALL_TESTS(test_alpn, 4); +@@ -11687,6 +11840,9 @@ int setup_tests(void) + ADD_ALL_TESTS(test_no_renegotiation, 2); #ifndef OPENSSL_NO_QUIC ADD_ALL_TESTS(test_quic_api, 9); +# ifndef OSSL_NO_USABLE_TLS1_3 diff --git a/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch b/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch index 84d7ff731..10654746c 100644 --- a/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch +++ b/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch @@ -46,7 +46,7 @@ Subject: [PATCH 33/43] QUIC: Process multiple post-handshake messages in a --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10871,8 +10871,7 @@ static int test_quic_api_version(int cln +@@ -10872,8 +10872,7 @@ static int test_quic_api_version(int cln goto end; /* Deal with two NewSessionTickets */ @@ -56,7 +56,7 @@ Subject: [PATCH 33/43] QUIC: Process multiple post-handshake messages in a goto end; /* Dummy handshake call should succeed */ -@@ -11059,8 +11058,7 @@ static int quic_setupearly_data_test(SSL +@@ -11060,8 +11059,7 @@ static int quic_setupearly_data_test(SSL return 0; /* Deal with two NewSessionTickets */ diff --git a/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch b/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch index 3675b0605..28914467b 100644 --- a/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch +++ b/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch @@ -15,7 +15,7 @@ Fixes an issue with extension defintions and `no-quic` --- a/Configure +++ b/Configure -@@ -578,6 +578,7 @@ my @disable_cascades = ( +@@ -579,6 +579,7 @@ my @disable_cascades = ( "sm3", "sm4", "srp", "srtp", "ssl3-method", "ssl-trace", "ts", "ui-console", "whirlpool", @@ -23,7 +23,7 @@ Fixes an issue with extension defintions and `no-quic` "fips-securitychecks" ], sub { $config{processor} eq "386" } => [ "sse2" ], -@@ -585,7 +586,7 @@ my @disable_cascades = ( +@@ -586,7 +587,7 @@ my @disable_cascades = ( "ssl3-method" => [ "ssl3" ], "zlib" => [ "zlib-dynamic" ], "des" => [ "mdc2" ], @@ -73,7 +73,7 @@ Fixes an issue with extension defintions and `no-quic` /* Must be immediately before pre_shared_key */ --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1918,7 +1918,7 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1930,7 +1930,7 @@ EXT_RETURN tls_construct_stoc_early_data #ifndef OPENSSL_NO_QUIC /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ diff --git a/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch b/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch index 272b2c0aa..f6d9674fd 100644 --- a/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch +++ b/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch @@ -77,7 +77,7 @@ Subject: [PATCH 37/43] QUIC: Update RFC references SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c -@@ -1917,7 +1917,7 @@ EXT_RETURN tls_construct_stoc_early_data +@@ -1929,7 +1929,7 @@ EXT_RETURN tls_construct_stoc_early_data return EXT_RETURN_NOT_SENT; #ifndef OPENSSL_NO_QUIC diff --git a/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch b/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch index 6d130e634..8d764eae5 100644 --- a/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch +++ b/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch @@ -69,7 +69,7 @@ from the server SSL. * This will ensure we have received the NewSessionTicket in TLSv1.3 where --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10831,6 +10831,7 @@ static int test_quic_api_version(int cln +@@ -10832,6 +10832,7 @@ static int test_quic_api_version(int cln static const char *client_str = "CLIENT"; const uint8_t *peer_str; size_t peer_str_len; @@ -77,7 +77,7 @@ from the server SSL. TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); -@@ -10853,8 +10854,10 @@ static int test_quic_api_version(int cln +@@ -10854,8 +10855,10 @@ static int test_quic_api_version(int cln || !TEST_true(SSL_set_app_data(clientssl, serverssl)) || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) @@ -90,7 +90,7 @@ from the server SSL. || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) -@@ -10976,6 +10979,7 @@ static int quic_setupearly_data_test(SSL +@@ -10977,6 +10980,7 @@ static int quic_setupearly_data_test(SSL { static const char *server_str = "SERVER"; static const char *client_str = "CLIENT"; @@ -98,7 +98,7 @@ from the server SSL. if (*sctx == NULL && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -11053,8 +11057,10 @@ static int quic_setupearly_data_test(SSL +@@ -11054,8 +11058,10 @@ static int quic_setupearly_data_test(SSL if (sess == NULL) return 1; @@ -111,7 +111,7 @@ from the server SSL. return 0; /* Deal with two NewSessionTickets */ -@@ -11093,12 +11099,15 @@ static int test_quic_early_data(int tst) +@@ -11094,12 +11100,15 @@ static int test_quic_early_data(int tst) SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; SSL_SESSION *sess = NULL; diff --git a/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch b/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch index a60075336..885ec470e 100644 --- a/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch +++ b/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch @@ -146,7 +146,7 @@ Don't make the new functions public. if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) { --- a/test/sslapitest.c +++ b/test/sslapitest.c -@@ -10831,7 +10831,6 @@ static int test_quic_api_version(int cln +@@ -10832,7 +10832,6 @@ static int test_quic_api_version(int cln static const char *client_str = "CLIENT"; const uint8_t *peer_str; size_t peer_str_len; @@ -154,7 +154,7 @@ Don't make the new functions public. TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); -@@ -10854,10 +10853,8 @@ static int test_quic_api_version(int cln +@@ -10855,10 +10854,8 @@ static int test_quic_api_version(int cln || !TEST_true(SSL_set_app_data(clientssl, serverssl)) || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) @@ -166,7 +166,7 @@ Don't make the new functions public. || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) -@@ -10979,7 +10976,6 @@ static int quic_setupearly_data_test(SSL +@@ -10980,7 +10977,6 @@ static int quic_setupearly_data_test(SSL { static const char *server_str = "SERVER"; static const char *client_str = "CLIENT"; @@ -174,7 +174,7 @@ Don't make the new functions public. if (*sctx == NULL && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -11057,10 +11053,8 @@ static int quic_setupearly_data_test(SSL +@@ -11058,10 +11054,8 @@ static int quic_setupearly_data_test(SSL if (sess == NULL) return 1; @@ -187,7 +187,7 @@ Don't make the new functions public. return 0; /* Deal with two NewSessionTickets */ -@@ -11099,15 +11093,12 @@ static int test_quic_early_data(int tst) +@@ -11100,15 +11094,12 @@ static int test_quic_early_data(int tst) SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; SSL_SESSION *sess = NULL; diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index fd1c6d76f..b5f65bfb0 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -162,6 +162,11 @@ pushd feeds/luci curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch | patch -p1 popd +# openssl +OPENSSL_VERSION=3.0.17 +OPENSSL_HASH=dfdd77e4ea1b57ff3a6dbde6b0bdc3f31db5ac99e7fdd4eaf9e1fbb6ec2db8ce +sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$OPENSSL_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$OPENSSL_HASH/" package/libs/openssl/Makefile + # openssl - quictls pushd package/libs/openssl/patches curl -sO $mirror/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch From 75b43ec550de49e6ebc352f5f4275b215a356e57 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 11 Jul 2025 13:56:50 +0800 Subject: [PATCH 264/425] package: remove openlist pkg from feeds Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index df160ea47..00de60e50 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -109,6 +109,7 @@ rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 # openlist +rm -rf feeds/packages/net/openlist feeds/luci/applications/luci-app-openlist git clone https://$github/sbwml/luci-app-openlist package/new/openlist --depth=1 # netdata From a82153576daa7f9dcf1515653c30c976fae987e4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 13 Jul 2025 13:26:53 +0800 Subject: [PATCH 265/425] luci-mod-status: iptables status menu conditions Signed-off-by: sbwml --- ...-firewall-disable-legacy-firewall-rul.patch | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch index 81ae48a53..5d37f54b2 100644 --- a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch +++ b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch @@ -6,12 +6,12 @@ Subject: [PATCH 4/5] luci-mod-status: firewall: disable legacy firewall rule Signed-off-by: sbwml --- - .../resources/view/status/nftables.js | 14 -------------- - .../share/luci/menu.d/luci-mod-status.json | 19 ++++++++++++++++--- - 2 files changed, 16 insertions(+), 17 deletions(-) + .../resources/view/status/nftables.js | 14 ------------ + .../share/luci/menu.d/luci-mod-status.json | 22 ++++++++++++++++--- + 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -index 406f134..9c083e7 100644 +index 0013a3a..bc630b0 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js @@ -675,26 +675,12 @@ return view.extend({ @@ -42,10 +42,10 @@ index 406f134..9c083e7 100644 return E('em', _('No nftables ruleset loaded.')); diff --git a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json -index 79101e9..eceb5e1 100644 +index 79101e9..0b7272d 100644 --- a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json +++ b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json -@@ -39,20 +39,33 @@ +@@ -39,23 +39,39 @@ } }, @@ -82,6 +82,12 @@ index 79101e9..eceb5e1 100644 "action": { "type": "view", "path": "status/iptables" ++ }, ++ "depends": { ++ "fs": { "/usr/sbin/iptables": "executable" } + } + }, + -- 2.43.5 From b6ca77755c753f4177b01b08345e607bfa70c163 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 13 Jul 2025 13:32:56 +0800 Subject: [PATCH 266/425] luci-compat: remove extra line breaks from description Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index b5f65bfb0..646d4f95b 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -329,6 +329,9 @@ sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/l # luci - disable wireless WPA3 [ "$platform" = "bcm53xx" ] && sed -i -e '/if (has_ap_sae || has_sta_sae) {/{N;N;N;N;d;}' feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js +# luci-compat - remove extra line breaks from description +sed -i '/
/d' feeds/luci/modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm + # odhcpd RFC-9096 mkdir -p package/network/services/odhcpd/patches curl -s $mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch From 93d80bf62ef40579fec8576d5c64da751c96e457 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 15 Jul 2025 14:42:16 +0800 Subject: [PATCH 267/425] linux-6.12: bump to 6.12.38 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index e40f0f569..d389e589d 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .37 -LINUX_KERNEL_HASH-6.12.37 = 936fdfd2405b5e0ac38d4e094b07772610c22cd478f4bb257c9bf929e762ff95 +LINUX_VERSION-6.12 = .38 +LINUX_KERNEL_HASH-6.12.38 = f035fa8d83d59f793c76b23567b130cc42118f10696815fed03c16bb15670fcc From 2cb6b41c6fbd6681f1cebe317a3f765d8333fcfa Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 18 Jul 2025 23:26:04 +0800 Subject: [PATCH 268/425] linux-6.12: bump to 6.12.39 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index d389e589d..b738ea851 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .38 -LINUX_KERNEL_HASH-6.12.38 = f035fa8d83d59f793c76b23567b130cc42118f10696815fed03c16bb15670fcc +LINUX_VERSION-6.12 = .39 +LINUX_KERNEL_HASH-6.12.39 = 6e562502a8fd11639f558e43b74f0df0d85fa85e60f5332acb275a75a35f5345 From e822a5c8950a8632116675ac778485ae23ec0729 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 18 Jul 2025 23:26:18 +0800 Subject: [PATCH 269/425] luci-app-openlist2 Signed-off-by: sbwml --- openwrt/24-config-common | 2 +- openwrt/scripts/02-prepare_package.sh | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index d99cccbf7..a75001fc8 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -111,7 +111,7 @@ CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y CONFIG_PACKAGE_luci-app-oaf=y -CONFIG_PACKAGE_luci-app-openlist=y +CONFIG_PACKAGE_luci-app-openlist2=y CONFIG_PACKAGE_luci-app-qbittorrent=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-samba4=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 00de60e50..eed71873c 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -109,8 +109,7 @@ rm -rf feeds/packages/net/{xray-core,v2ray-core,v2ray-geodata,sing-box} git clone https://$github/sbwml/openwrt_helloworld package/new/helloworld -b v5 # openlist -rm -rf feeds/packages/net/openlist feeds/luci/applications/luci-app-openlist -git clone https://$github/sbwml/luci-app-openlist package/new/openlist --depth=1 +git clone https://$github/sbwml/luci-app-openlist2 package/new/openlist --depth=1 # netdata sed -i 's/syslog/none/g' feeds/packages/admin/netdata/files/netdata.conf @@ -123,7 +122,7 @@ git clone https://$github/UnblockNeteaseMusic/luci-app-unblockneteasemusic packa sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new/luci-app-unblockneteasemusic/root/usr/share/luci/menu.d/luci-app-unblockneteasemusic.json # Theme -git clone --depth 1 https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon --depth=1 +git clone https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon --depth=1 # Mosdns git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 From 344e969f3c3fb29a090f12e95a262e1d0c841338 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Jul 2025 06:29:59 +0800 Subject: [PATCH 270/425] build.sh: Add support for FriendlyARM NanoPi R76S Signed-off-by: sbwml --- README.md | 16 ++- openwrt/24-config-musl-r76s | 28 +++++ openwrt/build.sh | 170 ++++++++++++++++++-------- openwrt/scripts/02-prepare_package.sh | 2 + 4 files changed, 163 insertions(+), 53 deletions(-) create mode 100644 openwrt/24-config-musl-r76s diff --git a/README.md b/README.md index 92b0d9e5b..ebaa10773 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,14 @@ --------------- -## 基于 Linux 6.6/6.12 LTS 固件下载: +## 基于 Linux 6.12 LTS 固件下载: #### NanoPi R4S: https://r4s.cooluc.com #### NanoPi R5S/R5C: https://r5s.cooluc.com +#### NanoPi R76S: https://r76s.cooluc.com + #### X86_64: https://x86.cooluc.com #### Snapshot 24.10: https://snapshot.cooluc.com @@ -178,6 +180,12 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r4s bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r5s ``` +### nanopi-r76s +```shell +# linux-6.12 +bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r76s +``` + ### x86_64 ```shell # linux-6.12 @@ -198,6 +206,12 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r4s bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r5s ``` +### nanopi-r76s +```shell +# linux-6.12 +bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r76s +``` + ### x86_64 ```shell # linux-6.12 diff --git a/openwrt/24-config-musl-r76s b/openwrt/24-config-musl-r76s new file mode 100644 index 000000000..30e66229a --- /dev/null +++ b/openwrt/24-config-musl-r76s @@ -0,0 +1,28 @@ +### Init +CONFIG_TARGET_rockchip=y +CONFIG_TARGET_rockchip_armv8=y +CONFIG_TARGET_rockchip_armv8_DEVICE_friendlyarm_nanopi-r76s=y + +### Basic +CONFIG_ALL_KMODS=y +CONFIG_ALL_NONSHARED=y +CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" +CONFIG_KERNEL_BUILD_USER="admin" +CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a73+crypto+crc -mtune=cortex-a73" +CONFIG_KERNEL_MEMCG_V1=y +CONFIG_KERNEL_MPTCP=y +CONFIG_KERNEL_MPTCP_IPV6=y +# CONFIG_KERNEL_PREEMPT_RT is not set +CONFIG_PACKAGE_autocore-arm=y +CONFIG_PACKAGE_bind-host=y +CONFIG_PACKAGE_block-mount=y +CONFIG_PACKAGE_coremark=y +CONFIG_PACKAGE_default-settings=y +CONFIG_TARGET_KERNEL_PARTSIZE=64 +CONFIG_TARGET_ROOTFS_PARTSIZE=944 +CONFIG_COREMARK_NUMBER_OF_THREADS=8 +# CONFIG_KERNEL_KALLSYMS is not set + +### Video Support +CONFIG_PACKAGE_kmod-drm-rockchip=y +CONFIG_PACKAGE_kmod-drm-panfrost=y diff --git a/openwrt/build.sh b/openwrt/build.sh index b53c35a2b..f2e2e0025 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -78,19 +78,16 @@ if curl --help | grep progress-bar >/dev/null 2>&1; then CURL_BAR="--progress-bar"; fi -if [ -z "$1" ] || [ "$2" != "nanopi-r4s" -a "$2" != "nanopi-r5s" -a "$2" != "x86_64" -a "$2" != "netgear_r8500" -a "$2" != "armv8" ]; then - echo -e "\n${RED_COLOR}Building type not specified.${RES}\n" +SUPPORTED_BOARDS="nanopi-r4s nanopi-r5s nanopi-r76s x86_64 netgear_r8500 armv8" +if [ -z "$1" ] || ! echo "$SUPPORTED_BOARDS" | grep -qw "$2"; then + echo -e "\n${RED_COLOR}Building type not specified or unsupported board: '$2'.${RES}\n" echo -e "Usage:\n" - echo -e "nanopi-r4s releases: ${GREEN_COLOR}bash build.sh rc2 nanopi-r4s${RES}" - echo -e "nanopi-r4s snapshots: ${GREEN_COLOR}bash build.sh dev nanopi-r4s${RES}" - echo -e "nanopi-r5s releases: ${GREEN_COLOR}bash build.sh rc2 nanopi-r5s${RES}" - echo -e "nanopi-r5s snapshots: ${GREEN_COLOR}bash build.sh dev nanopi-r5s${RES}" - echo -e "x86_64 releases: ${GREEN_COLOR}bash build.sh rc2 x86_64${RES}" - echo -e "x86_64 snapshots: ${GREEN_COLOR}bash build.sh dev x86_64${RES}" - echo -e "netgear-r8500 releases: ${GREEN_COLOR}bash build.sh rc2 netgear_r8500${RES}" - echo -e "netgear-r8500 snapshots: ${GREEN_COLOR}bash build.sh dev netgear_r8500${RES}" - echo -e "armsr-armv8 releases: ${GREEN_COLOR}bash build.sh rc2 armv8${RES}" - echo -e "armsr-armv8 snapshots: ${GREEN_COLOR}bash build.sh dev armv8${RES}\n" + + for board in $SUPPORTED_BOARDS; do + echo -e "$board releases: ${GREEN_COLOR}bash build.sh rc2 $board${RES}" + echo -e "$board snapshots: ${GREEN_COLOR}bash build.sh dev $board${RES}" + done + echo exit 1 fi @@ -108,11 +105,33 @@ fi [ -n "$LAN" ] && export LAN=$LAN || export LAN=10.0.0.1 # platform -[ "$2" = "armv8" ] && export platform="armv8" toolchain_arch="aarch64_generic" -[ "$2" = "nanopi-r4s" ] && export platform="rk3399" toolchain_arch="aarch64_generic" -[ "$2" = "nanopi-r5s" ] && export platform="rk3568" toolchain_arch="aarch64_generic" -[ "$2" = "netgear_r8500" ] && export platform="bcm53xx" toolchain_arch="arm_cortex-a9" -[ "$2" = "x86_64" ] && export platform="x86_64" toolchain_arch="x86_64" +case "$2" in + armv8) + platform="armv8" + toolchain_arch="aarch64_generic" + ;; + nanopi-r4s) + platform="rk3399" + toolchain_arch="aarch64_generic" + ;; + nanopi-r5s) + platform="rk3568" + toolchain_arch="aarch64_generic" + ;; + nanopi-r76s) + platform="rk3576" + toolchain_arch="aarch64_generic" + ;; + netgear_r8500) + platform="bcm53xx" + toolchain_arch="arm_cortex-a9" + ;; + x86_64) + platform="x86_64" + toolchain_arch="x86_64" + ;; +esac +export platform toolchain_arch # gcc14 & 15 if [ "$USE_GCC13" = y ]; then @@ -137,21 +156,33 @@ export \ # print version echo -e "\r\n${GREEN_COLOR}Building $branch${RES}\r\n" -if [ "$platform" = "x86_64" ]; then - echo -e "${GREEN_COLOR}Model: x86_64${RES}" -elif [ "$platform" = "armv8" ]; then - echo -e "${GREEN_COLOR}Model: armsr/armv8${RES}" - [ "$1" = "rc2" ] && model="armv8" -elif [ "$platform" = "bcm53xx" ]; then - echo -e "${GREEN_COLOR}Model: netgear_r8500${RES}" - [ "$LAN" = "10.0.0.1" ] && export LAN="192.168.1.1" -elif [ "$platform" = "rk3568" ]; then - echo -e "${GREEN_COLOR}Model: nanopi-r5s/r5c${RES}" - [ "$1" = "rc2" ] && model="nanopi-r5s" -else - echo -e "${GREEN_COLOR}Model: nanopi-r4s${RES}" - [ "$1" = "rc2" ] && model="nanopi-r4s" -fi +case "$platform" in + x86_64) + echo -e "${GREEN_COLOR}Model: x86_64${RES}" + ;; + armv8) + echo -e "${GREEN_COLOR}Model: armsr/armv8${RES}" + [ "$1" = "rc2" ] && model="armv8" + ;; + bcm53xx) + echo -e "${GREEN_COLOR}Model: netgear_r8500${RES}" + [ "$LAN" = "10.0.0.1" ] && export LAN="192.168.1.1" + ;; + rk3568) + echo -e "${GREEN_COLOR}Model: nanopi-r5s/r5c${RES}" + [ "$1" = "rc2" ] && model="nanopi-r5s" + ;; + rk3576) + echo -e "${GREEN_COLOR}Model: nanopi-r76s${RES}" + [ "$1" = "rc2" ] && model="nanopi-r76s" + ;; + rk3399|*) + echo -e "${GREEN_COLOR}Model: nanopi-r4s${RES}" + [ "$1" = "rc2" ] && model="nanopi-r4s" + ;; +esac + +# print build opt get_kernel_version=$(curl -s $mirror/tags/kernel-6.12) kmod_hash=$(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}' | tail -1 | md5sum | awk '{print $1}') kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) @@ -159,20 +190,34 @@ echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" echo -e "${GREEN_COLOR}Date: $CURRENT_DATE${RES}\r\n" echo -e "${GREEN_COLOR}SCRIPT_URL:${RES} ${BLUE_COLOR}$mirror${RES}\r\n" echo -e "${GREEN_COLOR}GCC VERSION: $gcc_version${RES}" -[ -n "$LAN" ] && echo -e "${GREEN_COLOR}LAN: $LAN${RES}" || echo -e "${GREEN_COLOR}LAN: 10.0.0.1${RES}" -[ -n "$ROOT_PASSWORD" ] && echo -e "${GREEN_COLOR}Default Password:${RES} ${BLUE_COLOR}$ROOT_PASSWORD${RES}" || echo -e "${GREEN_COLOR}Default Password: (${RES}${YELLOW_COLOR}No password${RES}${GREEN_COLOR})${RES}" +print_status() { + local name="$1" + local value="$2" + local true_color="${3:-$GREEN_COLOR}" + local false_color="${4:-$YELLOW_COLOR}" + local newline="${5:-}" + if [ "$value" = "y" ]; then + echo -e "${GREEN_COLOR}${name}:${RES} ${true_color}true${RES}${newline}" + else + echo -e "${GREEN_COLOR}${name}:${RES} ${false_color}false${RES}${newline}" + fi +} +[ -n "$LAN" ] && echo -e "${GREEN_COLOR}LAN:${RES} $LAN" || echo -e "${GREEN_COLOR}LAN:${RES} 10.0.0.1" +[ -n "$ROOT_PASSWORD" ] \ + && echo -e "${GREEN_COLOR}Default Password:${RES} ${BLUE_COLOR}$ROOT_PASSWORD${RES}" \ + || echo -e "${GREEN_COLOR}Default Password:${RES} (${YELLOW_COLOR}No password${RES})" [ "$ENABLE_GLIBC" = "y" ] && echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}glibc${RES}" || echo -e "${GREEN_COLOR}Standard C Library:${RES} ${BLUE_COLOR}musl${RES}" -[ "$ENABLE_OTA" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_OTA: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_OTA:${RES} ${YELLOW_COLOR}false${RES}" -[ "$ENABLE_DPDK" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_DPDK: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_DPDK:${RES} ${YELLOW_COLOR}false${RES}" -[ "$ENABLE_MOLD" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_MOLD: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_MOLD:${RES} ${YELLOW_COLOR}false${RES}" -[ "$ENABLE_BPF" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_BPF: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_BPF:${RES} ${RED_COLOR}false${RES}" -[ "$ENABLE_LTO" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_LTO: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_LTO:${RES} ${RED_COLOR}false${RES}" -[ "$ENABLE_LRNG" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_LRNG: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_LRNG:${RES} ${RED_COLOR}false${RES}" -[ "$ENABLE_LOCAL_KMOD" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_LOCAL_KMOD: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_LOCAL_KMOD: false${RES}" -[ "$BUILD_FAST" = "y" ] && echo -e "${GREEN_COLOR}BUILD_FAST: true${RES}" || echo -e "${GREEN_COLOR}BUILD_FAST:${RES} ${YELLOW_COLOR}false${RES}" -[ "$ENABLE_CCACHE" = "y" ] && echo -e "${GREEN_COLOR}ENABLE_CCACHE: true${RES}" || echo -e "${GREEN_COLOR}ENABLE_CCACHE:${RES} ${YELLOW_COLOR}false${RES}" -[ "$MINIMAL_BUILD" = "y" ] && echo -e "${GREEN_COLOR}MINIMAL_BUILD: true${RES}" || echo -e "${GREEN_COLOR}MINIMAL_BUILD: false${RES}" -[ "$KERNEL_CLANG_LTO" = "y" ] && echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO: true${RES}\r\n" || echo -e "${GREEN_COLOR}KERNEL_CLANG_LTO:${RES} ${YELLOW_COLOR}false${RES}\r\n" +print_status "ENABLE_OTA" "$ENABLE_OTA" +print_status "ENABLE_DPDK" "$ENABLE_DPDK" +print_status "ENABLE_MOLD" "$ENABLE_MOLD" +print_status "ENABLE_BPF" "$ENABLE_BPF" "$GREEN_COLOR" "$RED_COLOR" +print_status "ENABLE_LTO" "$ENABLE_LTO" "$GREEN_COLOR" "$RED_COLOR" +print_status "ENABLE_LRNG" "$ENABLE_LRNG" "$GREEN_COLOR" "$RED_COLOR" +print_status "ENABLE_LOCAL_KMOD" "$ENABLE_LOCAL_KMOD" +print_status "BUILD_FAST" "$BUILD_FAST" +print_status "ENABLE_CCACHE" "$ENABLE_CCACHE" +print_status "MINIMAL_BUILD" "$MINIMAL_BUILD" +print_status "KERNEL_CLANG_LTO" "$KERNEL_CLANG_LTO" "$GREEN_COLOR" "$YELLOW_COLOR" "\n" # clean old files rm -rf openwrt master @@ -237,13 +282,18 @@ fi echo -e "\n${GREEN_COLOR}Patching ...${RES}\n" # scripts -curl -sO $mirror/openwrt/scripts/00-prepare_base.sh -curl -sO $mirror/openwrt/scripts/01-prepare_base-mainline.sh -curl -sO $mirror/openwrt/scripts/02-prepare_package.sh -curl -sO $mirror/openwrt/scripts/03-convert_translation.sh -curl -sO $mirror/openwrt/scripts/04-fix_kmod.sh -curl -sO $mirror/openwrt/scripts/05-fix-source.sh -curl -sO $mirror/openwrt/scripts/99_clean_build_cache.sh +scripts=( + 00-prepare_base.sh + 01-prepare_base-mainline.sh + 02-prepare_package.sh + 03-convert_translation.sh + 04-fix_kmod.sh + 05-fix-source.sh + 99_clean_build_cache.sh +) +for script in "${scripts[@]}"; do + curl -sO "$mirror/openwrt/scripts/$script" +done if [ -n "$git_password" ] && [ -n "$private_url" ]; then curl -u openwrt:$git_password -sO "$private_url" else @@ -275,6 +325,8 @@ elif [ "$platform" = "bcm53xx" ]; then sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config elif [ "$platform" = "rk3568" ]; then curl -s $mirror/openwrt/24-config-musl-r5s > .config +elif [ "$platform" = "rk3576" ]; then + curl -s $mirror/openwrt/24-config-musl-r76s > .config elif [ "$platform" = "armv8" ]; then curl -s $mirror/openwrt/24-config-musl-armsr-armv8 > .config else @@ -615,6 +667,20 @@ EOF } ] } +EOF + elif [ "$model" = "nanopi-r76s" ]; then + [ "$MINIMAL_BUILD" = "y" ] && OTA_URL="https://r76s.cooluc.com/d/minimal/openwrt-24.10" + SHA256_R76S=$(sha256sum bin/targets/rockchip/armv8*/*-r76s-squashfs-sysupgrade.img.gz | awk '{print $1}') + cat > ota/fw.json < package/new/custom/coremark/src/musl/coremark.aarch64 +elif [ "$platform" = "rk3576" ]; then + curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-16-threads > package/new/custom/coremark/src/musl/coremark.aarch64 elif [ "$platform" = "rk3399" ]; then curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-6-threads > package/new/custom/coremark/src/musl/coremark.aarch64 elif [ "$platform" = "armv8" ]; then From e3e26026563f8f2bfed3b478d747a76f7bc234e7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Jul 2025 14:09:12 +0800 Subject: [PATCH 271/425] uboot: fix nanopi-r76s Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 646d4f95b..15dfba844 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -2,12 +2,12 @@ # Rockchip - rkbin & u-boot rm -rf package/boot/rkbin package/boot/uboot-rockchip package/boot/arm-trusted-firmware-rockchip -if [ "$platform" = "rk3568" ]; then - git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip - git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip -else +if [ "$platform" = "rk3399" ]; then git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip -b v2023.04 git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip -b 0419 +else + git clone https://$github/sbwml/package_boot_uboot-rockchip package/boot/uboot-rockchip + git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip fi # patch source From 3e9d4f884df64c523ecc0f75ffaf8d9550030df3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Jul 2025 17:29:57 +0800 Subject: [PATCH 272/425] nanopi-r76s: add kmod-rtw88-8822cs Signed-off-by: sbwml --- openwrt/24-config-musl-r76s | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/24-config-musl-r76s b/openwrt/24-config-musl-r76s index 30e66229a..d0e608062 100644 --- a/openwrt/24-config-musl-r76s +++ b/openwrt/24-config-musl-r76s @@ -23,6 +23,9 @@ CONFIG_TARGET_ROOTFS_PARTSIZE=944 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set +# SDIO WIFI +CONFIG_PACKAGE_kmod-rtw88-8822cs=y + ### Video Support CONFIG_PACKAGE_kmod-drm-rockchip=y CONFIG_PACKAGE_kmod-drm-panfrost=y From e67c0ba4021f96f6279be318245b493e8e931d1a Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 22 Jul 2025 17:54:17 +0800 Subject: [PATCH 273/425] script: add emmc-install script for nanopi-r76s Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 03ab2a80f..08a6c3a83 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -216,7 +216,7 @@ if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ]; then fi # emmc-install -if [ "$platform" = "rk3568" ]; then +if [ "$platform" = "rk3568" ] || [ "$platform" = "rk3576" ]; then mkdir -p files/sbin curl -so files/sbin/emmc-install $mirror/openwrt/files/sbin/emmc-install chmod 755 files/sbin/emmc-install From 0024a2b381f76ead7c8176175b6e8aacaa74b18a Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 24 Jul 2025 09:52:59 +0800 Subject: [PATCH 274/425] htop: update to 3.4.1 Signed-off-by: sbwml --- openwrt/build.sh | 3 +-- ...lation-issues-with-ncurses-on-GCC-15.patch | 20 ------------------- openwrt/scripts/05-fix-source.sh | 7 ++++--- 3 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 openwrt/patch/openwrt-6.x/gcc-15-c23/htop/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch diff --git a/openwrt/build.sh b/openwrt/build.sh index f2e2e0025..c49383b5b 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -62,8 +62,7 @@ fi # Check root if [ "$(id -u)" = "0" ]; then - echo -e "${RED_COLOR}Building with root user is not supported.${RES}" - exit 1 + export FORCE_UNSAFE_CONFIGURE=1 FORCE=1 fi # Start time diff --git a/openwrt/patch/openwrt-6.x/gcc-15-c23/htop/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch b/openwrt/patch/openwrt-6.x/gcc-15-c23/htop/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch deleted file mode 100644 index 3fb76db1d..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-15-c23/htop/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 04d0a5456c87c6ce7a77bef18b26e4b6dbb05265 Mon Sep 17 00:00:00 2001 -From: Benny Baumann -Date: Mon, 9 Dec 2024 22:18:08 +0100 -Subject: [PATCH] Avoid compilation issues with ncurses on GCC 15 - -Fixes: #1567 ---- - configure.ac | 1 + - 1 file changed, 1 insertion(+) - ---- a/configure.ac -+++ b/configure.ac -@@ -449,6 +449,7 @@ if test "$my_htop_platform" = "solaris"; - fi - AC_CHECK_FUNCS( [set_escdelay] ) - AC_CHECK_FUNCS( [getmouse] ) -+AC_DEFINE([NCURSES_ENABLE_STDBOOL_H], [1], [Define to enable stdbool.h in ncurses]) - - - AC_ARG_ENABLE([affinity], diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index ba1f62c24..393e8ffb7 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -61,9 +61,10 @@ if [ "$USE_GCC15" = y ]; then # gmp mkdir -p package/libs/gmp/patches curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch > package/libs/gmp/patches/001-fix-build-with-gcc-15.patch - # htop - mkdir -p feeds/packages/admin/htop/patches - curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15-c23/htop/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch > feeds/packages/admin/htop/patches/001-Avoid-compilation-issues-with-ncurses-on-GCC-15.patch + # htop - 24.10-NEXT + HTOP_VERSION=3.4.1 + HTOP_HASH=af9ec878f831b7c27d33e775c668ec79d569aa781861c995a0fbadc1bdb666cf + sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$HTOP_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$HTOP_HASH/" feeds/packages/admin/htop/Makefile # libtirpc sed -i '/TARGET_CFLAGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/libtirpc/Makefile # libsepol From 70a83e70166db7c6df6c01d47bebd9edd7feb951 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 24 Jul 2025 09:54:37 +0800 Subject: [PATCH 275/425] ci: add nanopi-r76s support Signed-off-by: sbwml --- .github/workflows/build-release.yml | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index d36ca5c0b..4af490a96 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -12,6 +12,7 @@ on: - 'armv8' - 'nanopi-r4s' - 'nanopi-r5s' + - 'nanopi-r76s' - 'netgear_r8500' - 'x86_64' version: diff --git a/README.md b/README.md index ebaa10773..9723b0c2b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# NanoPi R4S/R5S/R5C & X86_64 OpenWrt 简易构建脚本存档 +# NanoPi R4S/R5S/R5C/R76S & X86_64 OpenWrt 简易构建脚本存档 ### 存档来自:https://init2.cooluc.com From a2369df57419fa73cd034ea326ca300c93922fff Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Jul 2025 14:09:01 +0800 Subject: [PATCH 276/425] linux-6.12: bump to 6.12.40 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index b738ea851..9880cae37 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .39 -LINUX_KERNEL_HASH-6.12.39 = 6e562502a8fd11639f558e43b74f0df0d85fa85e60f5332acb275a75a35f5345 +LINUX_VERSION-6.12 = .40 +LINUX_KERNEL_HASH-6.12.40 = 4811af1317f98d2cccea3c7695969a2c03a27cb02fd2d5327032dd5341842933 From 7e19070c27af4ef6dd5de1f5fc6ca544fa7520db Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Jul 2025 16:14:17 +0800 Subject: [PATCH 277/425] emmc-install: use parted scripting mode Signed-off-by: sbwml --- openwrt/files/sbin/emmc-install | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/files/sbin/emmc-install b/openwrt/files/sbin/emmc-install index 457cab016..b2b8ab521 100755 --- a/openwrt/files/sbin/emmc-install +++ b/openwrt/files/sbin/emmc-install @@ -24,8 +24,8 @@ echo "Starting eMMC Flashing ..." # eMMC device echo " " echo "eMMC info" -emmc_device=$(parted -l 2>/dev/null | grep -A 1 -E 'Model: MMC .*sd/mmc' | tail -n1 | awk '{print $2}' | sed 's/://g') -emmc_size=$(parted -l 2>/dev/null | grep -A 1 -E 'Model: MMC .*sd/mmc' | tail -n1 | awk '{print $3}') +emmc_device=$(parted -s -l 2>/dev/null | grep -A 1 -E 'Model: MMC .*sd/mmc' | tail -n1 | awk '{print $2}' | sed 's/://g') +emmc_size=$(parted -s -l 2>/dev/null | grep -A 1 -E 'Model: MMC .*sd/mmc' | tail -n1 | awk '{print $3}') emmc_device_name=$(echo $emmc_device | awk -F/ '{print $3}') emmc_partition=$(fdisk -l 2>/dev/null | grep "$emmc_device_name"p | wc -l) if [ "$emmc_partition" -eq 3 ]; then From fdc5db628cf371ff26b23ba9541bdddd76d7b130 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 29 Jul 2025 20:18:02 +0800 Subject: [PATCH 278/425] nanopi-r76s: switch to rtl8822cs oot driver Signed-off-by: sbwml --- openwrt/24-config-musl-r76s | 2 +- openwrt/build.sh | 2 +- openwrt/scripts/01-prepare_base-mainline.sh | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openwrt/24-config-musl-r76s b/openwrt/24-config-musl-r76s index d0e608062..3965d69ad 100644 --- a/openwrt/24-config-musl-r76s +++ b/openwrt/24-config-musl-r76s @@ -24,7 +24,7 @@ CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set # SDIO WIFI -CONFIG_PACKAGE_kmod-rtw88-8822cs=y +CONFIG_PACKAGE_kmod-rtl8822cs=y ### Video Support CONFIG_PACKAGE_kmod-drm-rockchip=y diff --git a/openwrt/build.sh b/openwrt/build.sh index c49383b5b..eafade692 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -610,7 +610,7 @@ else if [ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ]; then cp -a bin/targets/rockchip/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/rtl88*-firmware*.ipk $kmodpkg_name/ cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ [ "$OPENWRT_CORE" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*3ginfo*.ipk $kmodpkg_name/ diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 08a6c3a83..b73b8e7a2 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -209,6 +209,9 @@ curl -s $mirror/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-supp curl -s $mirror/openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-6.12/601-netfilter-export-udp_get_timeouts-function.patch curl -s $mirror/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.12/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +# rtl8822cs +git clone https://$github/sbwml/package_kernel_rtl8822cs package/kernel/rtl8822cs + # RTC if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ]; then curl -s $mirror/openwrt/patch/rtc/sysfixtime > package/base-files/files/etc/init.d/sysfixtime From 6f814cb5f90c75a8ad17d3f84476289d12c7a990 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 31 Jul 2025 02:05:05 +0800 Subject: [PATCH 279/425] modules: bluetooth: add Realtek UART protocol support Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/other.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index d02eb6e37..1ec89d257 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -43,10 +43,12 @@ define KernelPackage/bluetooth CONFIG_BT_HCIBTUSB_MTK=y \ CONFIG_BT_HCIBTUSB_RTL=y \ CONFIG_BT_HCIUART \ + CONFIG_BT_HCIUART_3WIRE=y \ CONFIG_BT_HCIUART_BCM=n \ CONFIG_BT_HCIUART_INTEL=n \ CONFIG_BT_HCIUART_H4 \ CONFIG_BT_HCIUART_NOKIA=n \ + CONFIG_BT_HCIUART_RTL=y \ CONFIG_BT_HIDP $(call AddDepends/rfkill) FILES:= \ From 95ce78464050e6bb90624ec08ebfbdf0ca77f5e8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 31 Jul 2025 02:06:26 +0800 Subject: [PATCH 280/425] nanopi-r76s: Add Bluetooth driver Signed-off-by: sbwml --- openwrt/24-config-musl-r76s | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openwrt/24-config-musl-r76s b/openwrt/24-config-musl-r76s index 3965d69ad..e5760f964 100644 --- a/openwrt/24-config-musl-r76s +++ b/openwrt/24-config-musl-r76s @@ -23,8 +23,10 @@ CONFIG_TARGET_ROOTFS_PARTSIZE=944 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set -# SDIO WIFI -CONFIG_PACKAGE_kmod-rtl8822cs=y +# SDIO Wireless / Bluetooth +CONFIG_PACKAGE_kmod-bluetooth=y +CONFIG_PACKAGE_kmod-rtw88-8822cs=y +CONFIG_PACKAGE_rtl8822cs-firmware=y ### Video Support CONFIG_PACKAGE_kmod-drm-rockchip=y From 6adac4dc686c42ef76a35286e47267de88fa26cf Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 31 Jul 2025 22:55:30 +0800 Subject: [PATCH 281/425] config: minimal: drop iptables Signed-off-by: sbwml --- openwrt/24-config-minimal-common | 21 +-------------------- openwrt/scripts/00-prepare_base.sh | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index c92ee8dc9..fe51511e5 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -12,23 +12,10 @@ CONFIG_LIBCURL_OPENSSL=y ### Firewall CONFIG_PACKAGE_nat6=y -CONFIG_PACKAGE_ip6tables-nft=y -CONFIG_PACKAGE_iptables-mod-conntrack-extra=y -CONFIG_PACKAGE_iptables-mod-iprange=y -CONFIG_PACKAGE_iptables-mod-nat-extra=y -CONFIG_PACKAGE_iptables-mod-socket=y -CONFIG_PACKAGE_iptables-mod-tproxy=y -CONFIG_PACKAGE_iptables-nft=y -CONFIG_PACKAGE_xtables-nft=y -# CONFIG_PACKAGE_iptables-legacy is not set # Natflow CONFIG_PACKAGE_natflow=m -# SFE -CONFIG_PACKAGE_kmod-fast-classifier=y -CONFIG_PACKAGE_kmod-shortcut-fe-cm=y - ### Zram CONFIG_PACKAGE_zram-swap=y CONFIG_ZRAM_DEF_COMP_LZ4=y @@ -44,7 +31,6 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y ### Dnsmasq CONFIG_PACKAGE_dnsmasq-full=y -CONFIG_PACKAGE_dnsmasq_full_ipset=y # CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set # CONFIG_PACKAGE_dnsmasq is not set @@ -124,9 +110,6 @@ CONFIG_PACKAGE_kmod-ikconfig=y CONFIG_PACKAGE_kmod-inet-diag=y CONFIG_PACKAGE_kmod-ipsec4=y CONFIG_PACKAGE_kmod-ipsec6=y -CONFIG_PACKAGE_kmod-ipt-nat6=y -CONFIG_PACKAGE_kmod-ipt-tproxy=y -CONFIG_PACKAGE_kmod-iptunnel6=y CONFIG_PACKAGE_kmod-mac80211=y CONFIG_PACKAGE_kmod-nf-socket=y CONFIG_PACKAGE_kmod-nft-fullcone=y @@ -154,14 +137,12 @@ CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y ### Kernel Modules - USB WiFi Adapter CONFIG_PACKAGE_kmod-mt7921u=y -CONFIG_PACKAGE_kmod-rtw88-8812au=y -CONFIG_PACKAGE_kmod-rtw88-8821au=y -CONFIG_PACKAGE_kmod-rtw88-8822bu=y # CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y CONFIG_PACKAGE_dmesg=y +CONFIG_PACKAGE_openssh-sftp-server=y CONFIG_PACKAGE_taskset=y CONFIG_PACKAGE_wget-ssl=y CONFIG_PACKAGE_wpad-openssl=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 15dfba844..77d854921 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -351,7 +351,7 @@ sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$ZLIB_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$ZLIB_H # profile sed -i 's#\\u@\\h:\\w\\\$#\\[\\e[32;1m\\][\\u@\\h\\[\\e[0m\\] \\[\\033[01;34m\\]\\W\\[\\033[00m\\]\\[\\e[32;1m\\]]\\[\\e[0m\\]\\\$#g' package/base-files/files/etc/profile sed -ri 's/(export PATH=")[^"]*/\1%PATH%:\/opt\/bin:\/opt\/sbin:\/opt\/usr\/bin:\/opt\/usr\/sbin/' package/base-files/files/etc/profile -sed -i '/PS1/a\export TERM=xterm-color' package/base-files/files/etc/profile +sed -i '/ENV/i\export TERM=xterm-color' package/base-files/files/etc/profile # bash sed -i 's#ash#bash#g' package/base-files/files/etc/passwd From 28db645fa5741a8528b87a75258824a4f474e40e Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 1 Aug 2025 18:03:16 +0800 Subject: [PATCH 282/425] config-common: remove some less used utilities Signed-off-by: sbwml --- openwrt/24-config-common | 20 -------------------- openwrt/scripts/00-prepare_base.sh | 4 ++++ 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index a75001fc8..431130b81 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -229,9 +229,6 @@ CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y ### Kernel Modules - USB WiFi Adapter CONFIG_PACKAGE_kmod-mt7921u=y -CONFIG_PACKAGE_kmod-rtw88-8812au=y -CONFIG_PACKAGE_kmod-rtw88-8821au=y -CONFIG_PACKAGE_kmod-rtw88-8822bu=y # CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities @@ -250,7 +247,6 @@ CONFIG_PACKAGE_gdisk=y CONFIG_PACKAGE_htop=y CONFIG_PACKAGE_iperf3=y CONFIG_PACKAGE_iputils-ping=y -CONFIG_PACKAGE_less=y CONFIG_PACKAGE_lrzsz=y CONFIG_PACKAGE_lsblk=y CONFIG_PACKAGE_lscpu=y @@ -283,22 +279,6 @@ CONFIG_PACKAGE_xz=y CONFIG_PACKAGE_zip=y CONFIG_PACKAGE_zoneinfo-asia=y -### Shadow Utilities -CONFIG_PACKAGE_shadow-gpasswd=y -CONFIG_PACKAGE_shadow-groupadd=y -CONFIG_PACKAGE_shadow-groupdel=y -CONFIG_PACKAGE_shadow-groupmod=y -CONFIG_PACKAGE_shadow-groups=y -CONFIG_PACKAGE_shadow-login=y -CONFIG_PACKAGE_shadow-nologin=y -CONFIG_PACKAGE_shadow-passwd=y -CONFIG_PACKAGE_shadow-su=y -CONFIG_PACKAGE_shadow-useradd=y -CONFIG_PACKAGE_shadow-userdel=y -CONFIG_PACKAGE_shadow-usermod=y -CONFIG_PACKAGE_shadow-utils=y -# CONFIG_shadow-all is not set - ### GNU Core Utilities CONFIG_PACKAGE_coreutils=y CONFIG_PACKAGE_coreutils-cat=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 77d854921..2bee74df5 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -375,3 +375,7 @@ sed -i 's/0.openwrt.pool.ntp.org/ntp1.aliyun.com/g' package/base-files/files/bin sed -i 's/1.openwrt.pool.ntp.org/ntp2.aliyun.com/g' package/base-files/files/bin/config_generate sed -i 's/2.openwrt.pool.ntp.org/time1.cloud.tencent.com/g' package/base-files/files/bin/config_generate sed -i 's/3.openwrt.pool.ntp.org/time2.cloud.tencent.com/g' package/base-files/files/bin/config_generate + +# luci-theme-bootstrap +sed -i 's/font-size: 13px/font-size: 14px/g' feeds/luci/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css +sed -i 's/9.75px/10.75px/g' feeds/luci/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css From 677112561b96e61d715a21e211183c7b43fffc41 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 5 Aug 2025 05:26:54 +0800 Subject: [PATCH 283/425] linux-6.12: bump to 6.12.41 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 9880cae37..11f05faf1 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .40 -LINUX_KERNEL_HASH-6.12.40 = 4811af1317f98d2cccea3c7695969a2c03a27cb02fd2d5327032dd5341842933 +LINUX_VERSION-6.12 = .41 +LINUX_KERNEL_HASH-6.12.41 = 6b19a3ae99423de2416964d67251d745910277af258b4c4c63e88fd87dbf0e27 From 47656fd6b8b13bc956d66634d685f2f4705c2c66 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 5 Aug 2025 05:27:15 +0800 Subject: [PATCH 284/425] OpenAppFilter: update to 6.x version Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index ec0997d70..87e5a3eee 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -128,7 +128,7 @@ git clone https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon -- git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 # OpenAppFilter -git clone https://$github/sbwml/OpenAppFilter --depth=1 package/new/OpenAppFilter +git clone https://$github/sbwml/OpenAppFilter --depth=1 package/new/OpenAppFilter -b v6 # iperf3 sed -i "s/D_GNU_SOURCE/D_GNU_SOURCE -funroll-loops/g" feeds/packages/net/iperf3/Makefile From 42f23d6e4e4f607b02931e1ffecba3909139c515 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 20 Aug 2025 04:30:00 +0800 Subject: [PATCH 285/425] linux-6.12: bump to 6.12.42 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 11f05faf1..51f0379fc 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .41 -LINUX_KERNEL_HASH-6.12.41 = 6b19a3ae99423de2416964d67251d745910277af258b4c4c63e88fd87dbf0e27 +LINUX_VERSION-6.12 = .42 +LINUX_KERNEL_HASH-6.12.42 = 4804528a29cd20309a0b41c30e5aeffc35fa21ee3358f4a706d4586d003bc1fb From 0f2dea543701395271a6dd800d143ae060ddaa9e Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 21 Aug 2025 12:34:34 +0800 Subject: [PATCH 286/425] linux-6.12: bump to 6.12.43 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 51f0379fc..78b4d3933 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .42 -LINUX_KERNEL_HASH-6.12.42 = 4804528a29cd20309a0b41c30e5aeffc35fa21ee3358f4a706d4586d003bc1fb +LINUX_VERSION-6.12 = .43 +LINUX_KERNEL_HASH-6.12.43 = 0fcbbbbcd456e87bbbfc8bf37af541fda62ccfcce76903503424fd101ef7bdee From 24d28fd7181ec09200beec8372c5575d43bf8115 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 27 Aug 2025 12:02:14 +0800 Subject: [PATCH 287/425] config: add accel/rocket rockchip NPU driver for nanopi r76s Signed-off-by: sbwml --- openwrt/24-config-common | 1 + openwrt/24-config-musl-r76s | 3 +++ openwrt/build.sh | 3 +++ 3 files changed, 7 insertions(+) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 431130b81..a604b5fff 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -1,3 +1,4 @@ + ### Curl CONFIG_PACKAGE_curl=y CONFIG_PACKAGE_libcurl=y diff --git a/openwrt/24-config-musl-r76s b/openwrt/24-config-musl-r76s index e5760f964..71ec2accd 100644 --- a/openwrt/24-config-musl-r76s +++ b/openwrt/24-config-musl-r76s @@ -31,3 +31,6 @@ CONFIG_PACKAGE_rtl8822cs-firmware=y ### Video Support CONFIG_PACKAGE_kmod-drm-rockchip=y CONFIG_PACKAGE_kmod-drm-panfrost=y + +### Rocket NPU +CONFIG_PACKAGE_kmod-rocket-rockchip=y diff --git a/openwrt/build.sh b/openwrt/build.sh index eafade692..77ae866d3 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -420,6 +420,9 @@ if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then tools_suffix="_ccache" fi +# nanopi-r76s +[ "$platform" = "rk3576" ] && sed -i '/samba4/d' .config + # Toolchain Cache if [ "$BUILD_FAST" = "y" ]; then [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl From 816528c4e69320eb0b23c9d4c1a024f0fe356173 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 27 Aug 2025 12:09:31 +0800 Subject: [PATCH 288/425] ci: fix nanopi r76s firmware release Signed-off-by: sbwml --- .github/workflows/build-release.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 4af490a96..22cb9e552 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -194,12 +194,7 @@ jobs: working-directory: /builder run: | mkdir -p rom info - if [ "${{ github.event.inputs.device }}" = "nanopi-r4s" ]; then - cp -a openwrt/bin/targets/rockchip/*/*.img.gz rom/ - cp -a openwrt/bin/targets/rockchip/*/*-r4s.manifest info/manifest.txt - cp -a openwrt/bin/targets/rockchip/*/config.buildinfo info/config.buildinfo - cd rom && sha256sum *gz > ../info/sha256sums.txt - elif [ "${{ github.event.inputs.device }}" = "nanopi-r5s" ]; then + if [[ "${{ github.event.inputs.device }}" == "nanopi-*" ]]; then cp -a openwrt/bin/targets/rockchip/*/*.img.gz rom/ cp -a openwrt/bin/targets/rockchip/*/*.manifest info/manifest.txt cp -a openwrt/bin/targets/rockchip/*/config.buildinfo info/config.buildinfo From 16bd7f77354649d5a32241101bfe311a444d0fec Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 30 Aug 2025 22:47:06 +0800 Subject: [PATCH 289/425] linux-6.12: bump to 6.12.44 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 78b4d3933..e28a8c487 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .43 -LINUX_KERNEL_HASH-6.12.43 = 0fcbbbbcd456e87bbbfc8bf37af541fda62ccfcce76903503424fd101ef7bdee +LINUX_VERSION-6.12 = .44 +LINUX_KERNEL_HASH-6.12.44 = b650210ed3027b224969d148aa377452a9aad3ae7f2851abedd31adfef16bdae From 250dab370d670be3df19862f20d8d156052e099e Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 31 Aug 2025 12:14:08 +0800 Subject: [PATCH 290/425] ci: fix shell condition not matching nanopi-* device names Signed-off-by: sbwml --- .github/workflows/build-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 22cb9e552..7aa6a1458 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -194,7 +194,7 @@ jobs: working-directory: /builder run: | mkdir -p rom info - if [[ "${{ github.event.inputs.device }}" == "nanopi-*" ]]; then + if [[ "${{ github.event.inputs.device }}" == nanopi-* ]]; then cp -a openwrt/bin/targets/rockchip/*/*.img.gz rom/ cp -a openwrt/bin/targets/rockchip/*/*.manifest info/manifest.txt cp -a openwrt/bin/targets/rockchip/*/config.buildinfo info/config.buildinfo From 2f04561b312215776032287c05edcc9fb0177c47 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 11 Sep 2025 00:08:51 +0800 Subject: [PATCH 291/425] linux-6.12: bump to 6.12.46 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index e28a8c487..6b98e2d3a 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .44 -LINUX_KERNEL_HASH-6.12.44 = b650210ed3027b224969d148aa377452a9aad3ae7f2851abedd31adfef16bdae +LINUX_VERSION-6.12 = .46 +LINUX_KERNEL_HASH-6.12.46 = 2e5e7382d324caac23c5d80415f7c7ba64e3dbeee2ad936291e8c6c4b114573e From 45b4a07656d5b86c050d293a6b5dc873c4fab086 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 12 Sep 2025 12:20:25 +0800 Subject: [PATCH 292/425] linux-6.12: bump to 6.12.47 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 6b98e2d3a..db2569539 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .46 -LINUX_KERNEL_HASH-6.12.46 = 2e5e7382d324caac23c5d80415f7c7ba64e3dbeee2ad936291e8c6c4b114573e +LINUX_VERSION-6.12 = .47 +LINUX_KERNEL_HASH-6.12.47 = e82fe40871743048226987bd349ef107168b15aab90140e872ca4ed470922e25 From 907fc30d1939b8fd5b08d107d0d62e731e856331 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 12 Sep 2025 12:20:58 +0800 Subject: [PATCH 293/425] rtl8812au-ct: mark BROKEN Signed-off-by: sbwml --- openwrt/24-config-common | 1 - openwrt/24-config-minimal-common | 1 - openwrt/24-config-musl-r8500 | 1 - openwrt/24-config-musl-r8500-minimal | 1 - openwrt/scripts/04-fix_kmod.sh | 3 +++ 5 files changed, 3 insertions(+), 4 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index a604b5fff..93fd86623 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -230,7 +230,6 @@ CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y ### Kernel Modules - USB WiFi Adapter CONFIG_PACKAGE_kmod-mt7921u=y -# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index fe51511e5..4f9215f2b 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -137,7 +137,6 @@ CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y ### Kernel Modules - USB WiFi Adapter CONFIG_PACKAGE_kmod-mt7921u=y -# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/24-config-musl-r8500 b/openwrt/24-config-musl-r8500 index 1bf957c84..2736dfd2d 100644 --- a/openwrt/24-config-musl-r8500 +++ b/openwrt/24-config-musl-r8500 @@ -200,7 +200,6 @@ CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-veth=y CONFIG_PACKAGE_kmod-xdp-sockets-diag=y # CONFIG_PACKAGE_kmod-mhi-pcie is not set -# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/24-config-musl-r8500-minimal b/openwrt/24-config-musl-r8500-minimal index 0425b112c..7bdb7abda 100644 --- a/openwrt/24-config-musl-r8500-minimal +++ b/openwrt/24-config-musl-r8500-minimal @@ -152,7 +152,6 @@ CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-veth=y CONFIG_PACKAGE_kmod-xdp-sockets-diag=y # CONFIG_PACKAGE_kmod-mhi-pcie is not set -# CONFIG_PACKAGE_kmod-rtl8812au-ct is not set ### Utilities CONFIG_PACKAGE_bash=y diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index 23102094d..8fa5b41d2 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -2,6 +2,9 @@ # Fix build for 6.12 +### BROKEN +sed -i 's/^\([[:space:]]*DEPENDS:=.*\)$/\1 @BROKEN/' package/kernel/rtl8812au-ct/Makefile + # cryptodev-linux mkdir -p package/kernel/cryptodev-linux/patches curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch From e3f4037f8232c7b5756691b21abfbbe64775c007 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 15 Sep 2025 22:50:21 +0800 Subject: [PATCH 294/425] build.sh: drop Netgear R8500 support Signed-off-by: sbwml --- .github/workflows/build-release.yml | 6 - openwrt/24-config-musl-r8500 | 251 -------------------- openwrt/24-config-musl-r8500-minimal | 177 -------------- openwrt/build.sh | 60 +---- openwrt/scripts/01-prepare_base-mainline.sh | 12 - openwrt/scripts/04-fix_kmod.sh | 6 - openwrt/scripts/05-fix-source.sh | 12 - openwrt/scripts/99_clean_build_cache.sh | 4 +- 8 files changed, 4 insertions(+), 524 deletions(-) delete mode 100644 openwrt/24-config-musl-r8500 delete mode 100644 openwrt/24-config-musl-r8500-minimal diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 7aa6a1458..cf10fe31b 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -13,7 +13,6 @@ on: - 'nanopi-r4s' - 'nanopi-r5s' - 'nanopi-r76s' - - 'netgear_r8500' - 'x86_64' version: description: 'Select the build version' @@ -206,11 +205,6 @@ jobs: cp -a openwrt/bin/targets/x86/*/*-x86-64-generic.manifest info/manifest.txt cp -a openwrt/bin/targets/x86/*/config.buildinfo info/config.buildinfo cd rom && sha256sum *gz > ../info/sha256sums.txt - elif [ "${{ github.event.inputs.device }}" = "netgear_r8500" ]; then - cp -a openwrt/bin/targets/bcm53xx/generic/*-bcm53xx-generic-netgear_r8500-squashfs.chk rom/ - cp -a openwrt/bin/targets/bcm53xx/generic/*.manifest info/manifest.txt - cp -a openwrt/bin/targets/bcm53xx/generic/config.buildinfo info/config.buildinfo - cd rom && sha256sum * > ../info/sha256sums.txt elif [ "${{ github.event.inputs.device }}" = "armv8" ]; then tar zcf rom/u-boot-qemu_armv8.tar.gz -C openwrt/bin/targets/armsr/armv8*/ ./u-boot-qemu_armv8 cp -a openwrt/bin/targets/armsr/armv8*/*-generic-initramfs-kernel.bin rom/ diff --git a/openwrt/24-config-musl-r8500 b/openwrt/24-config-musl-r8500 deleted file mode 100644 index 2736dfd2d..000000000 --- a/openwrt/24-config-musl-r8500 +++ /dev/null @@ -1,251 +0,0 @@ -### Init -CONFIG_TARGET_bcm53xx=y -CONFIG_TARGET_bcm53xx_generic=y -CONFIG_TARGET_bcm53xx_generic_DEVICE_netgear_r8500=y - -### Basic -CONFIG_ALL_KMODS=y -CONFIG_ALL_NONSHARED=y -CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" -CONFIG_KERNEL_BUILD_USER="admin" -CONFIG_PACKAGE_autocore-arm=y -CONFIG_PACKAGE_bind-host=y -CONFIG_PACKAGE_block-mount=y -CONFIG_PACKAGE_default-settings=y -# CONFIG_KERNEL_KALLSYMS is not set - -### Curl -CONFIG_PACKAGE_curl=y -CONFIG_PACKAGE_libcurl=y -CONFIG_LIBCURL_NGHTTP3=y -CONFIG_LIBCURL_NGTCP2=y -CONFIG_LIBCURL_OPENSSL=y -# CONFIG_LIBCURL_GNUTLS is not set -# CONFIG_LIBCURL_MBEDTLS is not set -# CONFIG_LIBCURL_NOSSL is not set -# CONFIG_LIBCURL_WOLFSSL is not set - -### Firewall -CONFIG_PACKAGE_nat6=y -CONFIG_PACKAGE_ip6tables-nft=y -CONFIG_PACKAGE_iptables-mod-conntrack-extra=y -CONFIG_PACKAGE_iptables-mod-iprange=y -CONFIG_PACKAGE_iptables-mod-nat-extra=y -CONFIG_PACKAGE_iptables-mod-socket=y -CONFIG_PACKAGE_iptables-mod-tproxy=y -CONFIG_PACKAGE_iptables-nft=y -CONFIG_PACKAGE_xtables-nft=y -# CONFIG_PACKAGE_iptables-legacy is not set - -# Natflow -CONFIG_PACKAGE_natflow=m - -# SFE -CONFIG_PACKAGE_kmod-fast-classifier=y -CONFIG_PACKAGE_kmod-shortcut-fe-cm=y - -### Zram -CONFIG_PACKAGE_zram-swap=y -CONFIG_ZRAM_DEF_COMP_LZ4=y - -### Busybox -CONFIG_BUSYBOX_CUSTOM=y -CONFIG_BUSYBOX_CONFIG_ASH_HELP=y -CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_HISTORY=1024 -CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY=y -CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y -CONFIG_BUSYBOX_CONFIG_FEATURE_SH_HISTFILESIZE=y -CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y - -### Dnsmasq -CONFIG_PACKAGE_dnsmasq-full=y -CONFIG_PACKAGE_dnsmasq_full_ipset=y -# CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set -# CONFIG_PACKAGE_dnsmasq is not set - -### Luci -CONFIG_PACKAGE_luci=y -CONFIG_PACKAGE_luci-lib-base=y -CONFIG_PACKAGE_luci-lib-ip=y -CONFIG_PACKAGE_luci-lib-ipkg=y -CONFIG_PACKAGE_luci-lib-jsonc=y -CONFIG_PACKAGE_luci-lib-nixio=y -CONFIG_PACKAGE_luci-nginx=y -CONFIG_PACKAGE_luci-theme-argon=y -CONFIG_LUCI_LANG_zh_Hans=y -# CONFIG_LUCI_CSSTIDY is not set -# CONFIG_LUCI_JSMIN is not set - -### Nginx -CONFIG_PACKAGE_nginx-ssl=y -CONFIG_PACKAGE_nginx-mod-brotli=y -CONFIG_PACKAGE_nginx-mod-luci=y -CONFIG_PACKAGE_nginx-mod-rtmp=y -CONFIG_PACKAGE_nginx-mod-stream=y -CONFIG_PACKAGE_nginx-mod-ubus=y -CONFIG_PACKAGE_nginx-mod-zstd=y -CONFIG_PACKAGE_nginx-ssl-util=y -CONFIG_NGINX_DAV=y -CONFIG_NGINX_HTTP_AUTH_BASIC=y -CONFIG_NGINX_HTTP_QUIC=y -CONFIG_NGINX_HTTP_REAL_IP=y -CONFIG_NGINX_HTTP_SUB=y -CONFIG_NGINX_STREAM_REAL_IP=y - -### APPS -CONFIG_PACKAGE_luci-app-accesscontrol=y -CONFIG_PACKAGE_luci-app-airconnect=y -CONFIG_PACKAGE_luci-app-airplay2=y -CONFIG_PACKAGE_luci-app-argon-config=y -CONFIG_PACKAGE_luci-app-autoreboot=y -CONFIG_PACKAGE_luci-app-commands=y -CONFIG_PACKAGE_luci-app-ddns=y -CONFIG_PACKAGE_luci-app-diskman=y -CONFIG_PACKAGE_luci-app-eqos=y -CONFIG_PACKAGE_luci-app-filemanager=y -CONFIG_PACKAGE_luci-app-frpc=y -CONFIG_PACKAGE_luci-app-mentohust=y -CONFIG_PACKAGE_luci-app-mosdns=y -CONFIG_PACKAGE_luci-app-netspeedtest=y -CONFIG_PACKAGE_luci-app-nlbwmon=y -CONFIG_PACKAGE_luci-app-oaf=y -CONFIG_PACKAGE_luci-app-ramfree=y -CONFIG_PACKAGE_luci-app-samba4=y -CONFIG_PACKAGE_luci-app-socat=y -CONFIG_PACKAGE_luci-app-ttyd=y -CONFIG_PACKAGE_luci-app-upnp=y -CONFIG_PACKAGE_luci-app-usb-printer=y -CONFIG_PACKAGE_luci-app-vlmcsd=y -CONFIG_PACKAGE_luci-app-watchcat=y -CONFIG_PACKAGE_luci-app-webdav=y -CONFIG_PACKAGE_luci-app-wolplus=y -CONFIG_PACKAGE_luci-app-zerotier=y - -### Passwall -CONFIG_PACKAGE_luci-app-passwall=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Libev_Client=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_V2ray_Geodata=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Xray_Plugin=y -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Hysteria is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_NaiveProxy is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Libev_Server is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Rust_Client is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Rust_Server is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_ShadowsocksR_Libev_Client is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_SingBox is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Trojan_GO is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Trojan_Plus is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_tuic_client is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_V2ray_Plugin is not set - -### DDNS Scripts -CONFIG_PACKAGE_ddns-scripts=y -CONFIG_PACKAGE_ddns-scripts-aliyun=y -CONFIG_PACKAGE_ddns-scripts-dnspod=y - -### OpenSSL -CONFIG_OPENSSL_ENGINE=y -CONFIG_OPENSSL_OPTIMIZE_SPEED=y -CONFIG_OPENSSL_WITH_ASM=y -CONFIG_PACKAGE_libopenssl-afalg=y -CONFIG_PACKAGE_libopenssl-conf=y -CONFIG_PACKAGE_libopenssl-devcrypto=y -CONFIG_PACKAGE_libopenssl-legacy=y -CONFIG_PACKAGE_openssl-util=y -# CONFIG_OPENSSL_WITH_ERROR_MESSAGES is not set - -### L2TP -CONFIG_PACKAGE_kmod-l2tp=y -CONFIG_PACKAGE_kmod-pppol2tp=y -CONFIG_PACKAGE_ppp-mod-pppol2tp=y -CONFIG_PACKAGE_xl2tpd=y - -### Share Network -CONFIG_PACKAGE_usbmuxd=y -CONFIG_PACKAGE_kmod-usb-net-rndis=y -CONFIG_PACKAGE_kmod-usb-net-ipheth=y - -### Kernel Modules -CONFIG_PACKAGE_kmod-br-netfilter=y -CONFIG_PACKAGE_kmod-button-hotplug=y -CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y -CONFIG_PACKAGE_kmod-crypto-sha256=y -CONFIG_PACKAGE_kmod-fs-exfat=y -CONFIG_PACKAGE_kmod-fs-f2fs=y -CONFIG_PACKAGE_kmod-fs-ntfs3=y -CONFIG_PACKAGE_kmod-fs-vfat=y -CONFIG_PACKAGE_kmod-fs-xfs=y -CONFIG_PACKAGE_kmod-ikconfig=y -CONFIG_PACKAGE_kmod-inet-diag=y -CONFIG_PACKAGE_kmod-ipsec4=y -CONFIG_PACKAGE_kmod-ipsec6=y -CONFIG_PACKAGE_kmod-ipt-nat6=y -CONFIG_PACKAGE_kmod-ipt-tproxy=y -CONFIG_PACKAGE_kmod-iptunnel6=y -CONFIG_PACKAGE_kmod-nf-socket=y -CONFIG_PACKAGE_kmod-nft-fullcone=y -CONFIG_PACKAGE_kmod-nft-offload=y -CONFIG_PACKAGE_kmod-nft-socket=y -CONFIG_PACKAGE_kmod-nft-tproxy=y -CONFIG_PACKAGE_kmod-sched-bpf=y -CONFIG_PACKAGE_kmod-sched-cake=y -CONFIG_PACKAGE_kmod-sched-core=y -CONFIG_PACKAGE_kmod-sched=y -CONFIG_PACKAGE_kmod-tcp-bbr3=y -CONFIG_PACKAGE_kmod-tls=y -CONFIG_PACKAGE_kmod-tun=y -CONFIG_PACKAGE_kmod-usb-audio=y -CONFIG_PACKAGE_kmod-usb-storage-uas=y -CONFIG_PACKAGE_kmod-usb-storage=y -CONFIG_PACKAGE_kmod-veth=y -CONFIG_PACKAGE_kmod-xdp-sockets-diag=y -# CONFIG_PACKAGE_kmod-mhi-pcie is not set - -### Utilities -CONFIG_PACKAGE_bash=y -CONFIG_PACKAGE_dmesg=y -CONFIG_PACKAGE_dosfstools=y -CONFIG_PACKAGE_exfat-fsck=y -CONFIG_PACKAGE_exfat-mkfs=y -CONFIG_PACKAGE_f2fs-tools=y -CONFIG_PACKAGE_fdisk=y -CONFIG_PACKAGE_file=y -CONFIG_PACKAGE_ftp=y -CONFIG_PACKAGE_less=y -CONFIG_PACKAGE_lrzsz=y -CONFIG_PACKAGE_lsblk=y -CONFIG_PACKAGE_lscpu=y -CONFIG_PACKAGE_lsof=y -CONFIG_PACKAGE_nethogs=y -CONFIG_PACKAGE_openssh-sftp-server=y -CONFIG_PACKAGE_pciutils=y -CONFIG_PACKAGE_qrencode=y -CONFIG_PACKAGE_screen=y -CONFIG_PACKAGE_telnet-bsd=y -CONFIG_PACKAGE_usbutils=y -CONFIG_PACKAGE_wget-ssl=y -CONFIG_PACKAGE_wpad-openssl=y -CONFIG_PACKAGE_xfs-admin=y -CONFIG_PACKAGE_xfs-fsck=y -CONFIG_PACKAGE_xfs-growfs=y -CONFIG_PACKAGE_xfs-mkfs=y -CONFIG_PACKAGE_zoneinfo-asia=y - -### GNU Core Utilities -CONFIG_PACKAGE_coreutils=y -CONFIG_PACKAGE_coreutils-dircolors=y -CONFIG_PACKAGE_coreutils-ls=y - -### procps-ng Utilities -CONFIG_PACKAGE_procps-ng=y -CONFIG_PACKAGE_procps-ng-free=y -CONFIG_PACKAGE_procps-ng-ps=y -CONFIG_PACKAGE_procps-ng-top=y - -### Version -CONFIG_IMAGEOPT=y -CONFIG_VERSIONOPT=y -CONFIG_VERSION_FILENAMES=y - -### ZLIB -CONFIG_ZLIB_OPTIMIZE_SPEED=y diff --git a/openwrt/24-config-musl-r8500-minimal b/openwrt/24-config-musl-r8500-minimal deleted file mode 100644 index 7bdb7abda..000000000 --- a/openwrt/24-config-musl-r8500-minimal +++ /dev/null @@ -1,177 +0,0 @@ -### Init -CONFIG_TARGET_bcm53xx=y -CONFIG_TARGET_bcm53xx_generic=y -CONFIG_TARGET_bcm53xx_generic_DEVICE_netgear_r8500=y - -### Basic -CONFIG_ALL_KMODS=y -CONFIG_ALL_NONSHARED=y -CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" -CONFIG_KERNEL_BUILD_USER="admin" -CONFIG_PACKAGE_autocore-arm=y -CONFIG_PACKAGE_bind-host=y -CONFIG_PACKAGE_block-mount=y -CONFIG_PACKAGE_default-settings=y -# CONFIG_KERNEL_KALLSYMS is not set - -### Curl -CONFIG_PACKAGE_curl=y -CONFIG_PACKAGE_libcurl=y -CONFIG_LIBCURL_NGHTTP3=y -CONFIG_LIBCURL_NGTCP2=y -CONFIG_LIBCURL_OPENSSL=y -# CONFIG_LIBCURL_GNUTLS is not set -# CONFIG_LIBCURL_MBEDTLS is not set -# CONFIG_LIBCURL_NOSSL is not set -# CONFIG_LIBCURL_WOLFSSL is not set - -### Firewall -CONFIG_PACKAGE_nat6=y -CONFIG_PACKAGE_ip6tables-nft=y -CONFIG_PACKAGE_iptables-mod-conntrack-extra=y -CONFIG_PACKAGE_iptables-mod-iprange=y -CONFIG_PACKAGE_iptables-mod-nat-extra=y -CONFIG_PACKAGE_iptables-mod-socket=y -CONFIG_PACKAGE_iptables-mod-tproxy=y -CONFIG_PACKAGE_iptables-nft=y -CONFIG_PACKAGE_xtables-nft=y -# CONFIG_PACKAGE_iptables-legacy is not set - -# Natflow -CONFIG_PACKAGE_natflow=m - -# SFE -CONFIG_PACKAGE_kmod-fast-classifier=y -CONFIG_PACKAGE_kmod-shortcut-fe-cm=y - -### Zram -CONFIG_PACKAGE_zram-swap=y -CONFIG_ZRAM_DEF_COMP_LZ4=y - -### Busybox -CONFIG_BUSYBOX_CUSTOM=y -CONFIG_BUSYBOX_CONFIG_ASH_HELP=y -CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_HISTORY=1024 -CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY=y -CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y -CONFIG_BUSYBOX_CONFIG_FEATURE_SH_HISTFILESIZE=y -CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y - -### Dnsmasq -CONFIG_PACKAGE_dnsmasq-full=y -CONFIG_PACKAGE_dnsmasq_full_ipset=y -# CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set -# CONFIG_PACKAGE_dnsmasq is not set - -### Luci -CONFIG_PACKAGE_luci=y -CONFIG_PACKAGE_luci-lib-base=y -CONFIG_PACKAGE_luci-lib-ip=y -CONFIG_PACKAGE_luci-lib-ipkg=y -CONFIG_PACKAGE_luci-lib-jsonc=y -CONFIG_PACKAGE_luci-lib-nixio=y -CONFIG_PACKAGE_luci-nginx=y -CONFIG_LUCI_LANG_zh_Hans=y - -### Nginx -CONFIG_PACKAGE_nginx-ssl=y -CONFIG_PACKAGE_nginx-mod-brotli=y -CONFIG_PACKAGE_nginx-mod-luci=y -CONFIG_PACKAGE_nginx-mod-rtmp=y -CONFIG_PACKAGE_nginx-mod-stream=y -CONFIG_PACKAGE_nginx-mod-ubus=y -CONFIG_PACKAGE_nginx-mod-zstd=y -CONFIG_PACKAGE_nginx-ssl-util=y -CONFIG_NGINX_DAV=y -CONFIG_NGINX_HTTP_AUTH_BASIC=y -CONFIG_NGINX_HTTP_QUIC=y -CONFIG_NGINX_HTTP_REAL_IP=y -CONFIG_NGINX_HTTP_SUB=y -CONFIG_NGINX_STREAM_REAL_IP=y - -### APPS -CONFIG_PACKAGE_luci-app-autoreboot=y -CONFIG_PACKAGE_luci-app-ddns=y -CONFIG_PACKAGE_luci-app-filemanager=y -CONFIG_PACKAGE_luci-app-ramfree=y -CONFIG_PACKAGE_luci-app-ttyd=y -CONFIG_PACKAGE_luci-app-upnp=y - -### DDNS Scripts -CONFIG_PACKAGE_ddns-scripts=y -CONFIG_PACKAGE_ddns-scripts-aliyun=y -CONFIG_PACKAGE_ddns-scripts-dnspod=y - -### OpenSSL -CONFIG_OPENSSL_ENGINE=y -CONFIG_OPENSSL_OPTIMIZE_SPEED=y -CONFIG_OPENSSL_WITH_ASM=y -CONFIG_PACKAGE_libopenssl-afalg=y -CONFIG_PACKAGE_libopenssl-conf=y -CONFIG_PACKAGE_libopenssl-devcrypto=y -CONFIG_PACKAGE_libopenssl-legacy=y -CONFIG_PACKAGE_openssl-util=y -# CONFIG_OPENSSL_WITH_ERROR_MESSAGES is not set - -### Share Network -CONFIG_PACKAGE_usbmuxd=y -CONFIG_PACKAGE_kmod-usb-net-rndis=y -CONFIG_PACKAGE_kmod-usb-net-ipheth=y - -### Kernel Modules -CONFIG_PACKAGE_kmod-br-netfilter=y -CONFIG_PACKAGE_kmod-button-hotplug=y -CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y -CONFIG_PACKAGE_kmod-crypto-sha256=y -CONFIG_PACKAGE_kmod-fs-exfat=y -CONFIG_PACKAGE_kmod-fs-f2fs=y -CONFIG_PACKAGE_kmod-fs-ntfs3=y -CONFIG_PACKAGE_kmod-fs-vfat=y -CONFIG_PACKAGE_kmod-fs-xfs=y -CONFIG_PACKAGE_kmod-ikconfig=y -CONFIG_PACKAGE_kmod-inet-diag=y -CONFIG_PACKAGE_kmod-ipsec4=y -CONFIG_PACKAGE_kmod-ipsec6=y -CONFIG_PACKAGE_kmod-ipt-nat6=y -CONFIG_PACKAGE_kmod-ipt-tproxy=y -CONFIG_PACKAGE_kmod-iptunnel6=y -CONFIG_PACKAGE_kmod-nf-socket=y -CONFIG_PACKAGE_kmod-nft-fullcone=y -CONFIG_PACKAGE_kmod-nft-offload=y -CONFIG_PACKAGE_kmod-nft-socket=y -CONFIG_PACKAGE_kmod-nft-tproxy=y -CONFIG_PACKAGE_kmod-sched-bpf=y -CONFIG_PACKAGE_kmod-sched-cake=y -CONFIG_PACKAGE_kmod-sched-core=y -CONFIG_PACKAGE_kmod-sched=y -CONFIG_PACKAGE_kmod-tcp-bbr3=y -CONFIG_PACKAGE_kmod-tls=y -CONFIG_PACKAGE_kmod-tun=y -CONFIG_PACKAGE_kmod-usb-storage-uas=y -CONFIG_PACKAGE_kmod-usb-storage=y -CONFIG_PACKAGE_kmod-veth=y -CONFIG_PACKAGE_kmod-xdp-sockets-diag=y -# CONFIG_PACKAGE_kmod-mhi-pcie is not set - -### Utilities -CONFIG_PACKAGE_bash=y -CONFIG_PACKAGE_dmesg=y -CONFIG_PACKAGE_ftp=y -CONFIG_PACKAGE_openssh-sftp-server=y -CONFIG_PACKAGE_telnet-bsd=y -CONFIG_PACKAGE_usbutils=y -CONFIG_PACKAGE_wget-ssl=y -CONFIG_PACKAGE_wpad-openssl=y - -### GNU Core Utilities -CONFIG_PACKAGE_coreutils=y -CONFIG_PACKAGE_coreutils-dircolors=y -CONFIG_PACKAGE_coreutils-ls=y - -### Version -CONFIG_IMAGEOPT=y -CONFIG_VERSIONOPT=y -CONFIG_VERSION_FILENAMES=y - -### ZLIB -CONFIG_ZLIB_OPTIMIZE_SPEED=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 77ae866d3..3a28ac2f1 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -77,7 +77,7 @@ if curl --help | grep progress-bar >/dev/null 2>&1; then CURL_BAR="--progress-bar"; fi -SUPPORTED_BOARDS="nanopi-r4s nanopi-r5s nanopi-r76s x86_64 netgear_r8500 armv8" +SUPPORTED_BOARDS="nanopi-r4s nanopi-r5s nanopi-r76s x86_64 armv8" if [ -z "$1" ] || ! echo "$SUPPORTED_BOARDS" | grep -qw "$2"; then echo -e "\n${RED_COLOR}Building type not specified or unsupported board: '$2'.${RES}\n" echo -e "Usage:\n" @@ -121,10 +121,6 @@ case "$2" in platform="rk3576" toolchain_arch="aarch64_generic" ;; - netgear_r8500) - platform="bcm53xx" - toolchain_arch="arm_cortex-a9" - ;; x86_64) platform="x86_64" toolchain_arch="x86_64" @@ -163,10 +159,6 @@ case "$platform" in echo -e "${GREEN_COLOR}Model: armsr/armv8${RES}" [ "$1" = "rc2" ] && model="armv8" ;; - bcm53xx) - echo -e "${GREEN_COLOR}Model: netgear_r8500${RES}" - [ "$LAN" = "10.0.0.1" ] && export LAN="192.168.1.1" - ;; rk3568) echo -e "${GREEN_COLOR}Model: nanopi-r5s/r5c${RES}" [ "$1" = "rc2" ] && model="nanopi-r5s" @@ -315,13 +307,6 @@ rm -rf ../master # Load devices Config if [ "$platform" = "x86_64" ]; then curl -s $mirror/openwrt/24-config-musl-x86 > .config -elif [ "$platform" = "bcm53xx" ]; then - if [ "$MINIMAL_BUILD" = "y" ]; then - curl -s $mirror/openwrt/24-config-musl-r8500-minimal > .config - else - curl -s $mirror/openwrt/24-config-musl-r8500 > .config - fi - sed -i '1i\# CONFIG_PACKAGE_kselftests-bpf is not set\n# CONFIG_PACKAGE_perf is not set\n' .config elif [ "$platform" = "rk3568" ]; then curl -s $mirror/openwrt/24-config-musl-r5s > .config elif [ "$platform" = "rk3576" ]; then @@ -334,10 +319,10 @@ fi # config-common if [ "$MINIMAL_BUILD" = "y" ]; then - [ "$platform" != "bcm53xx" ] && curl -s $mirror/openwrt/24-config-minimal-common >> .config + curl -s $mirror/openwrt/24-config-minimal-common >> .config echo 'VERSION_TYPE="minimal"' >> package/base-files/files/usr/lib/os-release else - [ "$platform" != "bcm53xx" ] && curl -s $mirror/openwrt/24-config-common >> .config + curl -s $mirror/openwrt/24-config-common >> .config [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi @@ -567,45 +552,6 @@ elif [ "$platform" = "armv8" ]; then } ] } -EOF - fi - exit 0 -elif [ "$platform" = "bcm53xx" ]; then - if [ "$NO_KMOD" != "y" ]; then - cp -a bin/targets/bcm53xx/generic/packages $kmodpkg_name - rm -f $kmodpkg_name/Packages* - cp -a bin/packages/arm_cortex-a9/base/rtl88*a-firmware*.ipk $kmodpkg_name/ - cp -a bin/packages/arm_cortex-a9/base/natflow*.ipk $kmodpkg_name/ - [ "$OPENWRT_CORE" = "y" ] && { - cp -a bin/packages/arm_cortex-a9/base/*3ginfo*.ipk $kmodpkg_name/ - cp -a bin/packages/arm_cortex-a9/base/*modemband*.ipk $kmodpkg_name/ - cp -a bin/packages/arm_cortex-a9/base/*sms-tool*.ipk $kmodpkg_name/ - cp -a bin/packages/arm_cortex-a9/base/*quectel*.ipk $kmodpkg_name/ - } - bash kmod-sign $kmodpkg_name - tar zcf bcm53xx-$kmodpkg_name.tar.gz $kmodpkg_name - rm -rf $kmodpkg_name - fi - # OTA json - if [ "$1" = "rc2" ]; then - mkdir -p ota - if [ "$MINIMAL_BUILD" = "y" ]; then - OTA_URL="https://r8500.cooluc.com/d/minimal/openwrt-24.10" - else - OTA_URL="https://github.com/sbwml/builder/releases/download" - fi - VERSION=$(sed 's/v//g' version.txt) - SHA256=$(sha256sum bin/targets/bcm53xx/generic/*-bcm53xx-generic-netgear_r8500-squashfs.chk | awk '{print $1}') - cat > ota/fw.json < target/linux/x86/base-files/etc/board.d/01_leds curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network -# bcm53xx - target -rm -rf target/linux/bcm53xx -if [ "$(whoami)" = "sbwml" ]; then - git clone https://$gitea/sbwml/target_linux_bcm53xx target/linux/bcm53xx - git clone https://$gitea/sbwml/brcmfmac-firmware-4366c-pcie package/firmware/brcmfmac-firmware-4366c-pcie - git clone https://$gitea/sbwml/brcmfmac-firmware-4366b-pcie package/firmware/brcmfmac-firmware-4366b-pcie -else - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_bcm53xx target/linux/bcm53xx - git clone https://"$git_name":"$git_password"@$gitea/sbwml/brcmfmac-firmware-4366c-pcie package/firmware/brcmfmac-firmware-4366c-pcie - git clone https://"$git_name":"$git_password"@$gitea/sbwml/brcmfmac-firmware-4366b-pcie package/firmware/brcmfmac-firmware-4366b-pcie -fi - # armsr/armv8 rm -rf target/linux/armsr git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b main diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index 8fa5b41d2..fa9c9dd82 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -66,12 +66,6 @@ popd # routing - batman-adv fix build with linux-6.12 curl -s $mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch > feeds/routing/batman-adv/patches/901-fix-linux-6.12rc2-builds.patch -# bcm53xx -if [ "$platform" = "bcm53xx" ]; then - # libpfring - sed -i '/CONFIGURE_VARS +=/iEXTRA_CFLAGS += -Wno-int-conversion\n' feeds/packages/libs/libpfring/Makefile -fi - # clang if [ "$KERNEL_CLANG_LTO" = "y" ]; then # xtables-addons module diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 393e8ffb7..0bedf5310 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -147,15 +147,3 @@ curl -s $mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package # sms-tools mkdir -p feeds/packages/utils/sms-tool/patches curl -s $mirror/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch > feeds/packages/utils/sms-tool/patches/900-fix-incompatible-pointer-type-error-for-signal-function.patch - -# bcm53xx -if [ "$platform" = "bcm53xx" ]; then - # mtd - sed -i 's/=1 -Wall/=1 -Wall -Wno-implicit-function-declaration/g' package/system/mtd/Makefile - # uwsgi - sed -i '/MAKE_VARS+=/iTARGET_CFLAGS += -Wno-incompatible-pointer-types\n' feeds/packages/net/uwsgi/Makefile - # libsoxr - sed -i '/CMAKE_INSTALL/iPKG_BUILD_FLAGS:=no-lto no-mold\n' feeds/packages/libs/libsoxr/Makefile - # wsdd2 - sed -i '/Build\/Compile/iTARGET_CFLAGS += -Wno-error -Wno-int-conversion\n' feeds/packages/net/wsdd2/Makefile -fi diff --git a/openwrt/scripts/99_clean_build_cache.sh b/openwrt/scripts/99_clean_build_cache.sh index f776b6d85..32ba91afa 100644 --- a/openwrt/scripts/99_clean_build_cache.sh +++ b/openwrt/scripts/99_clean_build_cache.sh @@ -1,8 +1,6 @@ rm -rf bin -rm -rf build_dir/target-aarch64_generic_musl/root-rockchip build_dir/target-x86_64_musl/root-x86 build_dir/target-arm_cortex-a9_musl_eabi/root-bcm53xx -rm -rf build_dir/target-aarch64_generic_musl/root.orig-rockchip build_dir/target-x86_64_musl/root.orig-x86 build_dir/target-arm_cortex-a9_musl_eabi/root.orig-bcm53xx +rm -rf build_dir/target-aarch64_generic_musl/root-rockchip build_dir/target-x86_64_musl/root-x86 rm -rf staging_dir/target-aarch64_generic_musl/root-rockchip staging_dir/target-x86_64_musl/root-x86 -rm -rf staging_dir/packages/rockchip staging_dir/packages/x86 staging_dir/target-arm_cortex-a9_musl_eabi/root-bcm53xx rm -rf dl/geo* rm -rf tmp/.config* CURRENT_DATE=$(date +%s) From be07b118e28737f8783bee631c3c8ebd25168718 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 16 Sep 2025 23:07:46 +0800 Subject: [PATCH 295/425] mt76: maintained as a standalone package Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 32c3e5e06..d3b619833 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -166,6 +166,7 @@ rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware # mt76 +rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile curl -s $mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch From 517bd7aa775db6363c11c57d91a3784838c717bb Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 21 Sep 2025 14:10:20 +0800 Subject: [PATCH 296/425] linux-6.12: bump to 6.12.48 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index db2569539..dd7f683f1 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .47 -LINUX_KERNEL_HASH-6.12.47 = e82fe40871743048226987bd349ef107168b15aab90140e872ca4ed470922e25 +LINUX_VERSION-6.12 = .48 +LINUX_KERNEL_HASH-6.12.48 = 5bf9eb676751bf48978e38363c772298b41a75336d5038ed6d37012399471db2 From bd611afef52eb215428b8415949ceae2fbfada81 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 21 Sep 2025 14:10:35 +0800 Subject: [PATCH 297/425] OpenWrt 24.10.3 Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 4 ---- tags/v24 | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 0bedf5310..9bc01592d 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -61,10 +61,6 @@ if [ "$USE_GCC15" = y ]; then # gmp mkdir -p package/libs/gmp/patches curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch > package/libs/gmp/patches/001-fix-build-with-gcc-15.patch - # htop - 24.10-NEXT - HTOP_VERSION=3.4.1 - HTOP_HASH=af9ec878f831b7c27d33e775c668ec79d569aa781861c995a0fbadc1bdb666cf - sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$HTOP_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$HTOP_HASH/" feeds/packages/admin/htop/Makefile # libtirpc sed -i '/TARGET_CFLAGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/libtirpc/Makefile # libsepol diff --git a/tags/v24 b/tags/v24 index 957950647..7c77343c5 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.2 +24.10.3 From 9d310babd8561f86a9c63befd8737131a40a28e2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 21 Sep 2025 14:48:26 +0800 Subject: [PATCH 298/425] mt76: update to 2025-09-15 & mac80211: update to 6.16.8 Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 9 +- ...ix-build-with-mac80211-6.11-backport.patch | 124 ------------------ ...ix-build-with-mac80211-6.14-backport.patch | 34 ----- openwrt/scripts/01-prepare_base-mainline.sh | 4 +- 4 files changed, 6 insertions(+), 165 deletions(-) delete mode 100644 openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch delete mode 100644 openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index ef12fe5f0..2e4da90a1 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2025-05-21 -PKG_SOURCE_VERSION:=3e161d0cf3c74bbb39e221d5aee37c50d013d052 -PKG_MIRROR_HASH:=3e5145eb65e170e62cee4e6b5cc2c17ee27a519272945536221ac733cd208204 +PKG_SOURCE_DATE:=2025-09-15 +PKG_SOURCE_VERSION:=6467af3bcf1154c2ceb032c903d533f0c718bbc2 +PKG_MIRROR_HASH:=98781ea57cdc97bc63ecb2c1d4004964f2a10663987887445f1c71b76610cd96 PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 @@ -41,7 +41,8 @@ define KernelPackage/mt76-default DEPENDS:= \ +kmod-mac80211 \ +@DRIVER_11AC_SUPPORT \ - +@KERNEL_PAGE_POOL + +@KERNEL_PAGE_POOL \ + @!TARGET_uml endef define KernelPackage/mt76 diff --git a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch b/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch deleted file mode 100644 index 910a8bd3b..000000000 --- a/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch +++ /dev/null @@ -1,124 +0,0 @@ ---- a/mt7603/soc.c -+++ b/mt7603/soc.c -@@ -52,15 +52,12 @@ error: - return ret; - } - --static int --mt76_wmac_remove(struct platform_device *pdev) -+static void mt76_wmac_remove(struct platform_device *pdev) - { - struct mt76_dev *mdev = platform_get_drvdata(pdev); - struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); - - mt7603_unregister_device(dev); -- -- return 0; - } - - static const struct of_device_id of_wmac_match[] = { -@@ -74,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2); - - struct platform_driver mt76_wmac_driver = { - .probe = mt76_wmac_probe, -- .remove = mt76_wmac_remove, -+ .remove_new = mt76_wmac_remove, - .driver = { - .name = "mt76_wmac", - .of_match_table = of_wmac_match, ---- a/mt7615/mt7615_trace.h -+++ b/mt7615/mt7615_trace.h -@@ -14,7 +14,7 @@ - - #define MAXNAME 32 - #define DEV_ENTRY __array(char, wiphy_name, 32) --#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ -+#define DEV_ASSIGN strscpy(__entry->wiphy_name, \ - wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) - #define DEV_PR_FMT "%s" - #define DEV_PR_ARG __entry->wiphy_name ---- a/mt7615/soc.c -+++ b/mt7615/soc.c -@@ -45,13 +45,11 @@ static int mt7622_wmac_probe(struct plat - return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map); - } - --static int mt7622_wmac_remove(struct platform_device *pdev) -+static void mt7622_wmac_remove(struct platform_device *pdev) - { - struct mt7615_dev *dev = platform_get_drvdata(pdev); - - mt7615_unregister_device(dev); -- -- return 0; - } - - static const struct of_device_id mt7622_wmac_of_match[] = { -@@ -65,7 +63,7 @@ struct platform_driver mt7622_wmac_drive - .of_match_table = mt7622_wmac_of_match, - }, - .probe = mt7622_wmac_probe, -- .remove = mt7622_wmac_remove, -+ .remove_new = mt7622_wmac_remove, - }; - - MODULE_FIRMWARE(MT7622_FIRMWARE_N9); ---- a/mt76x02_trace.h -+++ b/mt76x02_trace.h -@@ -14,7 +14,7 @@ - - #define MAXNAME 32 - #define DEV_ENTRY __array(char, wiphy_name, 32) --#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ -+#define DEV_ASSIGN strscpy(__entry->wiphy_name, \ - wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) - #define DEV_PR_FMT "%s" - #define DEV_PR_ARG __entry->wiphy_name ---- a/mt7915/soc.c -+++ b/mt7915/soc.c -@@ -1283,13 +1283,11 @@ free_device: - return ret; - } - --static int mt798x_wmac_remove(struct platform_device *pdev) -+static void mt798x_wmac_remove(struct platform_device *pdev) - { - struct mt7915_dev *dev = platform_get_drvdata(pdev); - - mt7915_unregister_device(dev); -- -- return 0; - } - - static const struct of_device_id mt798x_wmac_of_match[] = { -@@ -1306,7 +1304,7 @@ struct platform_driver mt798x_wmac_drive - .of_match_table = mt798x_wmac_of_match, - }, - .probe = mt798x_wmac_probe, -- .remove = mt798x_wmac_remove, -+ .remove_new = mt798x_wmac_remove, - }; - - MODULE_FIRMWARE(MT7986_FIRMWARE_WA); ---- a/trace.h -+++ b/trace.h -@@ -14,7 +14,7 @@ - - #define MAXNAME 32 - #define DEV_ENTRY __array(char, wiphy_name, 32) --#define DEVICE_ASSIGN strlcpy(__entry->wiphy_name, \ -+#define DEVICE_ASSIGN strscpy(__entry->wiphy_name, \ - wiphy_name(dev->hw->wiphy), MAXNAME) - #define DEV_PR_FMT "%s" - #define DEV_PR_ARG __entry->wiphy_name ---- a/usb_trace.h -+++ b/usb_trace.h -@@ -14,7 +14,7 @@ - - #define MAXNAME 32 - #define DEV_ENTRY __array(char, wiphy_name, 32) --#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ -+#define DEV_ASSIGN strscpy(__entry->wiphy_name, \ - wiphy_name(dev->hw->wiphy), MAXNAME) - #define DEV_PR_FMT "%s " - #define DEV_PR_ARG __entry->wiphy_name diff --git a/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch b/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch deleted file mode 100644 index b34345c09..000000000 --- a/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch +++ /dev/null @@ -1,34 +0,0 @@ ---- a/mac80211.c -+++ b/mac80211.c -@@ -1704,7 +1704,7 @@ s8 mt76_get_power_bound(struct mt76_phy - EXPORT_SYMBOL_GPL(mt76_get_power_bound); - - int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -- int *dbm) -+ unsigned int link_id, int *dbm) - { - struct mt76_phy *phy = mt76_vif_phy(hw, vif); - int n_chains, delta; ---- a/mt76.h -+++ b/mt76.h -@@ -1508,7 +1508,7 @@ int mt76_get_min_avg_rssi(struct mt76_de - s8 mt76_get_power_bound(struct mt76_phy *phy, s8 txpower); - - int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -- int *dbm); -+ unsigned int link_id, int *dbm); - int mt76_init_sar_power(struct ieee80211_hw *hw, - const struct cfg80211_sar_specs *sar); - int mt76_get_sar_power(struct mt76_phy *phy, ---- a/mt7996/main.c -+++ b/mt7996/main.c -@@ -668,7 +668,8 @@ static void mt7996_configure_filter(stru - } - - static int --mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) -+mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ unsigned int link_id, int *dbm) - { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index d3b619833..85af43302 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -169,14 +169,12 @@ git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile -curl -s $mirror/openwrt/patch/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch > package/kernel/mt76/patches/100-fix-build-with-mac80211-6.11-backport.patch curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch -curl -s $mirror/openwrt/patch/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch > package/kernel/mt76/patches/102-fix-build-with-mac80211-6.14-backport.patch # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - 6.15.6 +# mac80211 - 6.16.8 rm -rf package/kernel/mac80211 git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 From 051a0062878ac2772ca92a272a102309b5871213 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 26 Sep 2025 22:55:05 +0800 Subject: [PATCH 299/425] linux-6.12: bump to 6.12.49 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index dd7f683f1..438cd31bb 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .48 -LINUX_KERNEL_HASH-6.12.48 = 5bf9eb676751bf48978e38363c772298b41a75336d5038ed6d37012399471db2 +LINUX_VERSION-6.12 = .49 +LINUX_KERNEL_HASH-6.12.49 = 234621e146dacce2241049555d550e4f7a6bde67ccd7ef232d47ac8145425526 From f0924497469fd777b88a745249ef64c1426ddeb9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 26 Sep 2025 22:55:49 +0800 Subject: [PATCH 300/425] build.sh: add std build type * test Signed-off-by: sbwml --- openwrt/24-config-std-common | 270 +++++++++++++++++++++++++++++++++++ openwrt/build.sh | 3 + 2 files changed, 273 insertions(+) create mode 100644 openwrt/24-config-std-common diff --git a/openwrt/24-config-std-common b/openwrt/24-config-std-common new file mode 100644 index 000000000..02c057f15 --- /dev/null +++ b/openwrt/24-config-std-common @@ -0,0 +1,270 @@ + +### Curl +CONFIG_PACKAGE_curl=y +CONFIG_PACKAGE_libcurl=y +CONFIG_LIBCURL_NGHTTP3=y +CONFIG_LIBCURL_NGTCP2=y +CONFIG_LIBCURL_OPENSSL=y +# CONFIG_LIBCURL_GNUTLS is not set +# CONFIG_LIBCURL_MBEDTLS is not set +# CONFIG_LIBCURL_NOSSL is not set +# CONFIG_LIBCURL_WOLFSSL is not set + +### Firewall +CONFIG_PACKAGE_nat6=y +CONFIG_PACKAGE_ip6tables-nft=y +CONFIG_PACKAGE_iptables-mod-conntrack-extra=y +CONFIG_PACKAGE_iptables-mod-iprange=y +CONFIG_PACKAGE_iptables-mod-nat-extra=y +CONFIG_PACKAGE_iptables-mod-socket=y +CONFIG_PACKAGE_iptables-mod-tproxy=y +CONFIG_PACKAGE_iptables-nft=y +CONFIG_PACKAGE_xtables-nft=y +# CONFIG_PACKAGE_iptables-legacy is not set + +# Natflow +CONFIG_PACKAGE_natflow=m + +### Zram +CONFIG_PACKAGE_zram-swap=y +CONFIG_ZRAM_DEF_COMP_LZ4=y + +### Busybox +CONFIG_BUSYBOX_CUSTOM=y +CONFIG_BUSYBOX_CONFIG_ASH_HELP=y +CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_HISTORY=1024 +CONFIG_BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY=y +CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +CONFIG_BUSYBOX_CONFIG_FEATURE_SH_HISTFILESIZE=y +CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y + +### Dnsmasq +CONFIG_PACKAGE_dnsmasq-full=y +CONFIG_PACKAGE_dnsmasq_full_ipset=y +# CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set +# CONFIG_PACKAGE_dnsmasq is not set + +### Luci +CONFIG_PACKAGE_luci=y +CONFIG_PACKAGE_luci-lib-base=y +CONFIG_PACKAGE_luci-lib-ip=y +CONFIG_PACKAGE_luci-lib-ipkg=y +CONFIG_PACKAGE_luci-lib-jsonc=y +CONFIG_PACKAGE_luci-lib-nixio=y +CONFIG_PACKAGE_luci-nginx=y +CONFIG_PACKAGE_luci-proto-wireguard=y +CONFIG_PACKAGE_luci-theme-argon=y +CONFIG_LUCI_LANG_zh_Hans=y +# CONFIG_LUCI_CSSTIDY is not set +# CONFIG_LUCI_JSMIN is not set + +### Nginx +CONFIG_PACKAGE_nginx-ssl=y +CONFIG_PACKAGE_nginx-mod-brotli=y +CONFIG_PACKAGE_nginx-mod-luci=y +CONFIG_PACKAGE_nginx-mod-rtmp=y +CONFIG_PACKAGE_nginx-mod-stream=y +CONFIG_PACKAGE_nginx-mod-ubus=y +CONFIG_PACKAGE_nginx-mod-zstd=y +CONFIG_PACKAGE_nginx-ssl-util=y +CONFIG_NGINX_DAV=y +CONFIG_NGINX_HTTP_AUTH_BASIC=y +CONFIG_NGINX_HTTP_QUIC=y +CONFIG_NGINX_HTTP_REAL_IP=y +CONFIG_NGINX_HTTP_SUB=y +CONFIG_NGINX_STREAM_REAL_IP=y + +### APPS +CONFIG_PACKAGE_luci-app-airconnect=y +CONFIG_PACKAGE_luci-app-airplay2=y +CONFIG_PACKAGE_luci-app-argon-config=y +CONFIG_PACKAGE_luci-app-autoreboot=y +CONFIG_PACKAGE_luci-app-commands=y +CONFIG_PACKAGE_luci-app-cpufreq=y +CONFIG_PACKAGE_luci-app-ddns=y +CONFIG_PACKAGE_luci-app-diskman=y +CONFIG_PACKAGE_luci-app-eqos=y +CONFIG_PACKAGE_luci-app-quickfile=y +CONFIG_PACKAGE_luci-app-frpc=y +CONFIG_PACKAGE_luci-app-mosdns=y +CONFIG_PACKAGE_luci-app-natmap=y +CONFIG_PACKAGE_luci-app-netspeedtest=y +CONFIG_PACKAGE_luci-app-nlbwmon=y +CONFIG_PACKAGE_luci-app-oaf=y +CONFIG_PACKAGE_luci-app-ramfree=y +CONFIG_PACKAGE_luci-app-socat=y +CONFIG_PACKAGE_luci-app-sqm=y +CONFIG_PACKAGE_luci-app-ttyd=y +CONFIG_PACKAGE_luci-app-upnp=y +CONFIG_PACKAGE_luci-app-usb-printer=y +CONFIG_PACKAGE_luci-app-vlmcsd=y +CONFIG_PACKAGE_luci-app-webdav=y +CONFIG_PACKAGE_luci-app-wolplus=y +CONFIG_PACKAGE_luci-app-zerotier=y + +### ImmortalWrt Proxy - nft +CONFIG_PACKAGE_luci-app-homeproxy=y + +### DDNS Scripts +CONFIG_PACKAGE_ddns-scripts=y +CONFIG_PACKAGE_ddns-scripts-aliyun=y +CONFIG_PACKAGE_ddns-scripts-cloudflare=y +CONFIG_PACKAGE_ddns-scripts-dnspod=y +CONFIG_PACKAGE_ddns-scripts-freedns=y +CONFIG_PACKAGE_ddns-scripts-godaddy=y +CONFIG_PACKAGE_ddns-scripts-services=y + +### L2TP +CONFIG_PACKAGE_kmod-l2tp=y +CONFIG_PACKAGE_kmod-pppol2tp=y +CONFIG_PACKAGE_ppp-mod-pppol2tp=y +CONFIG_PACKAGE_xl2tpd=y + +### OpenSSL +CONFIG_OPENSSL_ENGINE=y +CONFIG_OPENSSL_OPTIMIZE_SPEED=y +CONFIG_OPENSSL_WITH_ASM=y +CONFIG_PACKAGE_libopenssl-afalg=y +CONFIG_PACKAGE_libopenssl-conf=y +CONFIG_PACKAGE_libopenssl-devcrypto=y +CONFIG_PACKAGE_libopenssl-legacy=y +CONFIG_PACKAGE_openssl-util=y +# CONFIG_PACKAGE_libopenssl-padlock is not set +# CONFIG_OPENSSL_WITH_ERROR_MESSAGES is not set + +### Share Network +CONFIG_PACKAGE_usbmuxd=y +CONFIG_PACKAGE_kmod-usb-net-rndis=y +CONFIG_PACKAGE_kmod-usb-net-ipheth=y + +### Kernel Modules +CONFIG_PACKAGE_kmod-bonding=y +CONFIG_PACKAGE_kmod-br-netfilter=y +CONFIG_PACKAGE_kmod-button-hotplug=y +CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y +CONFIG_PACKAGE_kmod-crypto-sha256=y +CONFIG_PACKAGE_kmod-fs-exfat=y +CONFIG_PACKAGE_kmod-fs-f2fs=y +CONFIG_PACKAGE_kmod-fs-ntfs3=y +CONFIG_PACKAGE_kmod-fs-vfat=y +CONFIG_PACKAGE_kmod-fs-xfs=y +CONFIG_PACKAGE_kmod-hwmon-pwmfan=y +CONFIG_PACKAGE_kmod-ikconfig=y +CONFIG_PACKAGE_kmod-inet-diag=y +CONFIG_PACKAGE_kmod-ipsec4=y +CONFIG_PACKAGE_kmod-ipsec6=y +CONFIG_PACKAGE_kmod-ipt-nat6=y +CONFIG_PACKAGE_kmod-ipt-tproxy=y +CONFIG_PACKAGE_kmod-iptunnel6=y +CONFIG_PACKAGE_kmod-mac80211=y +CONFIG_PACKAGE_kmod-nf-socket=y +CONFIG_PACKAGE_kmod-nft-fullcone=y +CONFIG_PACKAGE_kmod-nft-offload=y +CONFIG_PACKAGE_kmod-nft-socket=y +CONFIG_PACKAGE_kmod-nft-tproxy=y +CONFIG_PACKAGE_kmod-nls-cp936=y +CONFIG_PACKAGE_kmod-nls-cp950=y +CONFIG_PACKAGE_kmod-sched-bpf=y +CONFIG_PACKAGE_kmod-sched-cake=y +CONFIG_PACKAGE_kmod-sched-core=y +CONFIG_PACKAGE_kmod-sched=y +CONFIG_PACKAGE_kmod-tcp-bbr3=y +CONFIG_PACKAGE_kmod-tcp-brutal=y +CONFIG_PACKAGE_kmod-tls=y +CONFIG_PACKAGE_kmod-tun=y +CONFIG_PACKAGE_kmod-usb-audio=y +CONFIG_PACKAGE_kmod-usb-hid=y +CONFIG_PACKAGE_kmod-usb-storage-uas=y +CONFIG_PACKAGE_kmod-usb2-pci=y +CONFIG_PACKAGE_kmod-usb2=y +CONFIG_PACKAGE_kmod-usb3=y +CONFIG_PACKAGE_kmod-veth=y +CONFIG_PACKAGE_kmod-xdp-sockets-diag=y + +### Kernel Modules - out-of-tree driver +CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y + +### Kernel Modules - USB WiFi Adapter +CONFIG_PACKAGE_kmod-mt7921u=y + +### Utilities +CONFIG_PACKAGE_bash=y +CONFIG_PACKAGE_bash-completion=y +CONFIG_PACKAGE_dmesg=y +CONFIG_PACKAGE_dosfstools=y +CONFIG_PACKAGE_exfat-fsck=y +CONFIG_PACKAGE_exfat-mkfs=y +CONFIG_PACKAGE_f2fs-tools=y +CONFIG_PACKAGE_fdisk=y +CONFIG_PACKAGE_file=y +CONFIG_PACKAGE_fstrim=y +CONFIG_PACKAGE_ftp=y +CONFIG_PACKAGE_gdisk=y +CONFIG_PACKAGE_htop=y +CONFIG_PACKAGE_iperf3=y +CONFIG_PACKAGE_iputils-ping=y +CONFIG_PACKAGE_lrzsz=y +CONFIG_PACKAGE_lsblk=y +CONFIG_PACKAGE_lscpu=y +CONFIG_PACKAGE_lsof=y +# CONFIG_PACKAGE_nethogs is not set +CONFIG_PACKAGE_openssh-sftp-server=y +CONFIG_PACKAGE_pciutils=y +CONFIG_PACKAGE_qrencode=y +CONFIG_PACKAGE_rename=y +CONFIG_PACKAGE_resize2fs=y +CONFIG_PACKAGE_rsync=y +CONFIG_PACKAGE_screen=y +CONFIG_PACKAGE_sshpass=y +CONFIG_PACKAGE_tar=y +CONFIG_PACKAGE_taskset=y +CONFIG_PACKAGE_telnet-bsd=y +CONFIG_PACKAGE_tree=y +CONFIG_PACKAGE_unzip=y +CONFIG_PACKAGE_usbutils=y +CONFIG_PACKAGE_vim=y +CONFIG_PACKAGE_wget-ssl=y +CONFIG_PACKAGE_wpad-openssl=y +CONFIG_PACKAGE_xfs-admin=y +CONFIG_PACKAGE_xfs-fsck=y +CONFIG_PACKAGE_xfs-growfs=y +CONFIG_PACKAGE_xfs-mkfs=y +CONFIG_PACKAGE_xz-utils=y +CONFIG_PACKAGE_xz=y +CONFIG_PACKAGE_zip=y +CONFIG_PACKAGE_zoneinfo-asia=y + +### GNU Core Utilities +CONFIG_PACKAGE_coreutils=y +CONFIG_PACKAGE_coreutils-cat=y +CONFIG_PACKAGE_coreutils-chmod=y +CONFIG_PACKAGE_coreutils-chown=y +CONFIG_PACKAGE_coreutils-chroot=y +CONFIG_PACKAGE_coreutils-cp=y +CONFIG_PACKAGE_coreutils-date=y +CONFIG_PACKAGE_coreutils-dd=y +CONFIG_PACKAGE_coreutils-dircolors=y +CONFIG_PACKAGE_coreutils-ls=y +CONFIG_PACKAGE_coreutils-mkdir=y +CONFIG_PACKAGE_coreutils-mv=y +CONFIG_PACKAGE_coreutils-nproc=y +CONFIG_PACKAGE_coreutils-rm=y +CONFIG_PACKAGE_coreutils-sha1sum=y +CONFIG_PACKAGE_coreutils-sha512sum=y +CONFIG_PACKAGE_coreutils-sleep=y +CONFIG_PACKAGE_coreutils-timeout=y +CONFIG_PACKAGE_coreutils-truncate=y + +### procps-ng Utilities +CONFIG_PACKAGE_procps-ng=y +CONFIG_PACKAGE_procps-ng-free=y +CONFIG_PACKAGE_procps-ng-ps=y +CONFIG_PACKAGE_procps-ng-top=y + +### Version +CONFIG_IMAGEOPT=y +CONFIG_VERSIONOPT=y +CONFIG_VERSION_FILENAMES=y + +### ZLIB +CONFIG_ZLIB_OPTIMIZE_SPEED=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 3a28ac2f1..4bac0f61c 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -208,6 +208,7 @@ print_status "ENABLE_LOCAL_KMOD" "$ENABLE_LOCAL_KMOD" print_status "BUILD_FAST" "$BUILD_FAST" print_status "ENABLE_CCACHE" "$ENABLE_CCACHE" print_status "MINIMAL_BUILD" "$MINIMAL_BUILD" +print_status "STD_BUILD" "$STD_BUILD" print_status "KERNEL_CLANG_LTO" "$KERNEL_CLANG_LTO" "$GREEN_COLOR" "$YELLOW_COLOR" "\n" # clean old files @@ -321,6 +322,8 @@ fi if [ "$MINIMAL_BUILD" = "y" ]; then curl -s $mirror/openwrt/24-config-minimal-common >> .config echo 'VERSION_TYPE="minimal"' >> package/base-files/files/usr/lib/os-release +elif [ "$STD_BUILD" = "y" ]; then + curl -s $mirror/openwrt/24-config-std-common >> .config else curl -s $mirror/openwrt/24-config-common >> .config [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config From 0c113975d00bc80efcfb0086b7e394ab029b3d4b Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 9 Oct 2025 00:12:58 +0800 Subject: [PATCH 301/425] linux-6.12: bump to 6.12.51 Signed-off-by: sbwml --- openwrt/24-config-common | 2 -- openwrt/build.sh | 5 ++++- tags/kernel-6.12 | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 93fd86623..fccaffc0f 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -71,8 +71,6 @@ CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_luci-proto-wireguard=y CONFIG_PACKAGE_luci-theme-argon=y -CONFIG_PACKAGE_luci-theme-material=y -CONFIG_PACKAGE_luci-theme-openwrt-2020=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set diff --git a/openwrt/build.sh b/openwrt/build.sh index 4bac0f61c..50a808a58 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -409,7 +409,10 @@ if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then fi # nanopi-r76s -[ "$platform" = "rk3576" ] && sed -i '/samba4/d' .config +[ "$platform" = "rk3576" ] && { + sed -i '/samba4/d' .config + sed -i '/qbittorrent/d' .config +} # Toolchain Cache if [ "$BUILD_FAST" = "y" ]; then diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 438cd31bb..477c1b5d4 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .49 -LINUX_KERNEL_HASH-6.12.49 = 234621e146dacce2241049555d550e4f7a6bde67ccd7ef232d47ac8145425526 +LINUX_VERSION-6.12 = .51 +LINUX_KERNEL_HASH-6.12.51 = 2d55ad149ca7d9ef82595c669430650030cbf9afbbeb42e5cd9b4ba3cc1a7221 From 021c0f4b77258923a7a3c735565e19d1acb410b3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 21 Oct 2025 12:35:07 +0800 Subject: [PATCH 302/425] linux-6.12: bump to 6.12.54 Signed-off-by: sbwml --- tags/kernel-6.12 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 index 477c1b5d4..1b89660b4 100644 --- a/tags/kernel-6.12 +++ b/tags/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .51 -LINUX_KERNEL_HASH-6.12.51 = 2d55ad149ca7d9ef82595c669430650030cbf9afbbeb42e5cd9b4ba3cc1a7221 +LINUX_VERSION-6.12 = .54 +LINUX_KERNEL_HASH-6.12.54 = 1b0dcd3390efeec44e528748609bafcf36eae895bb68c8f62ac5e5940943de62 From 7d5047dd50f9b8cdf244c5165cf1f4ef8ecf7b89 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 21 Oct 2025 12:35:38 +0800 Subject: [PATCH 303/425] OpenWrt 24.10.4 Signed-off-by: sbwml --- openwrt/24-config-musl-x86 | 6 +- ...pd-RFC-9096-compliance-openwrt-24.10.patch | 320 ------------------ ...work-add-option-for-ipv6-max-plt-vlt.patch | 23 -- openwrt/scripts/00-prepare_base.sh | 7 - tags/v24 | 2 +- 5 files changed, 5 insertions(+), 353 deletions(-) delete mode 100644 openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch delete mode 100644 openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch diff --git a/openwrt/24-config-musl-x86 b/openwrt/24-config-musl-x86 index 7e25ae389..09eee43fb 100644 --- a/openwrt/24-config-musl-x86 +++ b/openwrt/24-config-musl-x86 @@ -23,8 +23,10 @@ CONFIG_TARGET_ROOTFS_PARTSIZE=944 # CONFIG_KERNEL_KALLSYMS is not set ### Kernel driver +CONFIG_PACKAGE_kmod-i40e=y CONFIG_PACKAGE_kmod-igb=y CONFIG_PACKAGE_kmod-igc=y +CONFIG_PACKAGE_kmod-ixgbe=y CONFIG_PACKAGE_kmod-mlx4-core=y CONFIG_PACKAGE_kmod-mlx5-core=y CONFIG_PACKAGE_kmod-mt76x2=y @@ -32,14 +34,14 @@ CONFIG_PACKAGE_kmod-mt7921e=y CONFIG_PACKAGE_kmod-mt7921u=y CONFIG_PACKAGE_kmod-mt7922-firmware=y CONFIG_PACKAGE_kmod-ngbe=y +CONFIG_PACKAGE_kmod-nvme=y CONFIG_PACKAGE_kmod-r8101=y CONFIG_PACKAGE_kmod-r8125=y CONFIG_PACKAGE_kmod-r8126=y CONFIG_PACKAGE_kmod-r8127=y CONFIG_PACKAGE_kmod-r8168=y -CONFIG_PACKAGE_kmod-txgbe=y # CONFIG_PACKAGE_kmod-r8169 is not set -CONFIG_PACKAGE_kmod-nvme=y +CONFIG_PACKAGE_kmod-txgbe=y ### Display & Extra Drivers CONFIG_PACKAGE_i915-firmware-huc=y diff --git a/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch b/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch deleted file mode 100644 index d6281669f..000000000 --- a/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch +++ /dev/null @@ -1,320 +0,0 @@ -From 726ca5340823e2d5f3b5e7b6ad83e52ba3be14a9 Mon Sep 17 00:00:00 2001 -From: Aviana Cruz -Date: Sat, 16 Sep 2023 15:04:12 +0000 -Subject: [PATCH] odhcpd: improve RFC 9096 compliance - -and allow configuring upper limit for preferred and valid lifetime. - -Signed-off-by: Aviana Cruz ---- - README | 12 ++++++------ - src/config.c | 35 +++++++++++++++++++++------------- - src/dhcpv6-ia.c | 50 ++++++++++++++++++++++++++++++------------------- - src/odhcpd.h | 8 ++++++-- - src/router.c | 17 ++++++++--------- - 5 files changed, 73 insertions(+), 49 deletions(-) - ---- a/README -+++ b/README -@@ -116,7 +116,9 @@ domain list Sear - leasetime string 12h DHCPv4 address leasetime - start integer 100 DHCPv4 pool start - limit integer 150 DHCPv4 pool size --preferred_lifetime string 7d Value for the preferred lifetime -+max_preferred_lifetime string 45m Upper limit for the preferred lifetime -+ for a prefix -+max_valid_lifetime string 90m Upper limit for the valid lifetime - for a prefix - ra_default integer 0 Override default route - 0: default, 1: ignore no public address, 2: ignore all -@@ -131,11 +133,9 @@ ra_maxinterval integer 600 Maximum ti - sending unsolicited RA - ra_mininterval integer 200 Minimum time allowed between - sending unsolicited RA --ra_lifetime integer 1800 Value to be placed in Router -- Lifetime field of RA --ra_useleasetime bool 0 Use configured leasetime as -- limit for the preferred and -- valid lifetime of a prefix -+ra_lifetime integer 2700 Value to be placed in Router -+ Lifetime field of RA. Not recommended to be -+ more than 2700 (RFC9096). - ra_reachabletime integer 0 Reachable Time in milliseconds to be - advertised in RA messages - ra_retranstime integer 0 Retransmit Time in milliseconds to be ---- a/src/config.c -+++ b/src/config.c -@@ -79,7 +79,6 @@ enum { - IFACE_ATTR_RA_MININTERVAL, - IFACE_ATTR_RA_MAXINTERVAL, - IFACE_ATTR_RA_LIFETIME, -- IFACE_ATTR_RA_USELEASETIME, - IFACE_ATTR_RA_REACHABLETIME, - IFACE_ATTR_RA_RETRANSTIME, - IFACE_ATTR_RA_HOPLIMIT, -@@ -91,7 +90,8 @@ enum { - IFACE_ATTR_NDPROXY_ROUTING, - IFACE_ATTR_NDPROXY_SLAVE, - IFACE_ATTR_PREFIX_FILTER, -- IFACE_ATTR_PREFERRED_LIFETIME, -+ IFACE_ATTR_MAX_PREFERRED_LIFETIME, -+ IFACE_ATTR_MAX_VALID_LIFETIME, - IFACE_ATTR_NTP, - IFACE_ATTR_MAX - }; -@@ -134,7 +134,6 @@ static const struct blobmsg_policy iface - [IFACE_ATTR_RA_MININTERVAL] = { .name = "ra_mininterval", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_MAXINTERVAL] = { .name = "ra_maxinterval", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_LIFETIME] = { .name = "ra_lifetime", .type = BLOBMSG_TYPE_INT32 }, -- [IFACE_ATTR_RA_USELEASETIME] = { .name = "ra_useleasetime", .type = BLOBMSG_TYPE_BOOL }, - [IFACE_ATTR_RA_REACHABLETIME] = { .name = "ra_reachabletime", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_RETRANSTIME] = { .name = "ra_retranstime", .type = BLOBMSG_TYPE_INT32 }, - [IFACE_ATTR_RA_HOPLIMIT] = { .name = "ra_hoplimit", .type = BLOBMSG_TYPE_INT32 }, -@@ -144,7 +143,8 @@ static const struct blobmsg_policy iface - [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL }, - [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL }, - [IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING }, -- [IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING }, -+ [IFACE_ATTR_MAX_PREFERRED_LIFETIME] = { .name = "max_preferred_lifetime", .type = BLOBMSG_TYPE_STRING }, -+ [IFACE_ATTR_MAX_VALID_LIFETIME] = { .name = "max_valid_lifetime", .type = BLOBMSG_TYPE_STRING }, - [IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY }, - }; - -@@ -215,7 +215,8 @@ static void set_interface_defaults(struc - iface->ndp = MODE_DISABLED; - iface->learn_routes = 1; - iface->dhcp_leasetime = 43200; -- iface->preferred_lifetime = 604800; /* rfc4861#section-6.2.1: AdvPreferredLifetime 7 days */ -+ iface->max_preferred_lifetime = ND_PREFERRED_LIMIT; -+ iface->max_valid_lifetime = ND_VALID_LIMIT; - iface->dhcpv4_start.s_addr = htonl(START_DEFAULT); - iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1); - iface->dhcpv6_assignall = true; -@@ -647,15 +648,26 @@ int config_parse_interface(void *data, s - - } - -- if ((c = tb[IFACE_ATTR_PREFERRED_LIFETIME])) { -+ if ((c = tb[IFACE_ATTR_MAX_PREFERRED_LIFETIME])) { - double time = parse_leasetime(c); - -- if (time >= 0) -- iface->preferred_lifetime = time; -- else -+ if (time >= 0) { -+ iface->max_preferred_lifetime = time; -+ } else { - syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", -- iface_attrs[IFACE_ATTR_PREFERRED_LIFETIME].name, iface->name); -+ iface_attrs[IFACE_ATTR_MAX_PREFERRED_LIFETIME].name, iface->name); -+ } -+ } -+ -+ if ((c = tb[IFACE_ATTR_MAX_VALID_LIFETIME])) { -+ double time = parse_leasetime(c); - -+ if (time >= 0) { -+ iface->max_valid_lifetime = time; -+ } else { -+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", -+ iface_attrs[IFACE_ATTR_MAX_VALID_LIFETIME].name, iface->name); -+ } - } - - if ((c = tb[IFACE_ATTR_START])) { -@@ -979,9 +991,6 @@ int config_parse_interface(void *data, s - if ((c = tb[IFACE_ATTR_RA_LIFETIME])) - iface->ra_lifetime = blobmsg_get_u32(c); - -- if ((c = tb[IFACE_ATTR_RA_USELEASETIME])) -- iface->ra_useleasetime = blobmsg_get_bool(c); -- - if ((c = tb[IFACE_ATTR_RA_DNS])) - iface->ra_dns = blobmsg_get_bool(c); - ---- a/src/dhcpv6-ia.c -+++ b/src/dhcpv6-ia.c -@@ -120,7 +120,7 @@ static inline bool valid_prefix_length(c - - static inline bool valid_addr(const struct odhcpd_ipaddr *addr, time_t now) - { -- return (addr->prefix <= 96 && addr->preferred_lt > (uint32_t)now); -+ return (addr->prefix <= 96 && addr->valid_lt > (uint32_t)now && addr->preferred_lt > (uint32_t)now); - } - - static size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen) -@@ -1037,17 +1037,27 @@ static size_t build_ia(uint8_t *buf, siz - } - - if (a) { -- uint32_t leasetime, preferred_lt; -+ uint32_t leasetime; - - if (a->leasetime) { - leasetime = a->leasetime; -- preferred_lt = a->leasetime; - } else { - leasetime = iface->dhcp_leasetime; -- preferred_lt = iface->preferred_lifetime; - } - -- uint32_t valid_lt = leasetime; -+ uint32_t floor_preferred_lifetime, floor_valid_lifetime; /* For calculating T1 / T2 */ -+ -+ if (iface->max_preferred_lifetime && iface->max_preferred_lifetime < leasetime) { -+ floor_preferred_lifetime = iface->max_preferred_lifetime; -+ } else { -+ floor_preferred_lifetime = leasetime; -+ } -+ -+ if (iface->max_valid_lifetime && iface->max_valid_lifetime < leasetime) { -+ floor_valid_lifetime = iface->max_valid_lifetime; -+ } else { -+ floor_valid_lifetime = leasetime; -+ } - - struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6; - size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len; -@@ -1071,15 +1081,20 @@ static size_t build_ia(uint8_t *buf, siz - prefix_preferred_lt = addrs[i].preferred_lt; - prefix_valid_lt = addrs[i].valid_lt; - -- if (prefix_preferred_lt != UINT32_MAX) -+ if (prefix_preferred_lt != UINT32_MAX) { - prefix_preferred_lt -= now; - -- if (prefix_preferred_lt > preferred_lt) -- prefix_preferred_lt = preferred_lt; -+ if (iface->max_preferred_lifetime && prefix_preferred_lt > iface->max_preferred_lifetime) -+ prefix_preferred_lt = iface->max_preferred_lifetime; -+ } - -- if (prefix_valid_lt != UINT32_MAX) -+ if (prefix_valid_lt != UINT32_MAX) { - prefix_valid_lt -= now; - -+ if (iface->max_valid_lifetime && prefix_valid_lt > iface->max_valid_lifetime) -+ prefix_valid_lt = iface->max_valid_lifetime; -+ } -+ - if (prefix_valid_lt > leasetime) - prefix_valid_lt = leasetime; - -@@ -1133,24 +1148,24 @@ static size_t build_ia(uint8_t *buf, siz - - /* Calculate T1 / T2 based on non-deprecated addresses */ - if (prefix_preferred_lt > 0) { -- if (prefix_preferred_lt < preferred_lt) -- preferred_lt = prefix_preferred_lt; -+ if (floor_preferred_lifetime > prefix_preferred_lt) -+ floor_preferred_lifetime = prefix_preferred_lt; - -- if (prefix_valid_lt < valid_lt) -- valid_lt = prefix_valid_lt; -+ if (floor_valid_lifetime > prefix_valid_lt) -+ floor_valid_lifetime = prefix_valid_lt; - } - } - - if (!INFINITE_VALID(a->valid_until)) - /* UINT32_MAX is RFC defined as infinite lease-time */ -- a->valid_until = (valid_lt == UINT32_MAX) ? 0 : valid_lt + now; -+ a->valid_until = (floor_valid_lifetime == UINT32_MAX) ? 0 : floor_valid_lifetime + now; - - if (!INFINITE_VALID(a->preferred_until)) - /* UINT32_MAX is RFC defined as infinite lease-time */ -- a->preferred_until = (preferred_lt == UINT32_MAX) ? 0 : preferred_lt + now; -+ a->preferred_until = (floor_preferred_lifetime == UINT32_MAX) ? 0 : floor_preferred_lifetime + now; - -- o_ia.t1 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 5 / 10); -- o_ia.t2 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 8 / 10); -+ o_ia.t1 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 5 / 10); -+ o_ia.t2 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 8 / 10); - - if (!o_ia.t1) - o_ia.t1 = htonl(1); ---- a/src/odhcpd.h -+++ b/src/odhcpd.h -@@ -37,6 +37,10 @@ - // RFC 8781 defines PREF64 option - #define ND_OPT_PREF64 38 - -+// RFC9096 defines recommended option lifetimes configuration values -+#define ND_PREFERRED_LIMIT 2700 -+#define ND_VALID_LIMIT 5400 -+ - #define INFINITE_VALID(x) ((x) == 0) - - #define _unused __attribute__((unused)) -@@ -302,7 +306,6 @@ struct interface { - bool ra_slaac; - bool ra_not_onlink; - bool ra_advrouter; -- bool ra_useleasetime; - bool ra_dns; - uint8_t pref64_length; - struct in6_addr pref64_addr; -@@ -319,7 +322,8 @@ struct interface { - uint32_t ra_retranstime; - uint32_t ra_hoplimit; - int ra_mtu; -- uint32_t preferred_lifetime; -+ uint32_t max_preferred_lifetime; -+ uint32_t max_valid_lifetime; - - // DHCP - uint32_t dhcp_leasetime; ---- a/src/router.c -+++ b/src/router.c -@@ -376,7 +376,7 @@ static int calc_adv_interval(struct inte - - static uint32_t calc_ra_lifetime(struct interface *iface, uint32_t maxival) - { -- uint32_t lifetime = 3*maxival; -+ uint32_t lifetime = maxival * 3; - - if (iface->ra_lifetime >= 0) { - lifetime = iface->ra_lifetime; -@@ -600,17 +600,16 @@ static int send_router_advert(struct int - if (addr->preferred_lt > (uint32_t)now) { - preferred_lt = TIME_LEFT(addr->preferred_lt, now); - -- if (preferred_lt > iface->preferred_lifetime) { -- /* set to possibly user mandated preferred_lt */ -- preferred_lt = iface->preferred_lifetime; -+ if (iface->max_preferred_lifetime && preferred_lt > iface->max_preferred_lifetime) { -+ preferred_lt = iface->max_preferred_lifetime; - } - } - - if (addr->valid_lt > (uint32_t)now) { - valid_lt = TIME_LEFT(addr->valid_lt, now); - -- if (iface->ra_useleasetime && valid_lt > iface->dhcp_leasetime) -- valid_lt = iface->dhcp_leasetime; -+ if (iface->max_valid_lifetime && valid_lt > iface->max_valid_lifetime) -+ valid_lt = iface->max_valid_lifetime; - } - - if (preferred_lt > valid_lt) { -@@ -663,9 +662,9 @@ static int send_router_advert(struct int - - if (default_route) { - syslog(LOG_WARNING, "A default route is present but there is no public prefix " -- "on %s thus we announce no default route by overriding ra_lifetime to 0!", iface->name); -+ "on %s thus we announce no default route by setting ra_lifetime to 0!", iface->name); - } else { -- syslog(LOG_WARNING, "No default route present, overriding ra_lifetime to 0!"); -+ syslog(LOG_WARNING, "No default route present, setting ra_lifetime to 0!"); - } - } - -@@ -730,7 +729,7 @@ static int send_router_advert(struct int - - if (iface->pref64_length) { - /* RFC 8781 § 4.1 rounding up lifetime to multiple of 8 */ -- uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : UINT16_MAX; -+ uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : (UINT16_MAX - 7); - uint8_t prefix_length_code; - uint32_t mask_a1, mask_a2; - diff --git a/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch b/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch deleted file mode 100644 index c87a1cf28..000000000 --- a/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js -+++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js -@@ -854,6 +854,20 @@ return view.extend({ - so.depends('ra', 'server'); - so.depends({ ra: 'hybrid', master: '0' }); - -+ so = ss.taboption('ipv6-ra', form.Value, 'max_preferred_lifetime', _('Max preferred lifetime')); -+ so.optional = true; -+ so.datatype = 'range(0, 2700)'; -+ so.placeholder = '2700'; -+ so.depends('ra', 'server'); -+ so.depends({ ra: 'hybrid', master: '0' }); -+ -+ so = ss.taboption('ipv6-ra', form.Value, 'max_valid_lifetime', _('Max valid lifetime')); -+ so.optional = true; -+ so.datatype = 'range(0, 5400)'; -+ so.placeholder = '5400'; -+ so.depends('ra', 'server'); -+ so.depends({ ra: 'hybrid', master: '0' }); -+ - so = ss.taboption('ipv6-ra', form.Value, 'ra_maxinterval', _('Max RA interval'), _('Maximum time allowed between sending unsolicited RA. Default is 600 seconds.')); - so.optional = true; - so.datatype = 'uinteger'; diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 2bee74df5..035baa2e1 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -332,13 +332,6 @@ sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/l # luci-compat - remove extra line breaks from description sed -i '/
/d' feeds/luci/modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm -# odhcpd RFC-9096 -mkdir -p package/network/services/odhcpd/patches -curl -s $mirror/openwrt/patch/odhcpd/001-odhcpd-RFC-9096-compliance-openwrt-24.10.patch > package/network/services/odhcpd/patches/001-odhcpd-RFC-9096-compliance.patch -pushd feeds/luci - curl -s $mirror/openwrt/patch/odhcpd/luci-mod-network-add-option-for-ipv6-max-plt-vlt.patch | patch -p1 -popd - # urngd - 2020-01-21 rm -rf package/system/urngd git clone https://$github/sbwml/package_system_urngd package/system/urngd diff --git a/tags/v24 b/tags/v24 index 7c77343c5..986f41dfb 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.3 +24.10.4 From 8eb74253b5c998cfee2deea03b764a815aaba6fb Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 3 Nov 2025 01:03:35 +0800 Subject: [PATCH 304/425] linux-6.18: init 6.18-rc3 Signed-off-by: sbwml --- openwrt/6.18-disable-config | 19 + openwrt/build.sh | 9 +- ...kernel-Always-collect-module-symvers.patch | 34 ++ ...r-update-kernel-config-options-for-l.patch | 36 ++ ...heck-for-atomic-context-on-PREEMPT_R.patch | 39 -- ...el-name-in-proc-cpuinfo-for-64bit-ta.patch | 22 +- ...den-app-limited-rate-sample-detectio.patch | 6 +- ...hrink-delivered_mstamp-first_tx_msta.patch | 4 +- ...napshot-packets-in-flight-at-transmi.patch | 8 +- ...ount-packets-lost-over-TCP-rate-samp.patch | 4 +- ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 6 +- ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 4 +- ...djust-skb-tx.in_flight-upon-merge-in.patch | 2 +- ...djust-skb-tx.in_flight-upon-split-in.patch | 8 +- ...ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 20 +- ...alize-TSO-sizing-in-TCP-CC-module-AP.patch | 4 +- ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 24 +- ...ecord-app-limited-status-of-TLP-repa.patch | 22 +- ...nform-CC-module-of-losses-repaired-b.patch | 4 +- ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 12 +- ...r-route-feature-RTAX_FEATURE_ECN_LOW.patch | 48 +- ...pdate-TCP-bbr-congestion-control-mod.patch | 70 +-- ...nsure-ECN-enabled-BBR-flows-set-ECT-.patch | 18 +- ...OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 8 +- ...tso_segs-and-skb_marked_lost-to-bpf_.patch | 0 ...v3-silence-Wconstant-logical-operand.patch | 6 +- ...-silence-btf-module-warning-messages.patch | 2 +- ...mpt_disable-enable_rt-where-recomme.patch} | 14 +- ...sable-interrupts-on-PREEMPT_RT-duri.patch} | 20 +- ...isable-tracing-points-on-PREEMPT_RT.patch} | 24 +- ...pin_lock_irq-instead-of-local_irq_d.patch} | 16 +- ...m-i915-Drop-the-irqs_disabled-check.patch} | 4 +- ...onsider-also-RCU-depth-in-busy-loop.patch} | 4 +- ...evert-drm-i915-Depend-on-PREEMPT_RT.patch} | 4 +- ...LRNG-Entropy-Source-and-DRNG-Manager.patch | 102 ++-- ...cate-one-DRNG-instance-per-NUMA-node.patch | 2 +- .../011-LRNG-0003-LRNG-proc-interface.patch | 4 +- ...004-LRNG-add-switchable-DRNG-support.patch | 2 +- ...LRNG-add-common-generic-hash-support.patch | 2 +- ...-externalize-DRBG-functions-for-LRNG.patch | 20 +- ...07-LRNG-add-SP800-90A-DRBG-extension.patch | 2 +- ...add-kernel-crypto-API-PRNG-extension.patch | 2 +- ...-LRNG-add-atomic-DRNG-implementation.patch | 2 +- ...mmon-timer-based-entropy-source-code.patch | 2 +- ...11-LRNG-add-interrupt-entropy-source.patch | 2 +- ...-scheduler-add-entropy-sampling-hook.patch | 12 +- ...G-add-scheduler-based-entropy-source.patch | 2 +- ...add-SP800-90B-compliant-health-tests.patch | 2 +- ...-add-random.c-entropy-source-support.patch | 2 +- ...11-LRNG-0016-LRNG-CPU-entropy-source.patch | 2 +- ...RNG-add-Jitter-RNG-fast-noise-source.patch | 2 +- ...to-enable-runtime-entropy-rate-confi.patch | 2 +- ...terface-for-gathering-of-raw-entropy.patch | 2 +- ...-add-power-on-and-runtime-self-tests.patch | 2 +- ...0021-LRNG-sysctls-and-proc-interface.patch | 4 +- ...add-drop-in-replacement-random-4-API.patch | 4 +- ...LRNG-add-kernel-crypto-API-interface.patch | 2 +- ...RNG-add-dev-lrng-device-file-support.patch | 2 +- ...-LRNG-add-hwrand-framework-interface.patch | 2 +- ...ter-export-udp_get_timeouts-function.patch | 0 ...k-events-support-multiple-registrant.patch | 24 +- ...-linux-kernel-to-support-shortcut-fe.patch | 32 +- .../net/982-add-bcm-fullcone-support.patch | 0 ...83-add-bcm-fullcone-nft_masq-support.patch | 4 +- .../net/README.md | 7 +- .../linux-6.18-target-linux-generic.patch} | 66 +-- ...natmap-add-default-STUN-server-lists.patch | 13 +- openwrt/patch/mt76/Makefile | 8 +- openwrt/patch/mt76/README.md | 2 +- .../102-fix-build-with-linux-6.18.patch | 490 ++++++++++++++++++ openwrt/patch/openwrt-6.x/modules/crypto.mk | 262 +--------- openwrt/patch/openwrt-6.x/modules/fs.mk | 1 - openwrt/patch/openwrt-6.x/modules/hwmon.mk | 2 +- openwrt/patch/openwrt-6.x/modules/i2c.mk | 4 +- openwrt/patch/openwrt-6.x/modules/iio.mk | 8 +- openwrt/patch/openwrt-6.x/modules/lib.mk | 38 +- .../patch/openwrt-6.x/modules/netdevices.mk | 23 +- .../patch/openwrt-6.x/modules/netsupport.mk | 2 +- openwrt/patch/openwrt-6.x/modules/other.mk | 8 +- openwrt/patch/openwrt-6.x/modules/rtc.mk | 2 +- openwrt/patch/openwrt-6.x/modules/sound.mk | 64 ++- openwrt/patch/openwrt-6.x/modules/usb.mk | 2 +- openwrt/patch/openwrt-6.x/modules/video.mk | 31 +- .../x86/64/{config-6.12 => config-6.18} | 0 .../x86/{config-6.12 => config-6.18} | 266 +++++++--- .../100-fix_cs5535_clockevt.patch | 2 +- .../103-pcengines_apu6_platform.patch | 20 +- .../bpf-headers/900-fix-build.patch | 22 + .../6.18/900-fix-linux-6.18.patch | 24 + .../gpio-button-hotplug/fix-linux-6.12.patch | 11 +- .../gpio-nct5104d/fix-linux-6.18.patch | 40 ++ ...0-fix-compilation-warning-simple-fix.patch | 22 + .../900-fix-build-with-linux-6.18.patch | 29 ++ .../901-fix-build-for-linux-6.17.patch | 38 ++ .../102-fix-build-with-kernel-6.18.patch | 22 + .../ovpn-dco/901-fix-linux-6.11.patch | 9 - .../ovpn-dco/902-fix-linux-6.12.patch | 14 - .../patch/packages-patches/ovpn-dco/Makefile | 61 +++ .../901-fix-build-for-linux-6.18.patch | 33 ++ ...nv_remove-return-void-for-linux-6.12.patch | 11 +- openwrt/scripts/00-prepare_base.sh | 2 + openwrt/scripts/01-prepare_base-mainline.sh | 190 ++++--- openwrt/scripts/04-fix_kmod.sh | 20 +- tags/kernel-6.12 | 2 - tags/kernel-6.18 | 2 + tags/kernel-tag.sh | 8 +- 106 files changed, 1759 insertions(+), 891 deletions(-) create mode 100644 openwrt/6.18-disable-config create mode 100644 openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch create mode 100644 openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch delete mode 100644 openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch rename openwrt/patch/{kernel-6.12 => kernel-6.18}/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch (59%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch (92%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch (96%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch (95%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch (97%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch (89%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch (94%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch (97%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch (94%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch (82%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch (97%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch (77%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch (68%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch (94%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch (87%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch (73%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch (80%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch (81%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch (100%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch (91%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/btf/990-btf-silence-btf-module-warning-messages.patch (90%) rename openwrt/patch/{kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch => kernel-6.18/linux-rt/012-RT-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch} (88%) rename openwrt/patch/{kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch => kernel-6.18/linux-rt/012-RT-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch} (84%) rename openwrt/patch/{kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch => kernel-6.18/linux-rt/012-RT-0003-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch} (76%) rename openwrt/patch/{kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch => kernel-6.18/linux-rt/012-RT-0004-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch} (86%) rename openwrt/patch/{kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch => kernel-6.18/linux-rt/012-RT-0005-drm-i915-Drop-the-irqs_disabled-check.patch} (90%) rename openwrt/patch/{kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch => kernel-6.18/linux-rt/012-RT-0006-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch} (89%) rename openwrt/patch/{kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch => kernel-6.18/linux-rt/012-RT-0007-Revert-drm-i915-Depend-on-PREEMPT_RT.patch} (84%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0003-LRNG-proc-interface.patch (96%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch (86%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch (75%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch (97%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch (97%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch (99%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch (97%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch (98%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/net/601-netfilter-export-udp_get_timeouts-function.patch (100%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/net/952-net-conntrack-events-support-multiple-registrant.patch (94%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch (87%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/net/982-add-bcm-fullcone-support.patch (100%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/net/983-add-bcm-fullcone-nft_masq-support.patch (97%) rename openwrt/patch/{kernel-6.12 => kernel-6.18}/net/README.md (78%) rename openwrt/patch/{kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch => kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch} (86%) create mode 100644 openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch rename openwrt/patch/openwrt-6.x/x86/64/{config-6.12 => config-6.18} (100%) rename openwrt/patch/openwrt-6.x/x86/{config-6.12 => config-6.18} (65%) rename openwrt/patch/openwrt-6.x/x86/{patches-6.12 => patches-6.18}/100-fix_cs5535_clockevt.patch (85%) rename openwrt/patch/openwrt-6.x/x86/{patches-6.12 => patches-6.18}/103-pcengines_apu6_platform.patch (95%) create mode 100644 openwrt/patch/packages-patches/bpf-headers/900-fix-build.patch create mode 100644 openwrt/patch/packages-patches/cryptodev-linux/6.18/900-fix-linux-6.18.patch create mode 100644 openwrt/patch/packages-patches/gpio-nct5104d/fix-linux-6.18.patch create mode 100644 openwrt/patch/packages-patches/jool/patches/100-fix-compilation-warning-simple-fix.patch create mode 100644 openwrt/patch/packages-patches/jool/patches/900-fix-build-with-linux-6.18.patch create mode 100644 openwrt/patch/packages-patches/libpfring/patches/901-fix-build-for-linux-6.17.patch create mode 100644 openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch delete mode 100644 openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch delete mode 100644 openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch create mode 100644 openwrt/patch/packages-patches/ovpn-dco/Makefile create mode 100644 openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch delete mode 100644 tags/kernel-6.12 create mode 100644 tags/kernel-6.18 diff --git a/openwrt/6.18-disable-config b/openwrt/6.18-disable-config new file mode 100644 index 000000000..f07a6f9c4 --- /dev/null +++ b/openwrt/6.18-disable-config @@ -0,0 +1,19 @@ + +# package/feeds/packages/v4l2loopback +# CONFIG_PACKAGE_kmod-v4l2loopback is not set + +# package/new/shortcut-fe/shortcut-fe +# CONFIG_PACKAGE_kmod-shortcut-fe is not set +# CONFIG_PACKAGE_kmod-shortcut-fe-cm is not set + +# package/new/shortcut-fe/fast-classifier +# CONFIG_PACKAGE_kmod-fast-classifier is not set + +# package/feeds/telephony/dahdi-linux +# CONFIG_PACKAGE_kmod-dahdi is not set +# CONFIG_PACKAGE_kmod-dahdi-dummy is not set +# CONFIG_PACKAGE_kmod-dahdi-echocan-oslec is not set +# CONFIG_PACKAGE_kmod-dahdi-hfcs is not set + +# package/feeds/routing/batman-adv +# CONFIG_PACKAGE_kmod-batman-adv is not set diff --git a/openwrt/build.sh b/openwrt/build.sh index 50a808a58..2d8c5b186 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -37,9 +37,9 @@ ip_info=`curl -sk https://ip.cooluc.com`; # script url if [ "$isCN" = "CN" ]; then - export mirror=https://init.cooluc.com + export mirror=https://init3.cooluc.com else - export mirror=https://init2.cooluc.com + export mirror=https://init3.cooluc.com fi # github actions - caddy server @@ -174,7 +174,7 @@ case "$platform" in esac # print build opt -get_kernel_version=$(curl -s $mirror/tags/kernel-6.12) +get_kernel_version=$(curl -s $mirror/tags/kernel-6.18) kmod_hash=$(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}' | tail -1 | md5sum | awk '{print $1}') kmodpkg_name=$(echo $(echo -e "$get_kernel_version" | awk -F'HASH-' '{print $2}' | awk '{print $1}')~$(echo $kmod_hash)-r1) echo -e "${GREEN_COLOR}Kernel: $kmodpkg_name ${RES}" @@ -329,6 +329,9 @@ else [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi +# waiting fix +curl -s $mirror/openwrt/6.18-disable-config >> .config + # ota [ "$ENABLE_OTA" = "y" ] && [ "$version" = "rc2" ] && echo 'CONFIG_PACKAGE_luci-app-ota=y' >> .config diff --git a/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch b/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch new file mode 100644 index 000000000..60cf3035e --- /dev/null +++ b/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch @@ -0,0 +1,34 @@ +From f499ed288826b284cdb4a4e5563cbcc45a31ef71 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 26 Oct 2025 16:12:19 +0800 +Subject: [PATCH] include: kernel: Always collect module symvers + +Signed-off-by: sbwml +--- + include/kernel.mk | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/include/kernel.mk b/include/kernel.mk +index 1648a6f..f63f367 100644 +--- a/include/kernel.mk ++++ b/include/kernel.mk +@@ -160,13 +160,9 @@ PKG_EXTMOD_SUBDIRS ?= . + PKG_SYMVERS_DIR = $(KERNEL_BUILD_DIR)/symvers + + define collect_module_symvers +- for subdir in $(PKG_EXTMOD_SUBDIRS); do \ +- realdir=$$$$(readlink -f $(PKG_BUILD_DIR)); \ +- grep -F $(PKG_BUILD_DIR) $(PKG_BUILD_DIR)/$$$$subdir/Module.symvers >> $(PKG_BUILD_DIR)/Module.symvers.tmp; \ +- [ "$(PKG_BUILD_DIR)" = "$$$$realdir" ] || \ +- grep -F $$$$realdir $(PKG_BUILD_DIR)/$$$$subdir/Module.symvers >> $(PKG_BUILD_DIR)/Module.symvers.tmp; \ +- done; \ +- sort -u $(PKG_BUILD_DIR)/Module.symvers.tmp > $(PKG_BUILD_DIR)/Module.symvers; \ ++ sort -u $(PKG_BUILD_DIR)/Module.symvers > $(PKG_BUILD_DIR)/Module.symvers.tmp; \ ++ rm -f $(PKG_BUILD_DIR)/Module.symvers; \ ++ mv $(PKG_BUILD_DIR)/Module.symvers.tmp $(PKG_BUILD_DIR)/Module.symvers; \ + mkdir -p $(PKG_SYMVERS_DIR); \ + mv $(PKG_BUILD_DIR)/Module.symvers $(PKG_SYMVERS_DIR)/$(PKG_NAME).symvers + endef +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch b/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch new file mode 100644 index 000000000..d0954dce1 --- /dev/null +++ b/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch @@ -0,0 +1,36 @@ +From e952be9f0d42ecb6dc18ab0b29611e7c6a3fe800 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Fri, 31 Oct 2025 12:32:08 +0800 +Subject: [PATCH] include: netfilter: update kernel config options for legacy + iptables and ebtables + +Signed-off-by: sbwml +--- + include/netfilter.mk | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/netfilter.mk b/include/netfilter.mk +index 255e478..6c4ce9d 100644 +--- a/include/netfilter.mk ++++ b/include/netfilter.mk +@@ -29,7 +29,7 @@ endef + # kernel only + $(eval $(if $(NF_KMOD),$(call nf_add,NF_REJECT,CONFIG_NF_REJECT_IPV4, $(P_V4)nf_reject_ipv4),)) + +-$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES, $(P_V4)ip_tables),)) ++$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES_LEGACY, $(P_V4)ip_tables),)) + $(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_NETFILTER_XTABLES, $(P_XT)x_tables),)) + + $(eval $(if $(NF_KMOD),$(call nf_add,IPT_CORE,CONFIG_NETFILTER_XTABLES, $(P_XT)xt_tcpudp),)) +@@ -282,7 +282,7 @@ $(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNCOUNT,CONFIG_NETFILTER_CONNCOUNT, $( + # ebtables + # + +-$(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES, $(P_EBT)ebtables),)) ++$(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES_LEGACY, $(P_EBT)ebtables),)) + + # ebtables: tables + $(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_BROUTE, $(P_EBT)ebtable_broute)) +-- +2.43.5 + diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch b/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch deleted file mode 100644 index 484ceb34f..000000000 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 34a01264ed3fab72c699f6fa8c999bb4ed907931 Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Mon, 25 Oct 2021 15:05:18 +0200 -Subject: [PATCH 3/8] drm/i915: Don't check for atomic context on PREEMPT_RT - -The !in_atomic() check in _wait_for_atomic() triggers on PREEMPT_RT -because the uncore::lock is a spinlock_t and does not disable -preemption or interrupts. - -Changing the uncore:lock to a raw_spinlock_t doubles the worst case -latency on an otherwise idle testbox during testing. - -Ignore _WAIT_FOR_ATOMIC_CHECK() on PREEMPT_RT. - -Reviewed-by: Tvrtko Ursulin -Link: https://lore.kernel.org/all/20211006164628.s2mtsdd2jdbfyf7g@linutronix.de/ -Signed-off-by: Sebastian Andrzej Siewior ---- - drivers/gpu/drm/i915/i915_utils.h | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/i915/i915_utils.h -+++ b/drivers/gpu/drm/i915/i915_utils.h -@@ -269,8 +269,13 @@ wait_remaining_ms_from_jiffies(unsigned - (Wmax)) - #define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) - --/* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */ --#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) -+/* -+ * If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. -+ * On PREEMPT_RT the context isn't becoming atomic because it is used in an -+ * interrupt handler or because a spinlock_t is acquired. This leads to -+ * warnings which don't occur otherwise and therefore the check is disabled. -+ */ -+#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT) - # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic()) - #else - # define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0) diff --git a/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch b/openwrt/patch/kernel-6.18/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch similarity index 59% rename from openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch rename to openwrt/patch/kernel-6.18/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch index 32c1f8752..dc0fb9592 100644 --- a/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch +++ b/openwrt/patch/kernel-6.18/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch @@ -18,15 +18,15 @@ Signed-off-by: Sumit Gupta --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c -@@ -206,9 +206,8 @@ static int c_show(struct seq_file *m, vo - * "processor". Give glibc what it expects. - */ - seq_printf(m, "processor\t: %d\n", i); -- if (compat) -- seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", -- MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); -+ seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", -+ MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); +@@ -224,9 +224,8 @@ static int c_show(struct seq_file *m, vo + * "processor". Give glibc what it expects. + */ + seq_printf(m, "processor\t: %d\n", cpu); +- if (compat) +- seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", +- MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); ++ seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", ++ MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); - seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", - loops_per_jiffy / (500000UL/HZ), + seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", + loops_per_jiffy / (500000UL/HZ), diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch similarity index 92% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index 736b718a7..c3c4cad79 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -32,7 +32,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3992,6 +3992,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4035,6 +4035,7 @@ static int tcp_ack(struct sock *sk, cons prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; rs.prior_in_flight = tcp_packets_in_flight(tp); @@ -42,10 +42,10 @@ Signed-off-by: Alexandre Frade * is in window. --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c -@@ -690,6 +690,7 @@ void tcp_write_timer_handler(struct sock +@@ -702,6 +702,7 @@ void tcp_write_timer_handler(struct sock + icsk_timeout(icsk)); return; } - + tcp_rate_check_app_limited(sk); tcp_mstamp_refresh(tcp_sk(sk)); event = icsk->icsk_pending; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch similarity index 96% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch index 69edfe392..336406daa 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -901,6 +901,11 @@ static inline u32 tcp_stamp_us_delta(u64 +@@ -943,6 +943,11 @@ static inline u32 tcp_stamp_us_delta(u64 return max_t(s64, t1 - t0, 0); } @@ -37,7 +37,7 @@ Signed-off-by: Alexandre Frade /* provide the departure time in us unit */ static inline u64 tcp_skb_timestamp_us(const struct sk_buff *skb) { -@@ -990,9 +995,9 @@ struct tcp_skb_cb { +@@ -1053,9 +1058,9 @@ struct tcp_skb_cb { /* pkts S/ACKed so far upon tx of skb, incl retrans: */ __u32 delivered; /* start of send pipeline phase */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch similarity index 95% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index 565bbe787..efd8b5c4a 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -998,6 +998,10 @@ struct tcp_skb_cb { +@@ -1061,6 +1061,10 @@ struct tcp_skb_cb { u32 first_tx_mstamp; /* when we reached the "delivered" count */ u32 delivered_mstamp; @@ -38,7 +38,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1154,6 +1158,7 @@ struct rate_sample { +@@ -1217,6 +1221,7 @@ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ @@ -46,7 +46,7 @@ Signed-off-by: Alexandre Frade s32 delivered; /* number of packets delivered over interval */ s32 delivered_ce; /* number of packets delivered w/ CE marks*/ long interval_us; /* time for tp->delivered to incr "delivered" */ -@@ -1276,6 +1281,7 @@ static inline void tcp_ca_event(struct s +@@ -1339,6 +1344,7 @@ static inline void tcp_ca_event(struct s void tcp_set_ca_state(struct sock *sk, const u8 ca_state); /* From tcp_rate.c */ @@ -56,7 +56,7 @@ Signed-off-by: Alexandre Frade struct rate_sample *rs); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2770,6 +2770,7 @@ static bool tcp_write_xmit(struct sock * +@@ -2926,6 +2926,7 @@ static bool tcp_write_xmit(struct sock * skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); tcp_init_tso_segs(skb, mss_now); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch similarity index 97% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch index 9939f1593..ff11135ed 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch @@ -19,7 +19,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1002,6 +1002,7 @@ struct tcp_skb_cb { +@@ -1065,6 +1065,7 @@ struct tcp_skb_cb { #define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) u32 in_flight:20, /* packets in flight at transmit */ unused2:12; @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1156,11 +1157,13 @@ struct ack_sample { +@@ -1219,11 +1220,13 @@ struct ack_sample { */ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch similarity index 89% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index a1ac02d76..4effc6e48 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -18,7 +18,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1175,6 +1175,7 @@ struct rate_sample { +@@ -1238,6 +1238,7 @@ struct rate_sample { bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ bool is_ack_delayed; /* is this (likely) a delayed ACK? */ @@ -28,8 +28,8 @@ Signed-off-by: Alexandre Frade struct tcp_congestion_ops { --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4082,6 +4082,7 @@ static int tcp_ack(struct sock *sk, cons - delivered = tcp_newly_delivered(sk, delivered, flag); +@@ -4133,6 +4133,7 @@ static int tcp_ack(struct sock *sk, cons + lost = tp->lost - lost; /* freshly marked lost */ rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); + rs.is_ece = !!(flag & FLAG_ECE); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch similarity index 94% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index cd225523e..60e303797 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -30,7 +30,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1202,6 +1202,9 @@ struct tcp_congestion_ops { +@@ -1265,6 +1265,9 @@ struct tcp_congestion_ops { /* override sysctl_tcp_min_tso_segs */ u32 (*min_tso_segs)(struct sock *sk); @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1136,7 +1136,12 @@ static void tcp_verify_retransmit_hint(s +@@ -1282,7 +1282,12 @@ static void tcp_verify_retransmit_hint(s */ static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) { diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch similarity index 97% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch index e97e7abe9..c23eaa407 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch @@ -39,7 +39,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1513,6 +1513,17 @@ static bool tcp_shifted_skb(struct sock +@@ -1652,6 +1652,17 @@ static bool tcp_shifted_skb(struct sock WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); tcp_skb_pcount_add(skb, -pcount); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch similarity index 94% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch index 84cfd569d..803d24214 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1301,6 +1301,21 @@ static inline bool tcp_skb_sent_after(u6 +@@ -1364,6 +1364,21 @@ static inline bool tcp_skb_sent_after(u6 return t1 > t2 || (t1 == t2 && after(seq1, seq2)); } @@ -55,16 +55,16 @@ Signed-off-by: Alexandre Frade * between different flows. --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -1606,7 +1606,7 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1759,7 +1759,7 @@ int tcp_fragment(struct sock *sk, enum t { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; - int old_factor; + int old_factor, inflight_prev; long limit; + u16 flags; int nlen; - u8 flags; -@@ -1681,6 +1681,30 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1834,6 +1834,30 @@ int tcp_fragment(struct sock *sk, enum t if (diff) tcp_adjust_pcount(sk, skb, diff); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch similarity index 82% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch index 3cc72d5ae..9d4f39bd6 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch @@ -23,20 +23,20 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1137,7 +1137,11 @@ enum tcp_ca_ack_event_flags { - #define TCP_CONG_NON_RESTRICTED 0x1 +@@ -1200,7 +1200,11 @@ enum tcp_ca_ack_event_flags { + #define TCP_CONG_NON_RESTRICTED BIT(0) /* Requires ECN/ECT set on all packets */ - #define TCP_CONG_NEEDS_ECN 0x2 + #define TCP_CONG_NEEDS_ECN BIT(1) -#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN) +/* Wants notification of CE events (CA_EVENT_ECN_IS_CE, CA_EVENT_ECN_NO_CE). */ -+#define TCP_CONG_WANTS_CE_EVENTS 0x4 ++#define TCP_CONG_WANTS_CE_EVENTS BIT(2) +#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | \ + TCP_CONG_NEEDS_ECN | \ + TCP_CONG_WANTS_CE_EVENTS) union tcp_cc_info; -@@ -1269,6 +1273,14 @@ static inline char *tcp_ca_get_name_by_k +@@ -1332,6 +1336,14 @@ static inline char *tcp_ca_get_name_by_k } #endif @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade const struct inet_connection_sock *icsk = inet_csk(sk); --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -376,7 +376,7 @@ static void __tcp_ecn_check_ce(struct so +@@ -358,7 +358,7 @@ static void tcp_data_ecn_check(struct so tcp_enter_quickack_mode(sk, 2); break; case INET_ECN_CE: @@ -61,13 +61,13 @@ Signed-off-by: Alexandre Frade + if (tcp_ca_wants_ce_events(sk)) tcp_ca_event(sk, CA_EVENT_ECN_IS_CE); - if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { -@@ -387,7 +387,7 @@ static void __tcp_ecn_check_ce(struct so + if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR) && +@@ -376,7 +376,7 @@ static void tcp_data_ecn_check(struct so tp->ecn_flags |= TCP_ECN_SEEN; break; default: - if (tcp_ca_needs_ecn(sk)) + if (tcp_ca_wants_ce_events(sk)) tcp_ca_event(sk, CA_EVENT_ECN_NO_CE); - tp->ecn_flags |= TCP_ECN_SEEN; - break; + if (!tcp_ecn_mode_rfc3168(tp)) + break; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch similarity index 97% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch index 68d2ce1c8..213c32aad 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1203,8 +1203,8 @@ struct tcp_congestion_ops { +@@ -1266,8 +1266,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); @@ -97,7 +97,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2062,13 +2062,12 @@ static u32 tcp_tso_autosize(const struct +@@ -2214,13 +2214,12 @@ static u32 tcp_tso_autosize(const struct static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) { const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch similarity index 77% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 39f15b4a1..482fdaabe 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -21,19 +21,19 @@ Signed-off-by: Alexandre Frade --- a/include/linux/tcp.h +++ b/include/linux/tcp.h -@@ -369,7 +369,8 @@ struct tcp_sock { - u8 compressed_ack; - u8 dup_ack_counter:2, - tlp_retrans:1, /* TLP is a retransmission */ -- unused:5; -+ fast_ack_mode:2, /* which fast ack mode ? */ -+ unused:3; - u8 thin_lto : 1,/* Use linear timeouts for thin streams */ - fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ - fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ +@@ -236,7 +236,8 @@ struct tcp_sock { + tcp_usec_ts : 1, /* TSval values in usec */ + is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ + is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */ +- recvmsg_inq : 1;/* Indicate # of bytes in queue upon recvmsg */ ++ recvmsg_inq : 1,/* Indicate # of bytes in queue upon recvmsg */ ++ fast_ack_mode:1;/* ack ASAP if >1 rcv_mss received? */ + __cacheline_group_end(tcp_sock_read_txrx); + + /* RX read-mostly hotpath cache lines */ --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -3397,6 +3397,7 @@ int tcp_disconnect(struct sock *sk, int +@@ -3469,6 +3469,7 @@ int tcp_disconnect(struct sock *sk, int tp->rx_opt.dsack = 0; tp->rx_opt.num_sacks = 0; tp->rcv_ooopack = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5793,13 +5793,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5902,13 +5902,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch similarity index 68% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch index 43f19d209..3a917dfb2 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -23,19 +23,19 @@ Signed-off-by: Alexandre Frade --- a/include/linux/tcp.h +++ b/include/linux/tcp.h -@@ -370,7 +370,8 @@ struct tcp_sock { - u8 dup_ack_counter:2, - tlp_retrans:1, /* TLP is a retransmission */ - fast_ack_mode:2, /* which fast ack mode ? */ -- unused:3; -+ tlp_orig_data_app_limited:1, /* app-limited before TLP rtx? */ -+ unused:2; - u8 thin_lto : 1,/* Use linear timeouts for thin streams */ - fastopen_connect:1, /* FASTOPEN_CONNECT sockopt */ - fastopen_no_cookie:1, /* Allow send/recv SYN+data without a cookie */ +@@ -293,7 +293,8 @@ struct tcp_sock { + * 0x5?10 << 16 + snd_wnd in net byte order + */ + u8 nonagle : 4,/* Disable Nagle algorithm? */ +- rate_app_limited:1; /* rate_{delivered,interval_us} limited? */ ++ rate_app_limited:1, /* rate_{delivered,interval_us} limited? */ ++ tlp_orig_data_app_limited:1; /* app-limited before TLP rtx? */ + u8 received_ce_pending:4, /* Not yet transmit cnt of received_ce */ + unused2:4; + u8 accecn_minlen:2,/* Minimum length of AccECN option sent */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -3008,6 +3008,7 @@ void tcp_send_loss_probe(struct sock *sk +@@ -3162,6 +3162,7 @@ void tcp_send_loss_probe(struct sock *sk if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch similarity index 94% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index 543d3b468..a4139dee0 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1115,6 +1115,7 @@ enum tcp_ca_event { +@@ -1178,6 +1178,7 @@ enum tcp_ca_event { CA_EVENT_LOSS, /* loss timeout */ CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3879,6 +3879,7 @@ static void tcp_process_tlp_ack(struct s +@@ -3915,6 +3915,7 @@ static void tcp_process_tlp_ack(struct s /* ACK advances: there was a loss, so reduce cwnd. Reset * tlp_high_seq in tcp_init_cwnd_reduction() */ diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch similarity index 87% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index b6e0d063d..2bea4fabf 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -21,7 +21,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1179,6 +1179,7 @@ struct rate_sample { +@@ -1242,6 +1242,7 @@ struct rate_sample { u32 last_end_seq; /* end_seq of most recently ACKed packet */ bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ @@ -31,9 +31,9 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3862,7 +3862,8 @@ static void tcp_replace_ts_recent(struct +@@ -3898,7 +3898,8 @@ static int tcp_replace_ts_recent(struct /* This routine deals with acks during a TLP episode and ends an episode by - * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack + * resetting tlp_high_seq. Ref: TLP algorithm in RFC8985 */ -static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) +static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag, @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade { struct tcp_sock *tp = tcp_sk(sk); -@@ -3890,6 +3891,11 @@ static void tcp_process_tlp_ack(struct s +@@ -3926,6 +3927,11 @@ static void tcp_process_tlp_ack(struct s FLAG_NOT_DUP | FLAG_DATA_SACKED))) { /* Pure dupack: original and TLP probe arrived; no loss */ tp->tlp_high_seq = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade } } -@@ -4075,7 +4081,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4125,7 +4131,7 @@ static int tcp_ack(struct sock *sk, cons tcp_in_ack_event(sk, flag); if (tp->tlp_high_seq) @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade if (tcp_ack_is_dubious(sk, flag)) { if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4120,7 +4126,7 @@ no_queue: +@@ -4176,7 +4182,7 @@ no_queue: tcp_ack_probe(sk); if (tp->tlp_high_seq) diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch similarity index 73% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch index 0e20e6999..48a2fd7ac 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch @@ -33,16 +33,16 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -376,6 +376,7 @@ static inline void tcp_dec_quickack_mode - #define TCP_ECN_QUEUE_CWR 2 - #define TCP_ECN_DEMAND_CWR 4 - #define TCP_ECN_SEEN 8 -+#define TCP_ECN_LOW 16 +@@ -403,6 +403,7 @@ static inline void tcp_dec_quickack_mode + #define TCP_ECN_DEMAND_CWR BIT(2) + #define TCP_ECN_SEEN BIT(3) + #define TCP_ECN_MODE_ACCECN BIT(4) ++#define TCP_ECN_LOW BIT(5) - enum tcp_tw_status { - TCP_TW_SUCCESS = 0, -@@ -794,6 +795,15 @@ static inline void tcp_fast_path_check(s - tcp_fast_path_on(tp); + #define TCP_ECN_DISABLED 0 + #define TCP_ECN_MODE_PENDING (TCP_ECN_MODE_RFC3168 | TCP_ECN_MODE_ACCECN) +@@ -836,6 +837,15 @@ static inline u32 __tcp_set_rto(const st + return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us); } +static inline void tcp_set_ecn_low_from_dst(struct sock *sk, @@ -59,7 +59,7 @@ Signed-off-by: Alexandre Frade /* Compute the actual rto_min value */ --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h -@@ -507,12 +507,14 @@ enum { +@@ -517,12 +517,14 @@ enum { #define RTAX_FEATURE_TIMESTAMP (1 << 2) /* unused */ #define RTAX_FEATURE_ALLFRAG (1 << 3) /* unused */ #define RTAX_FEATURE_TCP_USEC_TS (1 << 4) @@ -77,7 +77,7 @@ Signed-off-by: Alexandre Frade __u8 proto; --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c -@@ -462,6 +462,8 @@ void tcp_ca_openreq_child(struct sock *s +@@ -500,6 +500,8 @@ void tcp_ca_openreq_child(struct sock *s u32 ca_key = dst_metric(dst, RTAX_CC_ALGO); bool ca_got_dst = false; @@ -86,12 +86,12 @@ Signed-off-by: Alexandre Frade if (ca_key != TCP_CA_UNSPEC) { const struct tcp_congestion_ops *ca; ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -339,10 +339,9 @@ static void tcp_ecn_send_syn(struct sock - bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk); - bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 || - tcp_ca_needs_ecn(sk) || bpf_needs_ecn; +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -583,10 +583,9 @@ static inline void tcp_ecn_send_syn(stru + use_ecn = tcp_ecn == TCP_ECN_IN_ECN_OUT_ECN || + tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ECN || + tcp_ca_needs_ecn(sk) || bpf_needs_ecn || use_accecn; + const struct dst_entry *dst = __sk_dst_get(sk); if (!use_ecn) { @@ -100,13 +100,13 @@ Signed-off-by: Alexandre Frade if (dst && dst_feature(dst, RTAX_FEATURE_ECN)) use_ecn = true; } -@@ -354,6 +353,9 @@ static void tcp_ecn_send_syn(struct sock - tp->ecn_flags = TCP_ECN_OK; - if (tcp_ca_needs_ecn(sk) || bpf_needs_ecn) - INET_ECN_xmit(sk); +@@ -604,6 +603,9 @@ static inline void tcp_ecn_send_syn(stru + tp->syn_ect_snt = inet_sk(sk)->tos & INET_ECN_MASK; + } else { + tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); + -+ if (dst) -+ tcp_set_ecn_low_from_dst(sk, dst); ++ if (dst) ++ tcp_set_ecn_low_from_dst(sk, dst); + } } } - diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch similarity index 98% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch index 0fdc28068..b978b0c99 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -140,7 +140,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h -@@ -137,8 +137,8 @@ struct inet_connection_sock { +@@ -132,8 +132,8 @@ struct inet_connection_sock { u32 icsk_probes_tstamp; u32 icsk_user_timeout; @@ -153,7 +153,7 @@ Signed-off-by: Alexandre Frade #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -2491,7 +2491,7 @@ struct tcp_plb_state { +@@ -2588,7 +2588,7 @@ struct tcp_plb_state { u8 consec_cong_rounds:5, /* consecutive congested rounds */ unused:3; u32 pause_until; /* jiffies32 when PLB can resume rerouting */ @@ -472,7 +472,7 @@ Signed-off-by: Alexandre Frade /* Gain factor for adding extra_acked to target cwnd: */ static const int bbr_extra_acked_gain = BBR_UNIT; /* Window length of extra_acked window. */ -@@ -201,8 +256,121 @@ static const u32 bbr_ack_epoch_acked_res +@@ -201,8 +256,123 @@ static const u32 bbr_ack_epoch_acked_res /* Time period for clamping cwnd increment due to ack aggregation */ static const u32 bbr_extra_acked_max_us = 100 * 1000; @@ -587,14 +587,16 @@ Signed-off-by: Alexandre Frade + */ +static bool bbr_can_use_ecn(const struct sock *sk) +{ -+ return (tcp_sk(sk)->ecn_flags & TCP_ECN_OK) && ++ const struct tcp_sock *tp = tcp_sk(sk); ++ ++ return tcp_ecn_mode_any(tp) && + (tcp_sk(sk)->ecn_flags & TCP_ECN_LOW); +} + /* Do we estimate that STARTUP filled the pipe? */ static bool bbr_full_bw_reached(const struct sock *sk) { -@@ -214,17 +382,17 @@ static bool bbr_full_bw_reached(const st +@@ -214,17 +384,17 @@ static bool bbr_full_bw_reached(const st /* Return the windowed max recent bandwidth sample, in pkts/uS << BW_SCALE. */ static u32 bbr_max_bw(const struct sock *sk) { @@ -616,7 +618,7 @@ Signed-off-by: Alexandre Frade } /* Return maximum extra acked in past k-2k round trips, -@@ -241,15 +409,23 @@ static u16 bbr_extra_acked(const struct +@@ -241,15 +411,23 @@ static u16 bbr_extra_acked(const struct * The order here is chosen carefully to avoid overflow of u64. This should * work for input rates of up to 2.9Tbit/sec and gain of 2.89x. */ @@ -643,7 +645,7 @@ Signed-off-by: Alexandre Frade } /* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */ -@@ -257,12 +433,13 @@ static unsigned long bbr_bw_to_pacing_ra +@@ -257,12 +435,13 @@ static unsigned long bbr_bw_to_pacing_ra { u64 rate = bw; @@ -659,7 +661,7 @@ Signed-off-by: Alexandre Frade static void bbr_init_pacing_rate_from_rtt(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); -@@ -279,7 +456,7 @@ static void bbr_init_pacing_rate_from_rt +@@ -279,7 +458,7 @@ static void bbr_init_pacing_rate_from_rt bw = (u64)tcp_snd_cwnd(tp) * BW_UNIT; do_div(bw, rtt_us); WRITE_ONCE(sk->sk_pacing_rate, @@ -668,7 +670,7 @@ Signed-off-by: Alexandre Frade } /* Pace using current bw estimate and a gain factor. */ -@@ -295,31 +472,38 @@ static void bbr_set_pacing_rate(struct s +@@ -295,31 +474,38 @@ static void bbr_set_pacing_rate(struct s WRITE_ONCE(sk->sk_pacing_rate, rate); } @@ -718,7 +720,7 @@ Signed-off-by: Alexandre Frade { return bbr_tso_segs_generic(sk, mss_now, sk->sk_gso_max_size); } -@@ -329,7 +513,7 @@ static u32 bbr_tso_segs_goal(struct sock +@@ -329,7 +515,7 @@ static u32 bbr_tso_segs_goal(struct sock { struct tcp_sock *tp = tcp_sk(sk); @@ -727,7 +729,7 @@ Signed-off-by: Alexandre Frade } /* Save "last known good" cwnd so we can restore it after losses or PROBE_RTT */ -@@ -349,7 +533,9 @@ __bpf_kfunc static void bbr_cwnd_event(s +@@ -349,7 +535,9 @@ __bpf_kfunc static void bbr_cwnd_event(s struct tcp_sock *tp = tcp_sk(sk); struct bbr *bbr = inet_csk_ca(sk); @@ -738,7 +740,7 @@ Signed-off-by: Alexandre Frade bbr->idle_restart = 1; bbr->ack_epoch_mstamp = tp->tcp_mstamp; bbr->ack_epoch_acked = 0; -@@ -360,6 +546,16 @@ __bpf_kfunc static void bbr_cwnd_event(s +@@ -360,6 +548,16 @@ __bpf_kfunc static void bbr_cwnd_event(s bbr_set_pacing_rate(sk, bbr_bw(sk), BBR_UNIT); else if (bbr->mode == BBR_PROBE_RTT) bbr_check_probe_rtt_done(sk); @@ -755,7 +757,7 @@ Signed-off-by: Alexandre Frade } } -@@ -382,10 +578,10 @@ static u32 bbr_bdp(struct sock *sk, u32 +@@ -382,10 +580,10 @@ static u32 bbr_bdp(struct sock *sk, u32 * default. This should only happen when the connection is not using TCP * timestamps and has retransmitted all of the SYN/SYNACK/data packets * ACKed so far. In this case, an RTO can cut cwnd to 1, in which @@ -768,7 +770,7 @@ Signed-off-by: Alexandre Frade w = (u64)bw * bbr->min_rtt_us; -@@ -402,23 +598,23 @@ static u32 bbr_bdp(struct sock *sk, u32 +@@ -402,23 +600,23 @@ static u32 bbr_bdp(struct sock *sk, u32 * - one skb in sending host Qdisc, * - one skb in sending host TSO/GSO engine * - one skb being received by receiver host LRO/GRO/delayed-ACK engine @@ -800,7 +802,7 @@ Signed-off-by: Alexandre Frade cwnd += 2; return cwnd; -@@ -473,10 +669,10 @@ static u32 bbr_ack_aggregation_cwnd(stru +@@ -473,10 +671,10 @@ static u32 bbr_ack_aggregation_cwnd(stru { u32 max_aggr_cwnd, aggr_cwnd = 0; @@ -813,7 +815,7 @@ Signed-off-by: Alexandre Frade >> BBR_SCALE; aggr_cwnd = min(aggr_cwnd, max_aggr_cwnd); } -@@ -484,66 +680,27 @@ static u32 bbr_ack_aggregation_cwnd(stru +@@ -484,66 +682,27 @@ static u32 bbr_ack_aggregation_cwnd(stru return aggr_cwnd; } @@ -887,7 +889,7 @@ Signed-off-by: Alexandre Frade target_cwnd = bbr_bdp(sk, bw, gain); /* Increment the cwnd to account for excess ACKed data that seems -@@ -552,74 +709,26 @@ static void bbr_set_cwnd(struct sock *sk +@@ -552,74 +711,26 @@ static void bbr_set_cwnd(struct sock *sk target_cwnd += bbr_ack_aggregation_cwnd(sk); target_cwnd = bbr_quantization_budget(sk, target_cwnd); @@ -979,7 +981,7 @@ Signed-off-by: Alexandre Frade } static void bbr_reset_startup_mode(struct sock *sk) -@@ -629,191 +738,49 @@ static void bbr_reset_startup_mode(struc +@@ -629,191 +740,49 @@ static void bbr_reset_startup_mode(struc bbr->mode = BBR_STARTUP; } @@ -1195,7 +1197,7 @@ Signed-off-by: Alexandre Frade } /* Estimates the windowed max degree of ack aggregation. -@@ -827,7 +794,7 @@ static void bbr_update_bw(struct sock *s +@@ -827,7 +796,7 @@ static void bbr_update_bw(struct sock *s * * Max extra_acked is clamped by cwnd and bw * bbr_extra_acked_max_us (100 ms). * Max filter is an approximate sliding window of 5-10 (packet timed) round @@ -1204,7 +1206,7 @@ Signed-off-by: Alexandre Frade */ static void bbr_update_ack_aggregation(struct sock *sk, const struct rate_sample *rs) -@@ -835,15 +802,19 @@ static void bbr_update_ack_aggregation(s +@@ -835,15 +804,19 @@ static void bbr_update_ack_aggregation(s u32 epoch_us, expected_acked, extra_acked; struct bbr *bbr = inet_csk_ca(sk); struct tcp_sock *tp = tcp_sk(sk); @@ -1226,7 +1228,7 @@ Signed-off-by: Alexandre Frade bbr->extra_acked_win_rtts = 0; bbr->extra_acked_win_idx = bbr->extra_acked_win_idx ? 0 : 1; -@@ -877,49 +848,6 @@ static void bbr_update_ack_aggregation(s +@@ -877,49 +850,6 @@ static void bbr_update_ack_aggregation(s bbr->extra_acked[bbr->extra_acked_win_idx] = extra_acked; } @@ -1276,7 +1278,7 @@ Signed-off-by: Alexandre Frade static void bbr_check_probe_rtt_done(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); -@@ -929,9 +857,9 @@ static void bbr_check_probe_rtt_done(str +@@ -929,9 +859,9 @@ static void bbr_check_probe_rtt_done(str after(tcp_jiffies32, bbr->probe_rtt_done_stamp))) return; @@ -1288,7 +1290,7 @@ Signed-off-by: Alexandre Frade } /* The goal of PROBE_RTT mode is to have BBR flows cooperatively and -@@ -957,23 +885,35 @@ static void bbr_update_min_rtt(struct so +@@ -957,23 +887,35 @@ static void bbr_update_min_rtt(struct so { struct tcp_sock *tp = tcp_sk(sk); struct bbr *bbr = inet_csk_ca(sk); @@ -1333,7 +1335,7 @@ Signed-off-by: Alexandre Frade } if (bbr->mode == BBR_PROBE_RTT) { -@@ -982,9 +922,9 @@ static void bbr_update_min_rtt(struct so +@@ -982,9 +924,9 @@ static void bbr_update_min_rtt(struct so (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; /* Maintain min packets in flight for max(200 ms, 1 round). */ if (!bbr->probe_rtt_done_stamp && @@ -1345,7 +1347,7 @@ Signed-off-by: Alexandre Frade bbr->probe_rtt_round_done = 0; bbr->next_rtt_delivered = tp->delivered; } else if (bbr->probe_rtt_done_stamp) { -@@ -1005,18 +945,20 @@ static void bbr_update_gains(struct sock +@@ -1005,18 +947,20 @@ static void bbr_update_gains(struct sock switch (bbr->mode) { case BBR_STARTUP: @@ -1374,7 +1376,7 @@ Signed-off-by: Alexandre Frade break; case BBR_PROBE_RTT: bbr->pacing_gain = BBR_UNIT; -@@ -1028,27 +970,1108 @@ static void bbr_update_gains(struct sock +@@ -1028,27 +972,1108 @@ static void bbr_update_gains(struct sock } } @@ -1455,8 +1457,7 @@ Signed-off-by: Alexandre Frade + +/* Exit STARTUP upon N consecutive rounds with ECN mark rate > ecn_thresh. */ +static void bbr_check_ecn_too_high_in_startup(struct sock *sk, u32 ce_ratio) - { -- bbr_update_bw(sk, rs); ++{ + struct bbr *bbr = inet_csk_ca(sk); + + if (bbr_full_bw_reached(sk) || !bbr->ecn_eligible || @@ -2359,7 +2360,8 @@ Signed-off-by: Alexandre Frade +/* If pipe is probably full, drain the queue and then enter steady-state. */ +static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs, + struct bbr_context *ctx) -+{ + { +- bbr_update_bw(sk, rs); + struct bbr *bbr = inet_csk_ca(sk); + + if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { @@ -2492,7 +2494,7 @@ Signed-off-by: Alexandre Frade } __bpf_kfunc static void bbr_init(struct sock *sk) -@@ -1056,20 +2079,21 @@ __bpf_kfunc static void bbr_init(struct +@@ -1056,20 +2081,21 @@ __bpf_kfunc static void bbr_init(struct struct tcp_sock *tp = tcp_sk(sk); struct bbr *bbr = inet_csk_ca(sk); @@ -2519,7 +2521,7 @@ Signed-off-by: Alexandre Frade bbr->has_seen_rtt = 0; bbr_init_pacing_rate_from_rtt(sk); -@@ -1080,7 +2104,7 @@ __bpf_kfunc static void bbr_init(struct +@@ -1080,7 +2106,7 @@ __bpf_kfunc static void bbr_init(struct bbr->full_bw_cnt = 0; bbr->cycle_mstamp = 0; bbr->cycle_idx = 0; @@ -2528,7 +2530,7 @@ Signed-off-by: Alexandre Frade bbr_reset_startup_mode(sk); bbr->ack_epoch_mstamp = tp->tcp_mstamp; -@@ -1090,78 +2114,236 @@ __bpf_kfunc static void bbr_init(struct +@@ -1090,78 +2116,236 @@ __bpf_kfunc static void bbr_init(struct bbr->extra_acked[0] = 0; bbr->extra_acked[1] = 0; @@ -2793,7 +2795,7 @@ Signed-off-by: Alexandre Frade .undo_cwnd = bbr_undo_cwnd, .cwnd_event = bbr_cwnd_event, .ssthresh = bbr_ssthresh, -@@ -1174,10 +2356,11 @@ BTF_KFUNCS_START(tcp_bbr_check_kfunc_ids +@@ -1174,10 +2358,11 @@ BTF_KFUNCS_START(tcp_bbr_check_kfunc_ids BTF_ID_FLAGS(func, bbr_init) BTF_ID_FLAGS(func, bbr_main) BTF_ID_FLAGS(func, bbr_sndbuf_expand) @@ -2806,7 +2808,7 @@ Signed-off-by: Alexandre Frade BTF_ID_FLAGS(func, bbr_set_state) BTF_KFUNCS_END(tcp_bbr_check_kfunc_ids) -@@ -1210,5 +2393,12 @@ MODULE_AUTHOR("Van Jacobson "); MODULE_AUTHOR("Yuchung Cheng "); MODULE_AUTHOR("Soheil Hassas Yeganeh "); diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch similarity index 80% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch index 6de675a2c..b253a9ce0 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch @@ -25,17 +25,17 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -377,6 +377,7 @@ static inline void tcp_dec_quickack_mode - #define TCP_ECN_DEMAND_CWR 4 - #define TCP_ECN_SEEN 8 - #define TCP_ECN_LOW 16 -+#define TCP_ECN_ECT_PERMANENT 32 +@@ -404,6 +404,7 @@ static inline void tcp_dec_quickack_mode + #define TCP_ECN_SEEN BIT(3) + #define TCP_ECN_MODE_ACCECN BIT(4) + #define TCP_ECN_LOW BIT(5) ++#define TCP_ECN_ECT_PERMANENT BIT(6) - enum tcp_tw_status { - TCP_TW_SUCCESS = 0, + #define TCP_ECN_DISABLED 0 + #define TCP_ECN_MODE_PENDING (TCP_ECN_MODE_RFC3168 | TCP_ECN_MODE_ACCECN) --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c -@@ -2151,6 +2151,9 @@ __bpf_kfunc static void bbr_init(struct +@@ -2153,6 +2153,9 @@ __bpf_kfunc static void bbr_init(struct bbr->plb.pause_until = 0; tp->fast_ack_mode = bbr_fast_ack_mode ? 1 : 0; @@ -47,7 +47,7 @@ Signed-off-by: Alexandre Frade /* BBR marks the current round trip as a loss round. */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -393,7 +393,8 @@ static void tcp_ecn_send(struct sock *sk +@@ -347,7 +347,8 @@ static void tcp_ecn_send(struct sock *sk th->cwr = 1; skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; } diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch similarity index 81% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch index cbc7e2f42..bc4f45753 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch @@ -17,17 +17,17 @@ Signed-off-by: Alexandre Frade --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h -@@ -178,6 +178,7 @@ enum tcp_fastopen_client_fail { - #define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */ +@@ -185,6 +185,7 @@ enum tcp_fastopen_client_fail { #define TCPI_OPT_SYN_DATA 32 /* SYN-ACK acked data in SYN sent or rcvd */ #define TCPI_OPT_USEC_TS 64 /* usec timestamps */ -+#define TCPI_OPT_ECN_LOW 128 /* Low-latency ECN configured at init */ + #define TCPI_OPT_TFO_CHILD 128 /* child from a Fast Open option on SYN */ ++#define TCPI_OPT_ECN_LOW 256 /* Low-latency ECN enabled at conn init */ /* * Sender's congestion state indicating normal or abnormal situations --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -4124,6 +4124,8 @@ void tcp_get_info(struct sock *sk, struc +@@ -4227,6 +4227,8 @@ void tcp_get_info(struct sock *sk, struc info->tcpi_options |= TCPI_OPT_ECN; if (tp->ecn_flags & TCP_ECN_SEEN) info->tcpi_options |= TCPI_OPT_ECN_SEEN; diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch similarity index 100% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch diff --git a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch similarity index 91% rename from openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch rename to openwrt/patch/kernel-6.18/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch index 520924fa1..41c0d06da 100644 --- a/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch @@ -24,7 +24,7 @@ Signed-off-by: Oleksandr Natalenko --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c -@@ -1077,7 +1077,7 @@ static int bbr_update_ecn_alpha(struct s +@@ -1079,7 +1079,7 @@ static int bbr_update_ecn_alpha(struct s /* See if we should use ECN sender logic for this connection. */ if (!bbr->ecn_eligible && bbr_can_use_ecn(sk) && @@ -33,7 +33,7 @@ Signed-off-by: Oleksandr Natalenko (bbr->min_rtt_us <= bbr_ecn_max_rtt_us || !bbr_ecn_max_rtt_us)) bbr->ecn_eligible = 1; -@@ -1184,7 +1184,7 @@ static bool bbr_is_inflight_too_high(con +@@ -1186,7 +1186,7 @@ static bool bbr_is_inflight_too_high(con } if (rs->delivered_ce > 0 && rs->delivered > 0 && @@ -42,7 +42,7 @@ Signed-off-by: Oleksandr Natalenko ecn_thresh = (u64)rs->delivered * bbr_param(sk, ecn_thresh) >> BBR_SCALE; if (rs->delivered_ce > ecn_thresh) { -@@ -1382,7 +1382,7 @@ static void bbr_adapt_lower_bounds(struc +@@ -1384,7 +1384,7 @@ static void bbr_adapt_lower_bounds(struc return; /* ECN response. */ diff --git a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch similarity index 90% rename from openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch rename to openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch index 92870fe59..d154bb792 100644 --- a/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch +++ b/openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch @@ -10,7 +10,7 @@ Signed-off-by: sbwml --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c -@@ -8025,8 +8025,6 @@ static int btf_module_notify(struct noti +@@ -8199,8 +8199,6 @@ static int btf_module_notify(struct noti pr_warn("failed to validate module [%s] BTF: %ld\n", mod->name, PTR_ERR(btf)); err = PTR_ERR(btf); diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch similarity index 88% rename from openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch rename to openwrt/patch/kernel-6.18/linux-rt/012-RT-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch index 7deb3505c..c8f557152 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch +++ b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch @@ -1,7 +1,7 @@ -From 7d1d8942f209cdef6e23e192de25b4cde70c7843 Mon Sep 17 00:00:00 2001 +From be75f083e7a43c61ee1c80c40a000335ad46d6f3 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 27 Feb 2016 08:09:11 +0100 -Subject: [PATCH 1/8] drm/i915: Use preempt_disable/enable_rt() where +Subject: [PATCH 1/7] drm/i915: Use preempt_disable/enable_rt() where recommended Mario Kleiner suggest in commit @@ -34,7 +34,7 @@ Signed-off-by: Sebastian Andrzej Siewior --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c -@@ -308,6 +308,20 @@ static void intel_vblank_section_exit(st +@@ -315,6 +315,20 @@ static void intel_vblank_section_exit(st struct drm_i915_private *i915 = to_i915(display->drm); spin_unlock(&i915->uncore.lock); } @@ -55,7 +55,7 @@ Signed-off-by: Sebastian Andrzej Siewior #else static void intel_vblank_section_enter(struct intel_display *display) { -@@ -316,6 +330,17 @@ static void intel_vblank_section_enter(s +@@ -323,6 +337,17 @@ static void intel_vblank_section_enter(s static void intel_vblank_section_exit(struct intel_display *display) { } @@ -73,7 +73,7 @@ Signed-off-by: Sebastian Andrzej Siewior #endif static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, -@@ -353,10 +378,10 @@ static bool i915_get_crtc_scanoutpos(str +@@ -359,10 +384,10 @@ static bool i915_get_crtc_scanoutpos(str * timing critical raw register reads, potentially with * preemption disabled, so the following code must not block. */ @@ -87,7 +87,7 @@ Signed-off-by: Sebastian Andrzej Siewior /* Get optional system timestamp before query. */ if (stime) -@@ -420,10 +445,10 @@ static bool i915_get_crtc_scanoutpos(str +@@ -426,10 +451,10 @@ static bool i915_get_crtc_scanoutpos(str if (etime) *etime = ktime_get(); @@ -101,7 +101,7 @@ Signed-off-by: Sebastian Andrzej Siewior /* * While in vblank, position will be negative -@@ -461,13 +486,11 @@ int intel_get_crtc_scanline(struct intel +@@ -467,13 +492,11 @@ int intel_get_crtc_scanline(struct intel unsigned long irqflags; int position; diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch similarity index 84% rename from openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch rename to openwrt/patch/kernel-6.18/linux-rt/012-RT-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch index f0c574903..f11467c95 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch +++ b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch @@ -1,7 +1,7 @@ -From ae7629b5cddf2ab8b3400f1a71be97036577fcd1 Mon Sep 17 00:00:00 2001 +From 5d14201d0fc026ed1d5a9ab1b951a20383524933 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Sat, 27 Feb 2016 09:01:42 +0100 -Subject: [PATCH 2/8] drm/i915: Don't disable interrupts on PREEMPT_RT during +Subject: [PATCH 2/7] drm/i915: Don't disable interrupts on PREEMPT_RT during atomic updates Commit @@ -39,7 +39,7 @@ Signed-off-by: Sebastian Andrzej Siewior --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c -@@ -521,7 +521,8 @@ void intel_pipe_update_start(struct inte +@@ -562,7 +562,8 @@ void intel_pipe_update_start(struct inte */ intel_psr_wait_for_idle_locked(new_crtc_state); @@ -49,7 +49,7 @@ Signed-off-by: Sebastian Andrzej Siewior crtc->debug.min_vbl = evade.min; crtc->debug.max_vbl = evade.max; -@@ -539,7 +540,8 @@ void intel_pipe_update_start(struct inte +@@ -580,7 +581,8 @@ void intel_pipe_update_start(struct inte return; irq_disable: @@ -59,9 +59,9 @@ Signed-off-by: Sebastian Andrzej Siewior } #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) -@@ -668,7 +670,8 @@ void intel_pipe_update_end(struct intel_ - */ - intel_vrr_send_push(new_crtc_state); +@@ -726,7 +728,8 @@ void intel_pipe_update_end(struct intel_ + if (!state->base.legacy_cursor_update) + intel_vrr_send_push(NULL, new_crtc_state); - local_irq_enable(); + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) @@ -71,7 +71,7 @@ Signed-off-by: Sebastian Andrzej Siewior goto out; --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c -@@ -902,13 +902,15 @@ intel_legacy_cursor_update(struct drm_pl +@@ -919,13 +919,15 @@ intel_legacy_cursor_update(struct drm_pl */ intel_psr_wait_for_idle_locked(crtc_state); @@ -89,7 +89,7 @@ Signed-off-by: Sebastian Andrzej Siewior } if (new_plane_state->uapi.visible) { -@@ -918,7 +920,8 @@ intel_legacy_cursor_update(struct drm_pl +@@ -935,7 +937,8 @@ intel_legacy_cursor_update(struct drm_pl intel_plane_disable_arm(NULL, plane, crtc_state); } @@ -101,7 +101,7 @@ Signed-off-by: Sebastian Andrzej Siewior --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c -@@ -711,11 +711,13 @@ int intel_vblank_evade(struct intel_vbla +@@ -761,11 +761,13 @@ int intel_vblank_evade(struct intel_vbla break; } diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0003-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch similarity index 76% rename from openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch rename to openwrt/patch/kernel-6.18/linux-rt/012-RT-0003-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch index af99667c4..88f28c0ef 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch +++ b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0003-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch @@ -1,7 +1,7 @@ -From 7e6152f775a4a6f3e2b36898056252a639b60ec7 Mon Sep 17 00:00:00 2001 +From 0b0d2f1b3fb77c96bc45b22f2b0928576d6ffe08 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 6 Dec 2018 09:52:20 +0100 -Subject: [PATCH 4/8] drm/i915: Disable tracing points on PREEMPT_RT +Subject: [PATCH 3/7] drm/i915: Disable tracing points on PREEMPT_RT Luca Abeni reported this: | BUG: scheduling while atomic: kworker/u8:2/15203/0x00000003 @@ -30,11 +30,12 @@ Signed-off-by: Sebastian Andrzej Siewior --- drivers/gpu/drm/i915/display/intel_display_trace.h | 4 ++++ drivers/gpu/drm/i915/i915_trace.h | 4 ++++ - 2 files changed, 8 insertions(+) + drivers/gpu/drm/i915/intel_uncore_trace.h | 4 ++++ + 3 files changed, 12 insertions(+) --- a/drivers/gpu/drm/i915/display/intel_display_trace.h +++ b/drivers/gpu/drm/i915/display/intel_display_trace.h -@@ -9,6 +9,10 @@ +@@ -13,6 +13,10 @@ #if !defined(__INTEL_DISPLAY_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) #define __INTEL_DISPLAY_TRACE_H__ @@ -42,9 +43,9 @@ Signed-off-by: Sebastian Andrzej Siewior +#define NOTRACE +#endif + + #include #include #include - #include --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -6,6 +6,10 @@ @@ -58,3 +59,16 @@ Signed-off-by: Sebastian Andrzej Siewior #include #include #include +--- a/drivers/gpu/drm/i915/intel_uncore_trace.h ++++ b/drivers/gpu/drm/i915/intel_uncore_trace.h +@@ -7,6 +7,10 @@ + #if !defined(__INTEL_UNCORE_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) + #define __INTEL_UNCORE_TRACE_H__ + ++#if defined(CONFIG_PREEMPT_RT) && !defined(NOTRACE) ++#define NOTRACE ++#endif ++ + #include "i915_reg_defs.h" + + #include diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0004-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch similarity index 86% rename from openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch rename to openwrt/patch/kernel-6.18/linux-rt/012-RT-0004-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch index e9de6cb32..771062b21 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch +++ b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0004-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch @@ -1,7 +1,7 @@ -From 7b539177855a717a3ca6d18c67ca2370aff203cc Mon Sep 17 00:00:00 2001 +From 05828eb4b80cc738696cdc733d92d66079055fd9 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 8 Sep 2021 19:03:41 +0200 -Subject: [PATCH 5/8] drm/i915/gt: Use spin_lock_irq() instead of +Subject: [PATCH 4/7] drm/i915/gt: Use spin_lock_irq() instead of local_irq_disable() + spin_lock() execlists_dequeue() is invoked from a function which uses @@ -28,7 +28,7 @@ Reviewed-by: Maarten Lankhorst --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c -@@ -1303,7 +1303,7 @@ static void execlists_dequeue(struct int +@@ -1298,7 +1298,7 @@ static void execlists_dequeue(struct int * and context switches) submission. */ @@ -37,7 +37,7 @@ Reviewed-by: Maarten Lankhorst /* * If the queue is higher priority than the last -@@ -1403,7 +1403,7 @@ static void execlists_dequeue(struct int +@@ -1398,7 +1398,7 @@ static void execlists_dequeue(struct int * Even if ELSP[1] is occupied and not worthy * of timeslices, our queue might be. */ @@ -46,7 +46,7 @@ Reviewed-by: Maarten Lankhorst return; } } -@@ -1429,7 +1429,7 @@ static void execlists_dequeue(struct int +@@ -1424,7 +1424,7 @@ static void execlists_dequeue(struct int if (last && !can_merge_rq(last, rq)) { spin_unlock(&ve->base.sched_engine->lock); @@ -55,7 +55,7 @@ Reviewed-by: Maarten Lankhorst return; /* leave this for another sibling */ } -@@ -1591,7 +1591,7 @@ done: +@@ -1586,7 +1586,7 @@ done: */ sched_engine->queue_priority_hint = queue_prio(sched_engine); i915_sched_engine_reset_on_empty(sched_engine); @@ -64,7 +64,7 @@ Reviewed-by: Maarten Lankhorst /* * We can skip poking the HW if we ended up with exactly the same set -@@ -1617,13 +1617,6 @@ done: +@@ -1612,13 +1612,6 @@ done: } } @@ -78,7 +78,7 @@ Reviewed-by: Maarten Lankhorst static void clear_ports(struct i915_request **ports, int count) { memset_p((void **)ports, NULL, count); -@@ -2478,7 +2471,7 @@ static void execlists_submission_tasklet +@@ -2473,7 +2466,7 @@ static void execlists_submission_tasklet } if (!engine->execlists.pending[0]) { diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0005-drm-i915-Drop-the-irqs_disabled-check.patch similarity index 90% rename from openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch rename to openwrt/patch/kernel-6.18/linux-rt/012-RT-0005-drm-i915-Drop-the-irqs_disabled-check.patch index 69f96cf2b..69e3ad254 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch +++ b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0005-drm-i915-Drop-the-irqs_disabled-check.patch @@ -1,7 +1,7 @@ -From 9c2e94663607f6db53df8f5a347a71e10ffa4dc3 Mon Sep 17 00:00:00 2001 +From cc42b122cdf624c893583842eb13448b9d6ff01a Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 1 Oct 2021 20:01:03 +0200 -Subject: [PATCH 6/8] drm/i915: Drop the irqs_disabled() check +Subject: [PATCH 5/7] drm/i915: Drop the irqs_disabled() check The !irqs_disabled() check triggers on PREEMPT_RT even with i915_sched_engine::lock acquired. The reason is the lock is transformed diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0006-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch similarity index 89% rename from openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch rename to openwrt/patch/kernel-6.18/linux-rt/012-RT-0006-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch index bed8a14b9..a18ec9237 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch +++ b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0006-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch @@ -1,7 +1,7 @@ -From 192d322a13f7fa4419cbedbd315ed42c7462e4e9 Mon Sep 17 00:00:00 2001 +From e62808ec002112e34475e776c7986f471d2dfffc Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 3 Oct 2023 21:37:21 +0200 -Subject: [PATCH 7/8] drm/i915/guc: Consider also RCU depth in busy loop. +Subject: [PATCH 6/7] drm/i915/guc: Consider also RCU depth in busy loop. intel_guc_send_busy_loop() looks at in_atomic() and irqs_disabled() to decide if it should busy-spin while waiting or if it may sleep. diff --git a/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0007-Revert-drm-i915-Depend-on-PREEMPT_RT.patch similarity index 84% rename from openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch rename to openwrt/patch/kernel-6.18/linux-rt/012-RT-0007-Revert-drm-i915-Depend-on-PREEMPT_RT.patch index 271cbd4c0..ecd5776e0 100644 --- a/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch +++ b/openwrt/patch/kernel-6.18/linux-rt/012-RT-0007-Revert-drm-i915-Depend-on-PREEMPT_RT.patch @@ -1,7 +1,7 @@ -From d387c5c9e6666a0d14dafdb51675d583ab55e7d8 Mon Sep 17 00:00:00 2001 +From bc682cebd9ef2e61ddba67ca478aa3ea6c0d47f6 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 21 Feb 2022 17:59:14 +0100 -Subject: [PATCH 8/8] Revert "drm/i915: Depend on !PREEMPT_RT." +Subject: [PATCH 7/7] Revert "drm/i915: Depend on !PREEMPT_RT." Once the known issues are addressed, it should be safe to enable the driver. diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch similarity index 98% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch index b8ee1c382..b655bdc66 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch @@ -1,6 +1,6 @@ -From a736ccf49716dde80660d93f32358b455662d1e1 Mon Sep 17 00:00:00 2001 +From 6ab67c13afbc92f79b42393037e607611986fabd Mon Sep 17 00:00:00 2001 From: Stephan Mueller -Date: Tue, 25 Apr 2023 22:22:44 +0200 +Date: Sat, 1 Feb 2025 11:53:01 +0100 Subject: [PATCH 01/25] LRNG: Entropy Source and DRNG Manager The kernel crypto API contains deterministic random number generators @@ -144,8 +144,8 @@ Signed-off-by: Stephan Mueller drivers/char/lrng/Makefile | 11 + drivers/char/lrng/lrng_definitions.h | 163 +++ drivers/char/lrng/lrng_drng_atomic.h | 23 + - drivers/char/lrng/lrng_drng_chacha20.c | 195 ++++ - drivers/char/lrng/lrng_drng_chacha20.h | 42 + + drivers/char/lrng/lrng_drng_chacha20.c | 210 ++++ + drivers/char/lrng/lrng_drng_chacha20.h | 49 + drivers/char/lrng/lrng_drng_drbg.h | 13 + drivers/char/lrng/lrng_drng_kcapi.h | 13 + drivers/char/lrng/lrng_drng_mgr.c | 742 ++++++++++++ @@ -156,7 +156,7 @@ Signed-off-by: Stephan Mueller drivers/char/lrng/lrng_es_irq.h | 24 + drivers/char/lrng/lrng_es_jent.h | 17 + drivers/char/lrng/lrng_es_krng.h | 17 + - drivers/char/lrng/lrng_es_mgr.c | 506 ++++++++ + drivers/char/lrng/lrng_es_mgr.c | 528 +++++++++ drivers/char/lrng/lrng_es_mgr.h | 56 + drivers/char/lrng/lrng_es_mgr_cb.h | 87 ++ drivers/char/lrng/lrng_es_sched.h | 20 + @@ -169,7 +169,7 @@ Signed-off-by: Stephan Mueller drivers/char/lrng/lrng_sha256.c | 72 ++ drivers/char/lrng/lrng_sysctl.h | 15 + include/linux/lrng.h | 251 ++++ - 31 files changed, 4034 insertions(+) + 31 files changed, 4078 insertions(+) create mode 100644 drivers/char/lrng/Kconfig create mode 100644 drivers/char/lrng/Makefile create mode 100644 drivers/char/lrng/lrng_definitions.h @@ -202,7 +202,7 @@ Signed-off-by: Stephan Mueller --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig -@@ -422,4 +422,6 @@ config ADI +@@ -423,4 +423,6 @@ config ADI and SSM (Silicon Secured Memory). Intended consumers of this driver include crash and makedumpfile. @@ -211,7 +211,7 @@ Signed-off-by: Stephan Mueller endmenu --- a/drivers/char/Makefile +++ b/drivers/char/Makefile -@@ -43,3 +43,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o +@@ -44,3 +44,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o obj-$(CONFIG_XILLYBUS_CLASS) += xillybus/ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o obj-$(CONFIG_ADI) += adi.o @@ -292,20 +292,20 @@ Signed-off-by: Stephan Mueller + default n + help + When enabling this option, two entropy sources must -+ deliver 220 bits of entropy each to consider a DRNG ++ deliver 240 bits of entropy each to consider a DRNG + as fully seeded. Any two entropy sources can be used + to fulfill this requirement. If specific entropy sources + shall not be capable of contributing to this seeding + strategy, the respective entropy source must be configured -+ to provide less than 220 bits of entropy. ++ to provide less than 240 bits of entropy. + + The strategy is consistent with the requirements for -+ NTG.1 compliance in German AIS 20/31 draft from 2022 ++ NTG.1 compliance in German AIS 20/31 version 3.0 from 2024 + and is only enforced with lrng_es_mgr.ntg1=1. + -+ Compliance with German AIS 20/31 from 2011 is always -+ present when using /dev/random with the flag O_SYNC or -+ getrandom(2) with GRND_RANDOM. ++ Compliance with German AIS 20/31 version 2.0 from 2011 is ++ always present when using /dev/random with the flag O_SYNC ++ or getrandom(2) with GRND_RANDOM. + + If unsure, say N. + @@ -1329,7 +1329,7 @@ Signed-off-by: Stephan Mueller +#define LRNG_INIT_ENTROPY_BITS 32 + +/* AIS20/31: NTG.1.4 minimum entropy rate for one entropy source*/ -+#define LRNG_AIS2031_NPTRNG_MIN_ENTROPY 220 ++#define LRNG_AIS2031_NPTRNG_MIN_ENTROPY 240 + +/* + * Wakeup value @@ -1445,7 +1445,7 @@ Signed-off-by: Stephan Mueller +#endif /* _LRNG_DRNG_ATOMIC_H */ --- /dev/null +++ b/drivers/char/lrng/lrng_drng_chacha20.c -@@ -0,0 +1,195 @@ +@@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Backend for the LRNG providing the cryptographic primitives using @@ -1467,6 +1467,21 @@ Signed-off-by: Stephan Mueller + +#define CHACHA_BLOCK_WORDS (CHACHA_BLOCK_SIZE / sizeof(u32)) + ++static inline void lrng_chacha20_block_compat(struct chacha20_block *chacha20, ++ u8 *out) ++{ ++ struct chacha_state state; ++ ++ chacha_init_consts(&state); ++ memcpy(&state.x[4], chacha20->key.u, sizeof(chacha20->key.u)); ++ state.x[12] = chacha20->counter; ++ state.x[13] = chacha20->nonce[0]; ++ state.x[14] = chacha20->nonce[1]; ++ state.x[15] = chacha20->nonce[2]; ++ ++ chacha20_block(&state, out); ++} ++ +/* + * Update of the ChaCha20 state by either using an unused buffer part or by + * generating one ChaCha20 block which is half of the state of the ChaCha20. @@ -1485,7 +1500,7 @@ Signed-off-by: Stephan Mueller + BUILD_BUG_ON(CHACHA_BLOCK_SIZE != 2 * CHACHA_KEY_SIZE); + + if (used_words > CHACHA_KEY_SIZE_WORDS) { -+ chacha20_block(&chacha20->constants[0], (u8 *)tmp); ++ lrng_chacha20_block_compat(chacha20, (u8 *)tmp); + for (i = 0; i < CHACHA_KEY_SIZE_WORDS; i++) + chacha20->key.u[i] ^= le32_to_cpu(tmp[i]); + memzero_explicit(tmp, sizeof(tmp)); @@ -1555,13 +1570,13 @@ Signed-off-by: Stephan Mueller + int zeroize_buf = 0; + + while (outbuflen >= CHACHA_BLOCK_SIZE) { -+ chacha20_block(&chacha20->constants[0], outbuf); ++ lrng_chacha20_block_compat(chacha20, outbuf); + outbuf += CHACHA_BLOCK_SIZE; + outbuflen -= CHACHA_BLOCK_SIZE; + } + + if (outbuflen) { -+ chacha20_block(&chacha20->constants[0], (u8 *)aligned_buf); ++ lrng_chacha20_block_compat(chacha20, (u8 *)aligned_buf); + memcpy(outbuf, aligned_buf, outbuflen); + used = ((outbuflen + sizeof(aligned_buf[0]) - 1) / + sizeof(aligned_buf[0])); @@ -1643,7 +1658,7 @@ Signed-off-by: Stephan Mueller +#endif /* CONFIG_LRNG_DFLT_DRNG_CHACHA20 */ --- /dev/null +++ b/drivers/char/lrng/lrng_drng_chacha20.h -@@ -0,0 +1,42 @@ +@@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * LRNG ChaCha20 definitions @@ -1674,7 +1689,14 @@ Signed-off-by: Stephan Mueller + +static inline void lrng_cc20_init_rfc7539(struct chacha20_block *chacha20) +{ -+ chacha_init_consts(chacha20->constants); ++ struct chacha_state state = {}; ++ ++ chacha_init_consts(&state); ++ ++ chacha20->constants[0] = state.x[0]; ++ chacha20->constants[1] = state.x[1]; ++ chacha20->constants[2] = state.x[2]; ++ chacha20->constants[3] = state.x[3]; +} + +#define LRNG_CC20_INIT_RFC7539(x) \ @@ -2035,7 +2057,7 @@ Signed-off-by: Stephan Mueller + * producing data while this is ongoing. + */ + } while (force_seeding && forced && !drng->fully_seeded && -+ num_es_delivered >= (lrng_ntg1_2022_compliant() ? 2 : 1)); ++ num_es_delivered >= (lrng_ntg1_2024_compliant() ? 2 : 1)); + + memzero_explicit(&seedbuf, sizeof(seedbuf)); + @@ -3026,7 +3048,7 @@ Signed-off-by: Stephan Mueller +#endif /* _LRNG_ES_RANDOM_H */ --- /dev/null +++ b/drivers/char/lrng/lrng_es_mgr.c -@@ -0,0 +1,506 @@ +@@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG Entropy sources management @@ -3042,6 +3064,12 @@ Signed-off-by: Stephan Mueller +#include +#include + ++#ifdef CONFIG_VDSO_GETRANDOM ++#include ++#include ++#include ++#endif ++ +#include "lrng_drng_atomic.h" +#include "lrng_drng_mgr.h" +#include "lrng_es_aux.h" @@ -3131,9 +3159,8 @@ Signed-off-by: Stephan Mueller + return lrng_panic_on_permanent_health_failure; +} + -+bool lrng_ntg1_2022_compliant(void) ++bool lrng_ntg1_2024_compliant(void) +{ -+ /* Implies use of /dev/random w/ O_SYNC / getrandom w/ GRND_RANDOM */ + return ntg1; +} + @@ -3198,6 +3225,11 @@ Signed-off-by: Stephan Mueller + lrng_state.lrng_fully_seeded = false; + lrng_state.lrng_min_seeded = false; + lrng_state.all_online_numa_node_seeded = false; ++ ++#ifdef CONFIG_VDSO_GETRANDOM ++ /* WRITE_ONCE(__arch_get_k_vdso_rng_data()->is_ready, false); */ ++#endif ++ + pr_debug("reset LRNG\n"); +} + @@ -3234,6 +3266,14 @@ Signed-off-by: Stephan Mueller + +static void lrng_init_wakeup(void) +{ ++#ifdef CONFIG_VDSO_GETRANDOM ++ /* ++ * The LRNG does not enable the user space ChaCha20 ++ * DRNG in the VDSO. ++ */ ++ /* WRITE_ONCE(__arch_get_k_vdso_rng_data()->is_ready, true); */ ++#endif ++ + wake_up_all(&lrng_init_wait); + lrng_init_wakeup_dev(); + lrng_kick_random_ready(); @@ -3257,8 +3297,8 @@ Signed-off-by: Stephan Mueller +bool lrng_fully_seeded(bool fully_seeded, u32 collected_entropy, + struct entropy_buf *eb) +{ -+ /* AIS20/31 NTG.1: two entropy sources with each delivering 220 bits */ -+ if (ntg1) { ++ /* AIS20/31 NTG.1: two entropy sources with each delivering 240 bits */ ++ if (!fully_seeded && ntg1) { + u32 i, result = 0, ent_thresh = lrng_avail_entropy_thresh(); + + for_each_lrng_es(i) { @@ -3300,6 +3340,10 @@ Signed-off-by: Stephan Mueller + lrng_state.lrng_operational = false; + lrng_state.lrng_fully_seeded = false; + ++#ifdef CONFIG_VDSO_GETRANDOM ++ /* WRITE_ONCE(__arch_get_k_vdso_rng_data()->is_ready, false); */ ++#endif ++ + /* If sufficient entropy is available, reseed now. */ + lrng_es_add_entropy(); + } @@ -3359,7 +3403,7 @@ Signed-off-by: Stephan Mueller + return; + + requested_bits = ntg1 ? -+ /* Approximation so that two ES should deliver 220 bits each */ ++ /* Approximation so that two ES should deliver 240 bits each */ + (lrng_avail_entropy() + LRNG_AIS2031_NPTRNG_MIN_ENTROPY) : + /* Apply SP800-90C oversampling if applicable */ + lrng_get_seed_entropy_osr(state->all_online_numa_node_seeded); @@ -3562,7 +3606,7 @@ Signed-off-by: Stephan Mueller + for ((ctr) = 0; (ctr) < lrng_ext_es_last; (ctr)++) + +bool lrng_enforce_panic_on_permanent_health_failure(void); -+bool lrng_ntg1_2022_compliant(void); ++bool lrng_ntg1_2024_compliant(void); +bool lrng_pool_all_numa_nodes_seeded_get(void); +bool lrng_state_min_seeded(void); +void lrng_debug_report_seedlevel(const char *name); diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch similarity index 98% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch index 1ced3e297..ea352f408 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch @@ -1,4 +1,4 @@ -From c214eec976715ae46ed8e6eee5a2147c8fd155eb Mon Sep 17 00:00:00 2001 +From 02d42166cbad6ba32033313e6828f49b497baaf5 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 15 May 2022 15:40:46 +0200 Subject: [PATCH 02/25] LRNG - allocate one DRNG instance per NUMA node diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0003-LRNG-proc-interface.patch similarity index 96% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0003-LRNG-proc-interface.patch index 826bfcf24..1cf11a048 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0003-LRNG-proc-interface.patch @@ -1,4 +1,4 @@ -From b97aca849edc371e2586ab0a2f12908910cfa500 Mon Sep 17 00:00:00 2001 +From debd65a3952744217f46ca1d234b98e0a182e676 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 18 Dec 2022 21:12:42 +0100 Subject: [PATCH 03/25] LRNG - /proc interface @@ -90,7 +90,7 @@ Signed-off-by: Stephan Mueller + lrng_security_strength(), + numa_drngs, + lrng_sp80090c_compliant() ? "SP800-90C, " : "", -+ lrng_ntg1_2022_compliant() ? " / 2022" : "", ++ lrng_ntg1_2024_compliant() ? " / 2024" : "", + lrng_state_min_seeded() ? "true" : "false", + lrng_state_fully_seeded() ? "true" : "false", + lrng_avail_entropy()); diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch index 1dc9c7d10..7fb3d0079 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch @@ -1,4 +1,4 @@ -From 074dffdaefb5398b95a733f38aa58c973f918e20 Mon Sep 17 00:00:00 2001 +From 0567447f38dc80698352d6683810f7df09f926bb Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 20 Feb 2023 22:02:06 +0100 Subject: [PATCH 04/25] LRNG - add switchable DRNG support diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch similarity index 98% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch index bb3ce8740..5a328aa6d 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch @@ -1,4 +1,4 @@ -From 6db232ea9ebcca23650d15e3606a8f4d48c09ca1 Mon Sep 17 00:00:00 2001 +From 73ef8dee29ad83e4e07e26b651d3d04dddc4438e Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 15 May 2022 16:01:44 +0200 Subject: [PATCH 05/25] LRNG - add common generic hash support diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch similarity index 86% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch index 0ce584cb5..d4a6d8bc2 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch @@ -1,4 +1,4 @@ -From b59bd03bfd2776058531dc6f9573a0e0a46a23d2 Mon Sep 17 00:00:00 2001 +From 1bfa3a1d69ab42205b6ce9e13a5c8010c16212d0 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Thu, 21 Mar 2024 14:17:33 +0100 Subject: [PATCH 06/25] crypto: DRBG - externalize DRBG functions for LRNG @@ -14,7 +14,7 @@ Signed-off-by: Stephan Mueller --- a/crypto/drbg.c +++ b/crypto/drbg.c -@@ -115,7 +115,7 @@ +@@ -116,7 +116,7 @@ * HMAC-SHA512 / SHA256 / AES 256 over other ciphers. Thus, the * favored DRBGs are the latest entries in this array. */ @@ -23,7 +23,7 @@ Signed-off-by: Stephan Mueller #ifdef CONFIG_CRYPTO_DRBG_CTR { .flags = DRBG_CTR | DRBG_STRENGTH128, -@@ -180,6 +180,7 @@ static const struct drbg_core drbg_cores +@@ -181,6 +181,7 @@ static const struct drbg_core drbg_cores }, #endif /* CONFIG_CRYPTO_DRBG_HMAC */ }; @@ -31,7 +31,7 @@ Signed-off-by: Stephan Mueller static int drbg_uninstantiate(struct drbg_state *drbg); -@@ -195,7 +196,7 @@ static int drbg_uninstantiate(struct drb +@@ -196,7 +197,7 @@ static int drbg_uninstantiate(struct drb * Return: normalized strength in *bytes* value or 32 as default * to counter programming errors */ @@ -40,7 +40,7 @@ Signed-off-by: Stephan Mueller { switch (flags & DRBG_STRENGTH_MASK) { case DRBG_STRENGTH128: -@@ -208,6 +209,7 @@ static inline unsigned short drbg_sec_st +@@ -209,6 +210,7 @@ static inline unsigned short drbg_sec_st return 32; } } @@ -48,7 +48,7 @@ Signed-off-by: Stephan Mueller /* * FIPS 140-2 continuous self test for the noise source -@@ -1236,7 +1238,7 @@ out: +@@ -1237,7 +1239,7 @@ out: } /* Free all substructures in a DRBG state without the DRBG state structure */ @@ -57,7 +57,7 @@ Signed-off-by: Stephan Mueller { if (!drbg) return; -@@ -1257,12 +1259,13 @@ static inline void drbg_dealloc_state(st +@@ -1258,12 +1260,13 @@ static inline void drbg_dealloc_state(st drbg->fips_primed = false; } } @@ -72,7 +72,7 @@ Signed-off-by: Stephan Mueller { int ret = -ENOMEM; unsigned int sb_size = 0; -@@ -1343,6 +1346,7 @@ err: +@@ -1344,6 +1347,7 @@ err: drbg_dealloc_state(drbg); return ret; } @@ -80,7 +80,7 @@ Signed-off-by: Stephan Mueller /************************************************************************* * DRBG interface functions -@@ -1877,8 +1881,7 @@ out: +@@ -1878,8 +1882,7 @@ out: * * return: flags */ @@ -90,7 +90,7 @@ Signed-off-by: Stephan Mueller { int i = 0; size_t start = 0; -@@ -1905,6 +1908,7 @@ static inline void drbg_convert_tfm_core +@@ -1906,6 +1909,7 @@ static inline void drbg_convert_tfm_core } } } diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch index b1c024ae4..1c5ef8e8c 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch @@ -1,4 +1,4 @@ -From ed6c12a2aeac7927392151adcbf947c3c0865988 Mon Sep 17 00:00:00 2001 +From 2e869f245789853af62630737a97173d3501c0b9 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 28 Jul 2024 21:39:01 +0200 Subject: [PATCH 07/25] LRNG - add SP800-90A DRBG extension diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch index 6632e2ff8..d9037da53 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch @@ -1,4 +1,4 @@ -From abd4e08622156956150d80bf4e8cd4b4c31113ef Mon Sep 17 00:00:00 2001 +From cb39bce15aca3daea5305e1b085fdf68bcb15101 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 20 Feb 2023 22:23:59 +0100 Subject: [PATCH 08/25] LRNG - add kernel crypto API PRNG extension diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch similarity index 98% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch index 76dd6ec1a..645eeda0e 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch @@ -1,4 +1,4 @@ -From 44fd5618cd312625394fc2cd0861b2ab44068148 Mon Sep 17 00:00:00 2001 +From bd07b1023c263b790592b97332029c25491730b7 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 20 Feb 2023 22:05:24 +0100 Subject: [PATCH 09/25] LRNG - add atomic DRNG implementation diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch similarity index 98% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch index 9ba7f20c2..7a97723ef 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch @@ -1,4 +1,4 @@ -From 23fcb6113f576df31763a698e8326c8d3bab57a6 Mon Sep 17 00:00:00 2001 +From 929a6edceacbae42c9802576cbf125ac091c005b Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 15 May 2022 16:21:44 +0200 Subject: [PATCH 10/25] LRNG - add common timer-based entropy source code diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch index 6e0d7a39c..4dad4766d 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch @@ -1,4 +1,4 @@ -From 7d4187b3588c7c0216ac82634493c30c1d5f28c7 Mon Sep 17 00:00:00 2001 +From 77f5d2dad6658d73ec36df21e08604110bf0364e Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Tue, 25 Apr 2023 23:03:39 +0200 Subject: [PATCH 11/25] LRNG - add interrupt entropy source diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch similarity index 75% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch index 686dd485c..26d88df94 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -1,6 +1,6 @@ -From 3f214277bf0fc706f883719b5f56a25955487e9c Mon Sep 17 00:00:00 2001 +From fd922b0c5d2007b72cc80917a7b3a920e6011886 Mon Sep 17 00:00:00 2001 From: Stephan Mueller -Date: Sun, 15 May 2022 16:39:02 +0200 +Date: Sat, 28 Sep 2024 21:24:59 +0200 Subject: [PATCH 12/25] scheduler - add entropy sampling hook The scheduler can be used as a source of entropy. This requires the @@ -16,15 +16,15 @@ Signed-off-by: Stephan Mueller --- a/kernel/sched/core.c +++ b/kernel/sched/core.c -@@ -7,6 +7,7 @@ - * Copyright (C) 1991-2002 Linus Torvalds +@@ -8,6 +8,7 @@ * Copyright (C) 1998-2024 Ingo Molnar, Red Hat */ + #define INSTANTIATE_EXPORTED_MIGRATE_DISABLE +#include + #include #include #include - #include -@@ -3620,6 +3621,8 @@ ttwu_stat(struct task_struct *p, int cpu +@@ -3641,6 +3642,8 @@ ttwu_stat(struct task_struct *p, int cpu { struct rq *rq; diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch index 1b9fb3828..320adcbb1 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch @@ -1,4 +1,4 @@ -From c83a2b55d00ccf38e9034664245a286ce5792be7 Mon Sep 17 00:00:00 2001 +From d6ec66e1acecf57db3c2a47012e2141ab20a8b5e Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Wed, 22 Feb 2023 07:05:59 +0100 Subject: [PATCH 13/25] LRNG - add scheduler-based entropy source diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch index 19a9e974a..8348ba01c 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch @@ -1,4 +1,4 @@ -From 77e3f8edebcba3cc3b60b654fa0ef12e73f4e378 Mon Sep 17 00:00:00 2001 +From d30ca0f68d72eb14c19aa5d92e67f0eb63b3086d Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Tue, 25 Apr 2023 23:13:30 +0200 Subject: [PATCH 14/25] LRNG - add SP800-90B compliant health tests diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch index 6f97cc889..d89d0c8f8 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch @@ -1,4 +1,4 @@ -From 92148eed7179e55a0f9d5cbedf42b814502e222a Mon Sep 17 00:00:00 2001 +From e7d55782ec935e5c652b8673397f5bee99ce2987 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 20 Feb 2023 22:07:27 +0100 Subject: [PATCH 15/25] LRNG - add random.c entropy source support diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch index 5058625a9..6a45f1d71 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch @@ -1,4 +1,4 @@ -From 67d7584f291dc9e3fb5a59645fce2fc8cadf3e38 Mon Sep 17 00:00:00 2001 +From ae89611be5b9703452ee9eca703d0b28728e28ea Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 20 Feb 2023 22:08:23 +0100 Subject: [PATCH 16/25] LRNG - CPU entropy source diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch index 555d147ad..4119b6203 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch @@ -1,4 +1,4 @@ -From a9b4e46d8253ca9e63fcf1fed126c407a1e4f73c Mon Sep 17 00:00:00 2001 +From f19c6b968e55182b6021c50c6279dbf853342fe6 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 27 Aug 2023 17:11:37 +0200 Subject: [PATCH 17/25] LRNG - add Jitter RNG fast noise source diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch similarity index 97% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch index 6961b98ab..35bd4bbc8 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch @@ -1,4 +1,4 @@ -From 718c21ecd7a9ac35fbdf28d2dcd2310634c669ef Mon Sep 17 00:00:00 2001 +From f9922de535ef07adbbe3044cc648475ffdfc7040 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 15 May 2022 17:56:56 +0200 Subject: [PATCH 18/25] LRNG - add option to enable runtime entropy rate diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch index ac7aee69c..13847d2ab 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch @@ -1,4 +1,4 @@ -From 78cb1213ad35895b6d0d1a1ff49224f0c123e86c Mon Sep 17 00:00:00 2001 +From 599c213c25a6d56bf4ac8685b7ff4cf1f4bf5f20 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 18 Dec 2022 21:22:36 +0100 Subject: [PATCH 19/25] LRNG - add interface for gathering of raw entropy diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch index c2cec9681..87141d348 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch @@ -1,4 +1,4 @@ -From 6c02564f6cdabbb5a463e0b10438d61a055e93d9 Mon Sep 17 00:00:00 2001 +From eddacc98bed6421e3f83639c2fb3e66d2451cd0d Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 15 May 2022 18:13:56 +0200 Subject: [PATCH 20/25] LRNG - add power-on and runtime self-tests diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch similarity index 97% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch index 79889edf3..29cd3424f 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch @@ -1,4 +1,4 @@ -From 6a5b2149c0ba1f6a04ae69368e5fbed2b38bff96 Mon Sep 17 00:00:00 2001 +From 80e7849ff47412ce3efa9cfb3ae3ff9cc02ec0d0 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 31 Jul 2022 22:34:51 +0200 Subject: [PATCH 21/25] LRNG - sysctls and /proc interface @@ -86,7 +86,7 @@ Signed-off-by: Stephan Mueller +} + +static int lrng_sysctl_do_entropy(const struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos) ++ void *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + int entropy_count = lrng_avail_entropy_aux(); diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch similarity index 99% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch index f059f581d..a8cc7629a 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch @@ -1,4 +1,4 @@ -From fa6f7a3d77638110f79d1972668afc4b15254ffa Mon Sep 17 00:00:00 2001 +From dfffa8a94b6d800ec4370982007fc85e4ab82c7a Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 20 Feb 2023 22:12:04 +0100 Subject: [PATCH 22/25] LRMG - add drop-in replacement random(4) API @@ -35,7 +35,7 @@ Signed-off-by: Stephan Mueller +obj-$(CONFIG_RANDOM_DEFAULT_IMPL) += random.o obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o obj-y += misc.o - obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o + obj-$(CONFIG_TEST_MISC_MINOR) += misc_minor_kunit.o --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -29,3 +29,8 @@ obj-$(CONFIG_LRNG_JENT) += lrng_es_jen diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch similarity index 98% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch index 159f7f5fd..9a924a9cf 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch @@ -1,4 +1,4 @@ -From 021ba8b87e270abdb892ae853fc863cb7e258265 Mon Sep 17 00:00:00 2001 +From caeedfaeac4743c46b3c85c8139ed5d79d1e084d Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 9 Oct 2022 10:22:39 +0200 Subject: [PATCH 23/25] LRNG - add kernel crypto API interface diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch similarity index 97% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch index 02dfb11e2..f4b98fb90 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch @@ -1,4 +1,4 @@ -From 7697fe0de6bdc7a8e0a4c722dbf6dec24ffe53d5 Mon Sep 17 00:00:00 2001 +From 36c40148b0eb1217a875b5c0694299f6d2e83492 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 15 May 2022 18:39:30 +0200 Subject: [PATCH 24/25] LRNG - add /dev/lrng device file support diff --git a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch similarity index 98% rename from openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch rename to openwrt/patch/kernel-6.18/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch index bc8eed543..f29bedfe3 100644 --- a/openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch @@ -1,4 +1,4 @@ -From 243b20ab41748e898abcf298b0cb836f04391afd Mon Sep 17 00:00:00 2001 +From de00e91ce125b8be4ee77a3f5a64cada10062c1a Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sun, 15 May 2022 18:43:30 +0200 Subject: [PATCH 25/25] LRNG - add hwrand framework interface diff --git a/openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch b/openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeouts-function.patch similarity index 100% rename from openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch rename to openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeouts-function.patch diff --git a/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch b/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch similarity index 94% rename from openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch rename to openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch index 6bcc95125..e6be120e3 100644 --- a/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch +++ b/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch @@ -22,7 +22,7 @@ Signed-off-by: Zhi Chen --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h -@@ -65,9 +65,14 @@ struct nf_ct_event_notifier { +@@ -69,9 +69,14 @@ struct nf_ct_event_notifier { int (*exp_event)(unsigned int events, const struct nf_exp_event *item); }; @@ -38,7 +38,7 @@ Signed-off-by: Zhi Chen void nf_ct_deliver_cached_events(struct nf_conn *ct); int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, -@@ -98,11 +103,13 @@ static inline void +@@ -102,11 +107,13 @@ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) { #ifdef CONFIG_NF_CONNTRACK_EVENTS @@ -53,7 +53,7 @@ Signed-off-by: Zhi Chen e = nf_ct_ecache_find(ct); if (e == NULL) -@@ -117,20 +124,34 @@ nf_conntrack_event_report(enum ip_conntr +@@ -129,20 +136,34 @@ nf_conntrack_event_report(enum ip_conntr u32 portid, int report) { #ifdef CONFIG_NF_CONNTRACK_EVENTS @@ -94,7 +94,7 @@ Signed-off-by: Zhi Chen #ifdef CONFIG_NF_CONNTRACK_EVENTS --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h -@@ -104,6 +104,9 @@ struct netns_ct { +@@ -91,6 +91,9 @@ struct netns_ct { u8 sysctl_checksum; struct ip_conntrack_stat __percpu *stat; @@ -123,7 +123,7 @@ Signed-off-by: Zhi Chen depends on NETFILTER_ADVANCED --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c -@@ -2753,6 +2753,10 @@ int nf_conntrack_init_net(struct net *ne +@@ -2760,6 +2760,10 @@ int nf_conntrack_init_net(struct net *ne nf_conntrack_ecache_pernet_init(net); nf_conntrack_proto_pernet_init(net); @@ -146,8 +146,8 @@ Signed-off-by: Zhi Chen #include #include #include -@@ -162,6 +165,35 @@ static int __nf_conntrack_eventmask_repo - return ret; +@@ -170,6 +173,35 @@ static void nf_ct_ecache_tstamp_refresh( + #endif } +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS @@ -182,7 +182,7 @@ Signed-off-by: Zhi Chen int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct, u32 portid, int report) { -@@ -197,10 +229,52 @@ int nf_conntrack_eventmask_report(unsign +@@ -207,10 +239,52 @@ int nf_conntrack_eventmask_report(unsign return ret; } @@ -235,7 +235,7 @@ Signed-off-by: Zhi Chen void nf_ct_deliver_cached_events(struct nf_conn *ct) { struct nf_conntrack_ecache *e; -@@ -226,6 +300,7 @@ void nf_ct_deliver_cached_events(struct +@@ -236,6 +310,7 @@ void nf_ct_deliver_cached_events(struct */ __nf_conntrack_eventmask_report(e, events, e->missed, &item); } @@ -243,7 +243,7 @@ Signed-off-by: Zhi Chen EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, -@@ -258,20 +333,43 @@ out_unlock: +@@ -268,20 +343,43 @@ out_unlock: rcu_read_unlock(); } @@ -289,7 +289,7 @@ Signed-off-by: Zhi Chen void nf_conntrack_unregister_notifier(struct net *net) { mutex_lock(&nf_ct_ecache_mutex); -@@ -279,6 +377,7 @@ void nf_conntrack_unregister_notifier(st +@@ -289,6 +387,7 @@ void nf_conntrack_unregister_notifier(st mutex_unlock(&nf_ct_ecache_mutex); /* synchronize_rcu() is called after netns pre_exit */ } @@ -299,7 +299,7 @@ Signed-off-by: Zhi Chen void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state) --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c -@@ -721,12 +721,19 @@ static size_t ctnetlink_nlmsg_size(const +@@ -741,12 +741,19 @@ static size_t ctnetlink_nlmsg_size(const } static int diff --git a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch similarity index 87% rename from openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch rename to openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 40dea69c3..8646f4811 100644 --- a/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -17,9 +17,9 @@ Signed-off-by: Xiaoping Fan --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h -@@ -72,6 +72,9 @@ void brioctl_set(int (*hook)(struct net - int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, - struct ifreq *ifr, void __user *uarg); +@@ -69,6 +69,9 @@ void brioctl_set(int (*hook)(struct net + void __user *uarg)); + int br_ioctl_call(struct net *net, unsigned int cmd, void __user *uarg); +extern void br_dev_update_stats(struct net_device *dev, + struct rtnl_link_stats64 *nlstats); @@ -29,7 +29,7 @@ Signed-off-by: Xiaoping Fan struct list_head *br_ip_list); --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -1011,6 +1011,9 @@ struct sk_buff { +@@ -1030,6 +1030,9 @@ struct sk_buff { __u8 csum_not_inet:1; #endif __u8 unreadable:1; @@ -41,7 +41,7 @@ Signed-off-by: Xiaoping Fan #endif --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h -@@ -68,6 +68,8 @@ struct nf_ct_event_notifier { +@@ -72,6 +72,8 @@ struct nf_ct_event_notifier { #ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS extern int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb); extern int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb); @@ -52,7 +52,7 @@ Signed-off-by: Xiaoping Fan const struct nf_ct_event_notifier *nb); --- a/net/Kconfig +++ b/net/Kconfig -@@ -518,6 +518,9 @@ config FAILOVER +@@ -520,6 +520,9 @@ config FAILOVER migration of VMs with direct attached VFs by failing over to the paravirtual datapath when the VF is unplugged. @@ -64,7 +64,7 @@ Signed-off-by: Xiaoping Fan select DIMLIB --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c -@@ -764,6 +764,26 @@ void br_port_flags_change(struct net_bri +@@ -765,6 +765,26 @@ void br_port_flags_change(struct net_bri br_recalculate_neigh_suppress_enabled(br); } @@ -93,7 +93,7 @@ Signed-off-by: Xiaoping Fan struct net_bridge_port *p; --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -3643,8 +3643,17 @@ static int xmit_one(struct sk_buff *skb, +@@ -3837,8 +3837,17 @@ static int xmit_one(struct sk_buff *skb, unsigned int len; int rc; @@ -103,15 +103,15 @@ Signed-off-by: Xiaoping Fan + */ + if (!skb->fast_forwarded) { +#endif - if (dev_nit_active(dev)) + if (dev_nit_active_rcu(dev)) dev_queue_xmit_nit(skb, dev); +#ifdef CONFIG_SHORTCUT_FE + } +#endif - #ifdef CONFIG_ETHERNET_PACKET_MANGLE - if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) -@@ -5493,6 +5502,11 @@ void netdev_rx_handler_unregister(struct + len = skb->len; + trace_net_dev_start_xmit(skb, dev); +@@ -5809,6 +5818,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5541,6 +5555,10 @@ static int __netif_receive_skb_core(stru +@@ -5858,6 +5872,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5579,6 +5597,16 @@ another_round: +@@ -5902,6 +5920,16 @@ another_round: goto out; } @@ -179,7 +179,7 @@ Signed-off-by: Xiaoping Fan rcu_read_unlock(); if (likely(ret >= 0 && missed == 0)) -@@ -339,6 +351,11 @@ int nf_conntrack_register_notifier(struc +@@ -349,6 +361,11 @@ int nf_conntrack_register_notifier(struc { return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); } @@ -191,7 +191,7 @@ Signed-off-by: Xiaoping Fan #else int nf_conntrack_register_notifier(struct net *net, const struct nf_ct_event_notifier *new) -@@ -369,6 +386,11 @@ int nf_conntrack_unregister_notifier(str +@@ -379,6 +396,11 @@ int nf_conntrack_unregister_notifier(str { return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); } diff --git a/openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch b/openwrt/patch/kernel-6.18/net/982-add-bcm-fullcone-support.patch similarity index 100% rename from openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch rename to openwrt/patch/kernel-6.18/net/982-add-bcm-fullcone-support.patch diff --git a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch similarity index 97% rename from openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch rename to openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch index f9ad88e36..5182d3a6f 100644 --- a/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -11,7 +11,7 @@ int nft_parse_register_store(const struct nft_ctx *ctx, --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h -@@ -1481,12 +1481,16 @@ enum nft_tproxy_attributes { +@@ -1499,12 +1499,16 @@ enum nft_tproxy_attributes { * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) @@ -30,7 +30,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -11153,6 +11153,24 @@ static int nft_validate_register_load(en +@@ -11628,6 +11628,24 @@ static int nft_validate_register_load(en return 0; } diff --git a/openwrt/patch/kernel-6.12/net/README.md b/openwrt/patch/kernel-6.18/net/README.md similarity index 78% rename from openwrt/patch/kernel-6.12/net/README.md rename to openwrt/patch/kernel-6.18/net/README.md index 105c48c9f..bd59c54dc 100644 --- a/openwrt/patch/kernel-6.12/net/README.md +++ b/openwrt/patch/kernel-6.18/net/README.md @@ -1,9 +1,5 @@ # Patches -## Fullcone - -- [x] Patch 1: [952-net-conntrack-events-support-multiple-registrant.patch](./952-net-conntrack-events-support-multiple-registrant.patch) - ## BCM-Fullcone - [x] Patch 1: [982-add-bcm-fullcone-support.patch](./982-add-bcm-fullcone-support.patch) @@ -12,4 +8,5 @@ ## Shortcut Forwarding Engine - [x] Patch 1: [601-netfilter-export-udp_get_timeouts-function.patch](./601-netfilter-export-udp_get_timeouts-function.patch) -- [x] Patch 2: [953-net-patch-linux-kernel-to-support-shortcut-fe.patch](./953-net-patch-linux-kernel-to-support-shortcut-fe.patch) +- [x] Patch 2: [952-net-conntrack-events-support-multiple-registrant.patch](./952-net-conntrack-events-support-multiple-registrant.patch) +- [x] Patch 3: [953-net-patch-linux-kernel-to-support-shortcut-fe.patch](./953-net-patch-linux-kernel-to-support-shortcut-fe.patch) diff --git a/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch b/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch similarity index 86% rename from openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch rename to openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch index 577d92882..9dc11737b 100644 --- a/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch +++ b/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch @@ -93,6 +93,28 @@ index c85df1f..fdcebc7 100644 { phy_driver_unregister(&b53_phy_driver_id3); phy_driver_unregister(&b53_phy_driver_id2); +diff --git a/target/linux/generic/files/drivers/net/phy/rtl8306.c b/target/linux/generic/files/drivers/net/phy/rtl8306.c +index 31bc758..d7a5faa 100644 +--- a/target/linux/generic/files/drivers/net/phy/rtl8306.c ++++ b/target/linux/generic/files/drivers/net/phy/rtl8306.c +@@ -1047,14 +1047,14 @@ static struct phy_driver rtl8306_driver = { + static int __init + rtl_init(void) + { +- phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup); +- return phy_driver_register(&rtl8306_driver, THIS_MODULE); ++ phy_register_fixup_for_id("*", rtl8306_fixup); ++ return phy_drivers_register(&rtl8306_driver, 1, THIS_MODULE); + } + + static void __exit + rtl_exit(void) + { +- phy_driver_unregister(&rtl8306_driver); ++ phy_drivers_unregister(&rtl8306_driver, 1); + } + + module_init(rtl_init); diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c index a26fd20..c3d50a0 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c @@ -114,7 +136,7 @@ index a26fd20..c3d50a0 100644 { struct rtl8366_platform_data *pdata = pdev->dev.platform_data; diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c -index 0878ca9..cce9bde 100644 +index 0878ca9..06f92fb 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c @@ -1478,7 +1478,7 @@ static int rtl8366rb_probe(struct platform_device *pdev) @@ -135,17 +157,8 @@ index 0878ca9..cce9bde 100644 } #ifdef CONFIG_OF -@@ -1506,7 +1504,7 @@ static struct platform_driver rtl8366rb_driver = { - .of_match_table = of_match_ptr(rtl8366rb_match), - }, - .probe = rtl8366rb_probe, -- .remove = rtl8366rb_remove, -+ .remove_new = rtl8366rb_remove, - }; - - static int __init rtl8366rb_module_init(void) diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366s.c b/target/linux/generic/files/drivers/net/phy/rtl8366s.c -index d4045fc..5458c50 100644 +index d4045fc..513ed2c 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366s.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366s.c @@ -1266,7 +1266,7 @@ static int rtl8366s_probe(struct platform_device *pdev) @@ -166,17 +179,8 @@ index d4045fc..5458c50 100644 } #ifdef CONFIG_OF -@@ -1296,7 +1294,7 @@ static struct platform_driver rtl8366s_driver = { - #endif - }, - .probe = rtl8366s_probe, -- .remove = rtl8366s_remove, -+ .remove_new = rtl8366s_remove, - }; - - static int __init rtl8366s_module_init(void) diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367.c b/target/linux/generic/files/drivers/net/phy/rtl8367.c -index 950e9d2..1b99601 100644 +index 950e9d2..7c10ce2 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367.c @@ -1801,7 +1801,7 @@ static int rtl8367_probe(struct platform_device *pdev) @@ -197,17 +201,8 @@ index 950e9d2..1b99601 100644 } static void rtl8367_shutdown(struct platform_device *pdev) -@@ -1839,7 +1837,7 @@ static struct platform_driver rtl8367_driver = { - #endif - }, - .probe = rtl8367_probe, -- .remove = rtl8367_remove, -+ .remove_new = rtl8367_remove, - .shutdown = rtl8367_shutdown, - }; - diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c -index 5f885aa..5adcf00 100644 +index 5f885aa..dc55fc6 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367b.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c @@ -1600,7 +1600,7 @@ static int rtl8367b_probe(struct platform_device *pdev) @@ -228,12 +223,3 @@ index 5f885aa..5adcf00 100644 } static void rtl8367b_shutdown(struct platform_device *pdev) -@@ -1638,7 +1636,7 @@ static struct platform_driver rtl8367b_driver = { - #endif - }, - .probe = rtl8367b_probe, -- .remove = rtl8367b_remove, -+ .remove_new = rtl8367b_remove, - .shutdown = rtl8367b_shutdown, - }; - diff --git a/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch b/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch index 54a8c8ab1..f67ecad46 100644 --- a/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch +++ b/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch @@ -9,11 +9,11 @@ Signed-off-by: sbwml 1 file changed, 14 insertions(+) diff --git a/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js b/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js -index e837fbf..14451bf 100644 +index 6c01d88..f64e4ed 100644 --- a/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js +++ b/applications/luci-app-natmap/htdocs/luci-static/resources/view/natmap.js -@@ -80,12 +80,26 @@ return view.extend({ - o.modalonly = true; +@@ -85,12 +85,26 @@ return view.extend({ + o.depends('udp_mode', '1'); o = s.option(form.Value, 'stun_server', _('STUN server')); + o.value('stun.voipia.net'); @@ -23,7 +23,7 @@ index e837fbf..14451bf 100644 + o.value('stun.fitauto.ru'); + o.value('stun.cooluc.com'); + o.default = 'stun.voipia.net'; - o.datatype = 'host'; + o.datatype = 'string'; o.modalonly = true; o.optional = false; o.rmempty = false; @@ -36,9 +36,6 @@ index e837fbf..14451bf 100644 + o.value('stun.fitauto.ru'); + o.value('stun.cooluc.com'); + o.default = 'stun.voipia.net'; - o.datatype = 'host'; + o.datatype = 'string'; o.modalonly = true; o.rmempty = false; --- -2.42.0 - diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 2e4da90a1..82be30c47 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -3,14 +3,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mt76 PKG_RELEASE=1 -PKG_LICENSE:=GPLv2 +PKG_LICENSE:=BSD-3-Clause-Clear PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2025-09-15 -PKG_SOURCE_VERSION:=6467af3bcf1154c2ceb032c903d533f0c718bbc2 -PKG_MIRROR_HASH:=98781ea57cdc97bc63ecb2c1d4004964f2a10663987887445f1c71b76610cd96 +PKG_SOURCE_DATE:=2025-10-20 +PKG_SOURCE_VERSION:=c63db0fcadb88680b35bec202b5142cfd016c10f +PKG_MIRROR_HASH:=38c3c84f5c58b6967283acf524412f6e13628d50add6f09d539f1239fb02b486 PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 diff --git a/openwrt/patch/mt76/README.md b/openwrt/patch/mt76/README.md index 6f63b6e6c..1285f63e1 100644 --- a/openwrt/patch/mt76/README.md +++ b/openwrt/patch/mt76/README.md @@ -1 +1 @@ -# mt76 - fix work for linux-6.12 +# mt76 - fix build for linux-6.18 diff --git a/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch b/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch new file mode 100644 index 000000000..fda80690b --- /dev/null +++ b/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch @@ -0,0 +1,490 @@ +--- a/mac80211.c ++++ b/mac80211.c +@@ -1932,7 +1932,8 @@ void mt76_sw_scan_complete(struct ieee80 + } + EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); + +-int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) ++int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, ++ u32 *rx_ant) + { + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; +--- a/mt76.h ++++ b/mt76.h +@@ -1577,7 +1577,8 @@ int mt76_get_sar_power(struct mt76_phy * + void mt76_csa_check(struct mt76_dev *dev); + void mt76_csa_finish(struct mt76_dev *dev); + +-int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); ++int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, ++ u32 *rx_ant); + int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); + void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id); + int mt76_get_rate(struct mt76_dev *dev, +--- a/mt7603/main.c ++++ b/mt7603/main.c +@@ -216,7 +216,7 @@ static int mt7603_set_sar_specs(struct i + } + + static int +-mt7603_config(struct ieee80211_hw *hw, u32 changed) ++mt7603_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + struct mt7603_dev *dev = hw->priv; + int ret = 0; +@@ -657,7 +657,8 @@ mt7603_sta_rate_tbl_update(struct ieee80 + } + + static void +-mt7603_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) ++mt7603_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, ++ s16 coverage_class) + { + struct mt7603_dev *dev = hw->priv; + +--- a/mt7615/main.c ++++ b/mt7615/main.c +@@ -97,7 +97,7 @@ static void mt7615_stop(struct ieee80211 + struct mt7615_phy *phy = mt7615_hw_phy(hw); + + cancel_delayed_work_sync(&phy->mt76->mac_work); +- del_timer_sync(&phy->roc_timer); ++ timer_delete_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + + cancel_delayed_work_sync(&dev->pm.ps_work); +@@ -420,7 +420,7 @@ static int mt7615_set_sar_specs(struct i + return mt76_update_channel(phy->mt76); + } + +-static int mt7615_config(struct ieee80211_hw *hw, u32 changed) ++static int mt7615_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); +@@ -784,7 +784,8 @@ static void mt7615_tx(struct ieee80211_h + mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); + } + +-static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) ++static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, ++ u32 val) + { + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); +@@ -972,7 +973,8 @@ mt7615_offset_tsf(struct ieee80211_hw *h + } + + static void +-mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) ++mt7615_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, ++ s16 coverage_class) + { + struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt7615_dev *dev = phy->dev; +@@ -984,7 +986,8 @@ mt7615_set_coverage_class(struct ieee802 + } + + static int +-mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ++mt7615_set_antenna(struct ieee80211_hw *hw, int radio_idx, ++ u32 tx_ant, u32 rx_ant) + { + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); +@@ -1043,7 +1046,7 @@ void mt7615_roc_work(struct work_struct + + void mt7615_roc_timer(struct timer_list *timer) + { +- struct mt7615_phy *phy = from_timer(phy, timer, roc_timer); ++ struct mt7615_phy *phy = timer_container_of(phy, timer, roc_timer); + + ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); + } +@@ -1194,7 +1197,7 @@ static int mt7615_cancel_remain_on_chann + if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + return 0; + +- del_timer_sync(&phy->roc_timer); ++ timer_delete_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + + mt7615_mutex_acquire(phy->dev); +--- a/mt7615/pci_mac.c ++++ b/mt7615/pci_mac.c +@@ -220,12 +220,12 @@ void mt7615_mac_reset_work(struct work_s + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + cancel_delayed_work_sync(&dev->mphy.mac_work); +- del_timer_sync(&dev->phy.roc_timer); ++ timer_delete_sync(&dev->phy.roc_timer); + cancel_work_sync(&dev->phy.roc_work); + if (phy2) { + set_bit(MT76_RESET, &phy2->mt76->state); + cancel_delayed_work_sync(&phy2->mt76->mac_work); +- del_timer_sync(&phy2->roc_timer); ++ timer_delete_sync(&phy2->roc_timer); + cancel_work_sync(&phy2->roc_work); + } + +--- a/mt7615/usb.c ++++ b/mt7615/usb.c +@@ -85,7 +85,7 @@ static void mt7663u_stop(struct ieee8021 + struct mt7615_dev *dev = hw->priv; + + clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); +- del_timer_sync(&phy->roc_timer); ++ timer_delete_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + cancel_delayed_work_sync(&phy->scan_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); +--- a/mt76x0/main.c ++++ b/mt76x0/main.c +@@ -57,7 +57,7 @@ out: + } + EXPORT_SYMBOL_GPL(mt76x0_set_sar_specs); + +-int mt76x0_config(struct ieee80211_hw *hw, u32 changed) ++int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + struct mt76x02_dev *dev = hw->priv; + +--- a/mt76x0/mt76x0.h ++++ b/mt76x0/mt76x0.h +@@ -48,7 +48,7 @@ void mt76x0_chip_onoff(struct mt76x02_de + + void mt76x0_mac_stop(struct mt76x02_dev *dev); + +-int mt76x0_config(struct ieee80211_hw *hw, u32 changed); ++int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed); + int mt76x0_set_channel(struct mt76_phy *mphy); + int mt76x0_set_sar_specs(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar); +--- a/mt76x02.h ++++ b/mt76x02.h +@@ -183,8 +183,8 @@ void mt76x02_wdt_work(struct work_struct + void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); + void mt76x02_set_tx_ackto(struct mt76x02_dev *dev); + void mt76x02_set_coverage_class(struct ieee80211_hw *hw, +- s16 coverage_class); +-int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val); ++ int radio_idx, s16 coverage_class); ++int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val); + void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); + bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update); + void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, +--- a/mt76x02_usb_core.c ++++ b/mt76x02_usb_core.c +@@ -264,8 +264,7 @@ void mt76x02u_init_beacon_config(struct + }; + dev->beacon_ops = &beacon_ops; + +- hrtimer_init(&dev->pre_tbtt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +- dev->pre_tbtt_timer.function = mt76x02u_pre_tbtt_interrupt; ++ hrtimer_setup(&dev->pre_tbtt_timer, mt76x02u_pre_tbtt_interrupt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + INIT_WORK(&dev->pre_tbtt_work, mt76x02u_pre_tbtt_work); + + mt76x02_init_beacon_config(dev); +--- a/mt76x02_util.c ++++ b/mt76x02_util.c +@@ -548,7 +548,7 @@ void mt76x02_set_tx_ackto(struct mt76x02 + EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto); + + void mt76x02_set_coverage_class(struct ieee80211_hw *hw, +- s16 coverage_class) ++ int radio_idx, s16 coverage_class) + { + struct mt76x02_dev *dev = hw->priv; + +@@ -559,7 +559,7 @@ void mt76x02_set_coverage_class(struct i + } + EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class); + +-int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) ++int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val) + { + struct mt76x02_dev *dev = hw->priv; + +--- a/mt76x2/pci_main.c ++++ b/mt76x2/pci_main.c +@@ -54,7 +54,7 @@ int mt76x2e_set_channel(struct mt76_phy + } + + static int +-mt76x2_config(struct ieee80211_hw *hw, u32 changed) ++mt76x2_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + struct mt76x02_dev *dev = hw->priv; + +@@ -99,8 +99,8 @@ mt76x2_flush(struct ieee80211_hw *hw, st + { + } + +-static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, +- u32 rx_ant) ++static int mt76x2_set_antenna(struct ieee80211_hw *hw, int radio_idx, ++ u32 tx_ant, u32 rx_ant) + { + struct mt76x02_dev *dev = hw->priv; + +--- a/mt76x2/usb_main.c ++++ b/mt76x2/usb_main.c +@@ -50,7 +50,7 @@ int mt76x2u_set_channel(struct mt76_phy + } + + static int +-mt76x2u_config(struct ieee80211_hw *hw, u32 changed) ++mt76x2u_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + struct mt76x02_dev *dev = hw->priv; + int err = 0; +--- a/mt7915/main.c ++++ b/mt7915/main.c +@@ -449,7 +449,8 @@ out: + return err; + } + +-static int mt7915_config(struct ieee80211_hw *hw, u32 changed) ++static int mt7915_config(struct ieee80211_hw *hw, int radio_idx, ++ u32 changed) + { + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); +@@ -913,7 +914,8 @@ static void mt7915_tx(struct ieee80211_h + mt76_tx(mphy, control->sta, wcid, skb); + } + +-static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) ++static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, ++ u32 val) + { + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); +@@ -1109,7 +1111,8 @@ mt7915_offset_tsf(struct ieee80211_hw *h + } + + static void +-mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) ++mt7915_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, ++ s16 coverage_class) + { + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_dev *dev = phy->dev; +@@ -1121,7 +1124,7 @@ mt7915_set_coverage_class(struct ieee802 + } + + static int +-mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ++mt7915_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_ant) + { + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); +@@ -1699,7 +1702,7 @@ mt7915_twt_teardown_request(struct ieee8 + } + + static int +-mt7915_set_frag_threshold(struct ieee80211_hw *hw, u32 val) ++mt7915_set_frag_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val) + { + return 0; + } +--- a/mt7921/main.c ++++ b/mt7921/main.c +@@ -371,7 +371,7 @@ void mt7921_roc_abort_sync(struct mt792x + { + struct mt792x_phy *phy = &dev->phy; + +- del_timer_sync(&phy->roc_timer); ++ timer_delete_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + ieee80211_iterate_interfaces(mt76_hw(dev), +@@ -402,7 +402,7 @@ static int mt7921_abort_roc(struct mt792 + { + int err = 0; + +- del_timer_sync(&phy->roc_timer); ++ timer_delete_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + + mt792x_mutex_acquire(phy->dev); +@@ -626,7 +626,7 @@ void mt7921_set_runtime_pm(struct mt792x + mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); + } + +-static int mt7921_config(struct ieee80211_hw *hw, u32 changed) ++static int mt7921_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); +@@ -915,7 +915,8 @@ void mt7921_mac_sta_remove(struct mt76_d + } + EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove); + +-static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, u32 val) ++static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, ++ u32 val) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + +@@ -1096,7 +1097,8 @@ mt7921_stop_sched_scan(struct ieee80211_ + } + + static int +-mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ++mt7921_set_antenna(struct ieee80211_hw *hw, int radio_idx, ++ u32 tx_ant, u32 rx_ant) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); +@@ -1492,7 +1494,7 @@ static void mt7921_abort_channel_switch( + { + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + +- del_timer_sync(&mvif->csa_timer); ++ timer_delete_sync(&mvif->csa_timer); + cancel_work_sync(&mvif->csa_work); + } + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -449,7 +449,7 @@ void mt7925_roc_abort_sync(struct mt792x + { + struct mt792x_phy *phy = &dev->phy; + +- del_timer_sync(&phy->roc_timer); ++ timer_delete_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + ieee80211_iterate_interfaces(mt76_hw(dev), +@@ -481,7 +481,7 @@ static int mt7925_abort_roc(struct mt792 + { + int err = 0; + +- del_timer_sync(&phy->roc_timer); ++ timer_delete_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + + mt792x_mutex_acquire(phy->dev); +@@ -750,7 +750,7 @@ void mt7925_set_runtime_pm(struct mt792x + mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); + } + +-static int mt7925_config(struct ieee80211_hw *hw, u32 changed) ++static int mt7925_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int ret = 0; +@@ -1211,7 +1211,8 @@ void mt7925_mac_sta_remove(struct mt76_d + } + EXPORT_SYMBOL_GPL(mt7925_mac_sta_remove); + +-static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, u32 val) ++static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, ++ u32 val) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + +@@ -1453,7 +1454,8 @@ mt7925_stop_sched_scan(struct ieee80211_ + } + + static int +-mt7925_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ++mt7925_set_antenna(struct ieee80211_hw *hw, int radio_idx, ++ u32 tx_ant, u32 rx_ant) + { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); +--- a/mt792x.h ++++ b/mt792x.h +@@ -411,7 +411,8 @@ void mt792x_sta_statistics(struct ieee80 + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo); +-void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class); ++void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, ++ s16 coverage_class); + void mt792x_dma_cleanup(struct mt792x_dev *dev); + int mt792x_dma_enable(struct mt792x_dev *dev); + int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force); +--- a/mt792x_core.c ++++ b/mt792x_core.c +@@ -305,7 +305,7 @@ EXPORT_SYMBOL_GPL(mt792x_tx_worker); + + void mt792x_roc_timer(struct timer_list *timer) + { +- struct mt792x_phy *phy = from_timer(phy, timer, roc_timer); ++ struct mt792x_phy *phy = timer_container_of(phy, timer, roc_timer); + + ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); + } +@@ -313,7 +313,7 @@ EXPORT_SYMBOL_GPL(mt792x_roc_timer); + + void mt792x_csa_timer(struct timer_list *timer) + { +- struct mt792x_vif *mvif = from_timer(mvif, timer, csa_timer); ++ struct mt792x_vif *mvif = timer_container_of(mvif, timer, csa_timer); + + ieee80211_queue_work(mvif->phy->mt76->hw, &mvif->csa_work); + } +@@ -362,7 +362,7 @@ void mt792x_unassign_vif_chanctx(struct + mutex_unlock(&dev->mt76.mutex); + + if (vif->bss_conf.csa_active) { +- del_timer_sync(&mvif->csa_timer); ++ timer_delete_sync(&mvif->csa_timer); + cancel_work_sync(&mvif->csa_work); + } + } +@@ -601,7 +601,8 @@ void mt792x_sta_statistics(struct ieee80 + } + EXPORT_SYMBOL_GPL(mt792x_sta_statistics); + +-void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) ++void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, ++ s16 coverage_class) + { + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct mt792x_dev *dev = phy->dev; +--- a/mt7996/main.c ++++ b/mt7996/main.c +@@ -655,7 +655,7 @@ static int mt7996_set_key(struct ieee802 + return err; + } + +-static int mt7996_config(struct ieee80211_hw *hw, u32 changed) ++static int mt7996_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) + { + return 0; + } +@@ -1371,7 +1371,8 @@ unlock: + rcu_read_unlock(); + } + +-static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) ++static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, ++ u32 val) + { + struct mt7996_dev *dev = mt7996_hw_dev(hw); + int i, ret = 0; +@@ -1591,7 +1592,8 @@ unlock: + } + + static void +-mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) ++mt7996_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, ++ s16 coverage_class) + { + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy; +@@ -1605,7 +1607,8 @@ mt7996_set_coverage_class(struct ieee802 + } + + static int +-mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ++mt7996_set_antenna(struct ieee80211_hw *hw, int radio_idx, ++ u32 tx_ant, u32 rx_ant) + { + struct mt7996_dev *dev = mt7996_hw_dev(hw); + int i; diff --git a/openwrt/patch/openwrt-6.x/modules/crypto.mk b/openwrt/patch/openwrt-6.x/modules/crypto.mk index 78c971217..6f814ab00 100644 --- a/openwrt/patch/openwrt-6.x/modules/crypto.mk +++ b/openwrt/patch/openwrt-6.x/modules/crypto.mk @@ -116,7 +116,7 @@ $(eval $(call KernelPackage,crypto-ccm)) define KernelPackage/crypto-chacha20poly1305 TITLE:=ChaCha20-Poly1305 AEAD support, RFC7539 (used by strongSwan IPsec VPN) - DEPENDS:=+kmod-crypto-aead +kmod-crypto-manager + DEPENDS:=+kmod-crypto-aead +kmod-crypto-manager +kmod-crypto-lib-poly1305 KCONFIG:=CONFIG_CRYPTO_CHACHA20POLY1305 FILES:=$(LINUX_DIR)/crypto/chacha20poly1305.ko AUTOLOAD:=$(call AutoLoad,09,chacha20poly1305) @@ -143,8 +143,8 @@ define KernelPackage/crypto-crc32 DEPENDS:=+kmod-crypto-hash KCONFIG:=CONFIG_CRYPTO_CRC32 HIDDEN:=1 - FILES:=$(LINUX_DIR)/crypto/crc32_generic.ko - AUTOLOAD:=$(call AutoLoad,04,crc32_generic,1) + FILES:=$(LINUX_DIR)/crypto/crc32c-cryptoapi.ko + AUTOLOAD:=$(call AutoLoad,04,crc32c-cryptoapi,1) $(call AddDepends/crypto) endef @@ -155,8 +155,8 @@ define KernelPackage/crypto-crc32c TITLE:=CRC32c CRC module DEPENDS:=+kmod-crypto-hash KCONFIG:=CONFIG_CRYPTO_CRC32C - FILES:=$(LINUX_DIR)/crypto/crc32c_generic.ko - AUTOLOAD:=$(call AutoLoad,04,crc32c_generic,1) + FILES:=$(LINUX_DIR)/crypto/crc32c-cryptoapi.ko + AUTOLOAD:=$(call AutoLoad,04,crc32c-cryptoapi,1) $(call AddDepends/crypto) endef @@ -566,40 +566,6 @@ define KernelPackage/crypto-lib-chacha20 $(call AddDepends/crypto) endef -define KernelPackage/crypto-lib-chacha20/x86_64 - KCONFIG+=CONFIG_CRYPTO_CHACHA20_X86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/chacha-x86_64.ko -endef - -# Note that a non-neon fallback implementation is available on arm32 when -# NEON is not supported, hence all arm targets can utilize lib-chacha20/arm -define KernelPackage/crypto-lib-chacha20/arm - KCONFIG+=CONFIG_CRYPTO_CHACHA20_NEON - FILES:=$(LINUX_DIR)/arch/arm/crypto/chacha-neon.ko -endef - -KernelPackage/crypto-lib-chacha20/armeb=$(KernelPackage/crypto-lib-chacha20/arm) - -define KernelPackage/crypto-lib-chacha20/aarch64 - KCONFIG+=CONFIG_CRYPTO_CHACHA20_NEON - FILES+=$(LINUX_DIR)/arch/arm64/crypto/chacha-neon.ko -endef - -define KernelPackage/crypto-lib-chacha20/mips32r2 - KCONFIG+=CONFIG_CRYPTO_CHACHA_MIPS - FILES:=$(LINUX_DIR)/arch/mips/crypto/chacha-mips.ko -endef - -ifeq ($(CONFIG_CPU_MIPS32_R2),y) - KernelPackage/crypto-lib-chacha20/$(ARCH)=\ - $(KernelPackage/crypto-lib-chacha20/mips32r2) -endif - -ifdef KernelPackage/crypto-lib-chacha20/$(ARCH) - KernelPackage/crypto-lib-chacha20/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-lib-chacha20/$(ARCH)) -endif - $(eval $(call KernelPackage,crypto-lib-chacha20)) @@ -619,8 +585,7 @@ define KernelPackage/crypto-lib-curve25519 KCONFIG:=CONFIG_CRYPTO_LIB_CURVE25519 HIDDEN:=1 FILES:= \ - $(LINUX_DIR)/lib/crypto/libcurve25519.ko \ - $(LINUX_DIR)/lib/crypto/libcurve25519-generic.ko + $(LINUX_DIR)/lib/crypto/libcurve25519.ko $(call AddDepends/crypto,+PACKAGE_kmod-crypto-kpp:kmod-crypto-kpp) endef @@ -628,26 +593,6 @@ define KernelPackage/crypto-lib-curve25519/config imply PACKAGE_kmod-crypto-kpp endef -define KernelPackage/crypto-lib-curve25519/x86_64 - KCONFIG+=CONFIG_CRYPTO_CURVE25519_X86 - FILES+=$(LINUX_DIR)/arch/x86/crypto/curve25519-x86_64.ko -endef - -define KernelPackage/crypto-lib-curve25519/arm-neon - KCONFIG+=CONFIG_CRYPTO_CURVE25519_NEON - FILES+=$(LINUX_DIR)/arch/arm/crypto/curve25519-neon.ko -endef - -ifeq ($(ARCH)-$(CONFIG_KERNEL_MODE_NEON),arm-y) - KernelPackage/crypto-lib-curve25519/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-lib-curve25519/arm-neon) -endif - -ifdef KernelPackage/crypto-lib-curve25519/$(ARCH) - KernelPackage/crypto-lib-curve25519/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-lib-curve25519/$(ARCH)) -endif - $(eval $(call KernelPackage,crypto-lib-curve25519)) @@ -656,44 +601,9 @@ define KernelPackage/crypto-lib-poly1305 KCONFIG:=CONFIG_CRYPTO_LIB_POLY1305 HIDDEN:=1 FILES:=$(LINUX_DIR)/lib/crypto/libpoly1305.ko - $(call AddDepends/crypto,+PACKAGE_kmod-crypto-hash:kmod-crypto-hash) -endef - -define KernelPackage/crypto-lib-poly1305/config - imply PACKAGE_kmod-crypto-hash -endef - -define KernelPackage/crypto-lib-poly1305/x86_64 - KCONFIG+=CONFIG_CRYPTO_POLY1305_X86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/poly1305-x86_64.ko -endef - -define KernelPackage/crypto-lib-poly1305/arm - KCONFIG+=CONFIG_CRYPTO_POLY1305_ARM - FILES:=$(LINUX_DIR)/arch/arm/crypto/poly1305-arm.ko -endef - -KernelPackage/crypto-lib-poly1305/armeb=$(KernelPackage/crypto-lib-poly1305/arm) - -define KernelPackage/crypto-lib-poly1305/aarch64 - KCONFIG+=CONFIG_CRYPTO_POLY1305_NEON - FILES:=$(LINUX_DIR)/arch/arm64/crypto/poly1305-neon.ko -endef - -define KernelPackage/crypto-lib-poly1305/mips - KCONFIG+=CONFIG_CRYPTO_POLY1305_MIPS - FILES:=$(LINUX_DIR)/arch/mips/crypto/poly1305-mips.ko + $(call AddDepends/crypto) endef -KernelPackage/crypto-lib-poly1305/mipsel=$(KernelPackage/crypto-lib-poly1305/mips) -KernelPackage/crypto-lib-poly1305/mips64=$(KernelPackage/crypto-lib-poly1305/mips) -KernelPackage/crypto-lib-poly1305/mips64el=$(KernelPackage/crypto-lib-poly1305/mips) - -ifdef KernelPackage/crypto-lib-poly1305/$(ARCH) - KernelPackage/crypto-lib-poly1305/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-lib-poly1305/$(ARCH)) -endif - $(eval $(call KernelPackage,crypto-lib-poly1305)) @@ -730,26 +640,13 @@ define KernelPackage/crypto-md5 CONFIG_CRYPTO_MD5 \ CONFIG_CRYPTO_MD5_OCTEON \ CONFIG_CRYPTO_MD5_PPC - FILES:=$(LINUX_DIR)/crypto/md5.ko + FILES:= \ + $(LINUX_DIR)/crypto/md5.ko \ + $(LINUX_DIR)/lib/crypto/libmd5.ko AUTOLOAD:=$(call AutoLoad,09,md5) $(call AddDepends/crypto) endef -define KernelPackage/crypto-md5/octeon - FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-md5.ko - AUTOLOAD+=$(call AutoLoad,09,octeon-md5) -endef - -define KernelPackage/crypto-md5/powerpc - FILES+=$(LINUX_DIR)/arch/powerpc/crypto/md5-ppc.ko - AUTOLOAD+=$(call AutoLoad,09,md5-ppc) -endef - -ifdef KernelPackage/crypto-md5/$(ARCH) - KernelPackage/crypto-md5/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-md5/$(ARCH)) -endif - $(eval $(call KernelPackage,crypto-md5)) @@ -966,62 +863,11 @@ define KernelPackage/crypto-sha1 CONFIG_CRYPTO_SHA1_OCTEON \ CONFIG_CRYPTO_SHA1_PPC_SPE \ CONFIG_CRYPTO_SHA1_SSSE3 - FILES:=$(LINUX_DIR)/crypto/sha1_generic.ko - AUTOLOAD:=$(call AutoLoad,09,sha1_generic) + FILES:=$(LINUX_DIR)/crypto/sha1.ko + AUTOLOAD:=$(call AutoLoad,09,sha1) $(call AddDepends/crypto) endef -define KernelPackage/crypto-sha1/arm - FILES+=$(LINUX_DIR)/arch/arm/crypto/sha1-arm.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-arm) -endef - -define KernelPackage/crypto-sha1/arm-neon - $(call KernelPackage/crypto-sha1/arm) - FILES+=$(LINUX_DIR)/arch/arm/crypto/sha1-arm-neon.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-arm-neon) -endef - -define KernelPackage/crypto-sha1/aarch64-ce - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha1-ce.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-ce) -endef - -KernelPackage/crypto-sha1/imx/cortexa7=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/imx/cortexa9=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/ipq40xx=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/mediatek/filogic=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/mediatek/mt7622=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/mvebu/cortexa9=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/mvebu/cortexa53=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/mvebu/cortexa72=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/qualcommax=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/rockchip/armv8=$(KernelPackage/crypto-sha1/aarch64-ce) - -define KernelPackage/crypto-sha1/octeon - FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha1.ko - AUTOLOAD+=$(call AutoLoad,09,octeon-sha1) -endef - -KernelPackage/crypto-sha1/tegra=$(KernelPackage/crypto-sha1/arm) - -define KernelPackage/crypto-sha1/mpc85xx - FILES+=$(LINUX_DIR)/arch/powerpc/crypto/sha1-ppc-spe.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-ppc-spe) -endef - -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-sha1/x86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/sha1-ssse3.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-ssse3) -endef -endif - -ifdef KernelPackage/crypto-sha1/$(ARCH) - KernelPackage/crypto-sha1/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-sha1/$(ARCH)) -endif - $(eval $(call KernelPackage,crypto-sha1)) @@ -1042,58 +888,20 @@ define KernelPackage/crypto-sha256 DEPENDS:=+kmod-crypto-hash KCONFIG:= \ CONFIG_CRYPTO_SHA256 \ + CONFIG_CRYPTO_LIB_SHA256_GENERIC=y \ + CRYPTO_CRYPTO_LIB_SHA256_ARCH=y \ CONFIG_CRYPTO_SHA256_OCTEON \ CONFIG_CRYPTO_SHA256_PPC_SPE \ CONFIG_CRYPTO_SHA256_ARM64 \ CONFIG_CRYPTO_SHA2_ARM64_CE \ CONFIG_CRYPTO_SHA256_SSSE3 FILES:= \ - $(LINUX_DIR)/crypto/sha256_generic.ko \ + $(LINUX_DIR)/crypto/sha256.ko \ $(LINUX_DIR)/lib/crypto/libsha256.ko AUTOLOAD:=$(call AutoLoad,09,sha256_generic) $(call AddDepends/crypto) endef -define KernelPackage/crypto-sha256/aarch64 - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha256-arm64.ko - AUTOLOAD+=$(call AutoLoad,09,sha256-arm64) -endef - -define KernelPackage/crypto-sha256/aarch64-ce - $(call KernelPackage/crypto-sha256/aarch64) - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha2-ce.ko - AUTOLOAD+=$(call AutoLoad,09,sha2-ce) -endef - -define KernelPackage/crypto-sha256/octeon - FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha256.ko - AUTOLOAD+=$(call AutoLoad,09,octeon-sha256) -endef - -define KernelPackage/crypto-sha256/mpc85xx - FILES+=$(LINUX_DIR)/arch/powerpc/crypto/sha256-ppc-spe.ko - AUTOLOAD+=$(call AutoLoad,09,sha256-ppc-spe) -endef - -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-sha256/x86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/sha256-ssse3.ko - AUTOLOAD+=$(call AutoLoad,09,sha256-ssse3) -endef -endif - -KernelPackage/crypto-sha256/mediatek/filogic=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/mediatek/mt7622=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/mvebu/cortexa53=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/mvebu/cortexa72=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/qualcommax=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/rockchip/armv8=$(KernelPackage/crypto-sha256/aarch64-ce) - -ifdef KernelPackage/crypto-sha256/$(ARCH) - KernelPackage/crypto-sha256/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-sha256/$(ARCH)) -endif - $(eval $(call KernelPackage,crypto-sha256)) @@ -1106,45 +914,13 @@ define KernelPackage/crypto-sha512 CONFIG_CRYPTO_SHA512_ARM64 \ CONFIG_CRYPTO_SHA512_OCTEON \ CONFIG_CRYPTO_SHA512_SSSE3 - FILES:=$(LINUX_DIR)/crypto/sha512_generic.ko - AUTOLOAD:=$(call AutoLoad,09,sha512_generic) + FILES:= \ + $(LINUX_DIR)/crypto/sha512.ko \ + $(LINUX_DIR)/lib/crypto/libsha512.ko + AUTOLOAD:=$(call AutoLoad,09,sha512) $(call AddDepends/crypto) endef -define KernelPackage/crypto-sha512/arm - FILES+=$(LINUX_DIR)/arch/arm/crypto/sha512-arm.ko - AUTOLOAD+=$(call AutoLoad,09,sha512-arm) -endef - -define KernelPackage/crypto-sha512/aarch64 - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha512-arm64.ko - AUTOLOAD+=$(call AutoLoad,09,sha512-arm64) -endef - -KernelPackage/crypto-sha512/imx/cortexa7=$(KernelPackage/crypto-sha512/arm) -KernelPackage/crypto-sha512/imx/cortexa9=$(KernelPackage/crypto-sha512/arm) -KernelPackage/crypto-sha512/ipq40xx=$(KernelPackage/crypto-sha512/arm) -KernelPackage/crypto-sha512/mvebu/cortexa9=$(KernelPackage/crypto-sha512/arm) - -define KernelPackage/crypto-sha512/octeon - FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha512.ko - AUTOLOAD+=$(call AutoLoad,09,octeon-sha512) -endef - -KernelPackage/crypto-sha512/tegra=$(KernelPackage/crypto-sha512/arm) - -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-sha512/x86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/sha512-ssse3.ko - AUTOLOAD+=$(call AutoLoad,09,sha512-ssse3) -endef -endif - -ifdef KernelPackage/crypto-sha512/$(ARCH) - KernelPackage/crypto-sha512/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-sha512/$(ARCH)) -endif - $(eval $(call KernelPackage,crypto-sha512)) diff --git a/openwrt/patch/openwrt-6.x/modules/fs.mk b/openwrt/patch/openwrt-6.x/modules/fs.mk index e676ea767..b4b4c9209 100644 --- a/openwrt/patch/openwrt-6.x/modules/fs.mk +++ b/openwrt/patch/openwrt-6.x/modules/fs.mk @@ -91,7 +91,6 @@ define KernelPackage/fs-smbfs-common KCONFIG:=\ CONFIG_SMBFS FILES:= \ - $(LINUX_DIR)/fs/smb/common/cifs_arc4.ko \ $(LINUX_DIR)/fs/smb/common/cifs_md4.ko endef diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index 09a077fde..c1014a417 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -10,7 +10,7 @@ HWMON_MENU:=Hardware Monitoring Support define KernelPackage/hwmon-core SUBMENU:=$(HWMON_MENU) TITLE:=Hardware monitoring support - DEPENDS:=+LINUX_6_12:kmod-i2c-core + DEPENDS:=+kmod-i2c-core KCONFIG:= \ CONFIG_HWMON \ CONFIG_HWMON_DEBUG_CHIP=n diff --git a/openwrt/patch/openwrt-6.x/modules/i2c.mk b/openwrt/patch/openwrt-6.x/modules/i2c.mk index 6145dc307..9c506a2ad 100644 --- a/openwrt/patch/openwrt-6.x/modules/i2c.mk +++ b/openwrt/patch/openwrt-6.x/modules/i2c.mk @@ -150,7 +150,7 @@ I2C_I801_MODULES:= \ define KernelPackage/i2c-i801 $(call i2c_defaults,$(I2C_I801_MODULES),59) TITLE:=Intel I801 and compatible I2C interfaces - DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus +LINUX_6_12:kmod-i2c-mux + DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus +kmod-i2c-mux endef define KernelPackage/i2c-i801/description @@ -289,7 +289,7 @@ I2C_PIIX4_MODULES:= \ define KernelPackage/i2c-piix4 $(call i2c_defaults,$(I2C_PIIX4_MODULES),59) TITLE:=Intel PIIX4 and compatible I2C interfaces - DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +LINUX_6_12:kmod-i2c-smbus + DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus endef define KernelPackage/i2c-piix4/description diff --git a/openwrt/patch/openwrt-6.x/modules/iio.mk b/openwrt/patch/openwrt-6.x/modules/iio.mk index 531c8207d..3a5ae96f4 100644 --- a/openwrt/patch/openwrt-6.x/modules/iio.mk +++ b/openwrt/patch/openwrt-6.x/modules/iio.mk @@ -208,7 +208,7 @@ $(eval $(call KernelPackage,iio-dht11)) define KernelPackage/iio-bme680 TITLE:=BME680 gas/humidity/pressure/temperature sensor - DEPENDS:=+kmod-regmap-core + DEPENDS:=+kmod-regmap-core +kmod-industrialio-triggered-buffer KCONFIG:=CONFIG_BME680 FILES:=$(LINUX_DIR)/drivers/iio/chemical/bme680_core.ko $(call AddDepends/iio) @@ -252,7 +252,7 @@ $(eval $(call KernelPackage,iio-bme680-spi)) define KernelPackage/iio-bmp280 TITLE:=BMP180/BMP280/BME280 pressure/temperatur sensor - DEPENDS:=+kmod-regmap-core +LINUX_6_12:kmod-industrialio-triggered-buffer + DEPENDS:=+kmod-regmap-core +kmod-industrialio-triggered-buffer KCONFIG:=CONFIG_BMP280 FILES:=$(LINUX_DIR)/drivers/iio/pressure/bmp280.ko $(call AddDepends/iio) @@ -433,7 +433,7 @@ $(eval $(call KernelPackage,iio-lsm6dsx)) define KernelPackage/iio-lsm6dsx-i2c DEPENDS:=+kmod-iio-lsm6dsx +kmod-i2c-core +kmod-regmap-i2c TITLE:=ST LSM6DSx driver for IMU MEMS sensors (I2C) - KCONFIG:=CONFIG_IIO_ST_LSM6DSX + KCONFIG:=CONFIG_IIO_ST_LSM6DSX_I2C FILES:=$(LINUX_DIR)/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.ko AUTOLOAD:=$(call AutoProbe,st_lsm6dsx-i2c) $(call AddDepends/iio) @@ -449,7 +449,7 @@ $(eval $(call KernelPackage,iio-lsm6dsx-i2c)) define KernelPackage/iio-lsm6dsx-spi DEPENDS:=+kmod-iio-lsm6dsx +kmod-regmap-spi TITLE:=ST LSM6DSx driver for IMU MEMS sensors (SPI) - KCONFIG:=CONFIG_IIO_ST_LSM6DSX + KCONFIG:=CONFIG_IIO_ST_LSM6DSX_SPI FILES:=$(LINUX_DIR)/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.ko AUTOLOAD:=$(call AutoProbe,st_lsm6dsx-spi) $(call AddDepends/iio) diff --git a/openwrt/patch/openwrt-6.x/modules/lib.mk b/openwrt/patch/openwrt-6.x/modules/lib.mk index 011da30e4..e1512fbbb 100644 --- a/openwrt/patch/openwrt-6.x/modules/lib.mk +++ b/openwrt/patch/openwrt-6.x/modules/lib.mk @@ -11,7 +11,7 @@ define KernelPackage/lib-crc-ccitt SUBMENU:=$(LIB_MENU) TITLE:=CRC-CCITT support KCONFIG:=CONFIG_CRC_CCITT - FILES:=$(LINUX_DIR)/lib/crc-ccitt.ko + FILES:=$(LINUX_DIR)/lib/crc/crc-ccitt.ko AUTOLOAD:=$(call AutoProbe,crc-ccitt) endef @@ -26,7 +26,7 @@ define KernelPackage/lib-crc-itu-t SUBMENU:=$(LIB_MENU) TITLE:=CRC ITU-T V.41 support KCONFIG:=CONFIG_CRC_ITU_T - FILES:=$(LINUX_DIR)/lib/crc-itu-t.ko + FILES:=$(LINUX_DIR)/lib/crc/crc-itu-t.ko AUTOLOAD:=$(call AutoProbe,crc-itu-t) endef @@ -41,7 +41,7 @@ define KernelPackage/lib-crc7 SUBMENU:=$(LIB_MENU) TITLE:=CRC7 support KCONFIG:=CONFIG_CRC7 - FILES:=$(LINUX_DIR)/lib/crc7.ko + FILES:=$(LINUX_DIR)/lib/crc/crc7.ko AUTOLOAD:=$(call AutoProbe,crc7) endef @@ -56,7 +56,7 @@ define KernelPackage/lib-crc8 SUBMENU:=$(LIB_MENU) TITLE:=CRC8 support KCONFIG:=CONFIG_CRC8 - FILES:=$(LINUX_DIR)/lib/crc8.ko + FILES:=$(LINUX_DIR)/lib/crc/crc8.ko AUTOLOAD:=$(call AutoProbe,crc8) endef @@ -71,7 +71,7 @@ define KernelPackage/lib-crc16 SUBMENU:=$(LIB_MENU) TITLE:=CRC16 support KCONFIG:=CONFIG_CRC16 - FILES:=$(LINUX_DIR)/lib/crc16.ko + FILES:=$(LINUX_DIR)/lib/crc/crc16.ko AUTOLOAD:=$(call AutoLoad,20,crc16,1) endef @@ -87,7 +87,7 @@ define KernelPackage/lib-crc32c TITLE:=CRC32 support KCONFIG:=CONFIG_LIBCRC32C DEPENDS:=+kmod-crypto-crc32c - FILES:=$(LINUX_DIR)/lib/libcrc32c.ko + FILES:=$(LINUX_DIR)/lib/crc/libcrc32c.ko AUTOLOAD:=$(call AutoProbe,libcrc32c) endef @@ -385,7 +385,7 @@ $(eval $(call KernelPackage,lib-parman)) define KernelPackage/libwx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Wangxun(R) Ethernet driver common library - DEPENDS:=@PCI_SUPPORT +kmod-phylink + DEPENDS:=@PCI_SUPPORT +kmod-phylink +kmod-ptp KCONFIG:=CONFIG_LIBWX FILES:=$(LINUX_DIR)/drivers/net/ethernet/wangxun/libwx/libwx.ko AUTOLOAD:=$(call AutoProbe,libwx) @@ -401,7 +401,6 @@ $(eval $(call KernelPackage,libwx)) define KernelPackage/libie SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel Ethernet library - DEPENDS:=@LINUX_6_12 KCONFIG:=CONFIG_LIBIE FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie.ko AUTOLOAD:=$(call AutoLoad,15,libie,1) @@ -417,7 +416,6 @@ $(eval $(call KernelPackage,libie)) define KernelPackage/libeth SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel Ethernet common library - DEPENDS:=@LINUX_6_12 KCONFIG:=CONFIG_LIBETH FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libeth/libeth.ko AUTOLOAD:=$(call AutoLoad,15,libeth,1) @@ -428,3 +426,25 @@ endef $(eval $(call KernelPackage,libeth)) + +define KernelPackage/libie-fwlog + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=LIBIE_FWLOG + KCONFIG:=CONFIG_LIBIE_FWLOG + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie_fwlog.ko + AUTOLOAD:=$(call AutoLoad,15,libie_fwlog,1) +endef + +$(eval $(call KernelPackage,libie-fwlog)) + + +define KernelPackage/libie-adminq + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=LIBIE_ADMINQ + KCONFIG:=CONFIG_LIBIE_ADMINQ + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie_adminq.ko + AUTOLOAD:=$(call AutoLoad,15,libie_adminq,1) +endef + +$(eval $(call KernelPackage,libie-adminq)) + diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index fec20abb2..d80e69416 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -223,6 +223,18 @@ endef $(eval $(call KernelPackage,et131x)) + +define KernelPackage/phy-package + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=PHY Device support and infrastructure + KCONFIG:=CONFIG_PHY_PACKAGE + FILES:=$(LINUX_DIR)/drivers/net/phy/phy_package.ko + AUTOLOAD:=$(call AutoProbe,phy_package) +endef + +$(eval $(call KernelPackage,phy-package)) + + define KernelPackage/phy-microchip SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Microchip Ethernet PHY driver @@ -432,7 +444,7 @@ define KernelPackage/phy-micrel SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Micrel PHYs KCONFIG:=CONFIG_MICREL_PHY - DEPENDS:=+kmod-libphy +kmod-ptp + DEPENDS:=+kmod-libphy +kmod-ptp +kmod-phy-package FILES:=$(LINUX_DIR)/drivers/net/phy/micrel.ko AUTOLOAD:=$(call AutoLoad,18,micrel,1) endef @@ -513,7 +525,7 @@ $(eval $(call KernelPackage,phy-airoha-en8811h)) define KernelPackage/phy-aquantia SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Aquantia Ethernet PHYs - DEPENDS:=+kmod-libphy +kmod-hwmon-core +kmod-lib-crc-ccitt +LINUX_6_12:kmod-lib-crc-itu-t + DEPENDS:=+kmod-libphy +kmod-hwmon-core +kmod-lib-crc-ccitt +kmod-lib-crc-itu-t KCONFIG:=CONFIG_AQUANTIA_PHY FILES:=$(LINUX_DIR)/drivers/net/phy/aquantia/aquantia.ko AUTOLOAD:=$(call AutoLoad,18,aquantia,1) @@ -1079,7 +1091,7 @@ $(eval $(call KernelPackage,igbvf)) define KernelPackage/ixgbe SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) 82598/82599 PCI-Express 10 Gigabit Ethernet support - DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +kmod-mdio-devres + DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +kmod-mdio-devres +kmod-libie-fwlog +kmod-libie-adminq KCONFIG:=CONFIG_IXGBE \ CONFIG_IXGBE_VXLAN=n \ CONFIG_IXGBE_HWMON=y \ @@ -1117,7 +1129,7 @@ $(eval $(call KernelPackage,ixgbevf)) define KernelPackage/i40e SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) Ethernet Controller XL710 Family support - DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +LINUX_6_12:kmod-libie + DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +kmod-libie +kmod-libie-adminq KCONFIG:=CONFIG_I40E \ CONFIG_I40E_VXLAN=n \ CONFIG_I40E_HWMON=y \ @@ -1136,7 +1148,7 @@ $(eval $(call KernelPackage,i40e)) define KernelPackage/iavf SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) Ethernet Adaptive Virtual Function support - DEPENDS:=@PCI_SUPPORT +LINUX_6_12:kmod-libie +LINUX_6_12:kmod-libeth + DEPENDS:=@PCI_SUPPORT +kmod-libie +kmod-libeth +kmod-libie-adminq +kmod-ptp KCONFIG:= \ CONFIG_I40EVF \ CONFIG_IAVF @@ -1984,6 +1996,7 @@ $(eval $(call KernelPackage,lan743x)) define KernelPackage/amazon-ena SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Elastic Network Adapter (for Amazon AWS) + DEPENDS:=+kmod-ptp KCONFIG:=CONFIG_ENA_ETHERNET FILES:=$(LINUX_DIR)/drivers/net/ethernet/amazon/ena/ena.ko AUTOLOAD:=$(call AutoLoad,12,ena) diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index 04180e6c2..86a392b5f 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -1377,7 +1377,7 @@ $(eval $(call KernelPackage,mpls)) define KernelPackage/9pnet SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Plan 9 Resource Sharing Support (9P2000) - DEPENDS:=+LINUX_6_12:kmod-fs-netfs + DEPENDS:=+kmod-fs-netfs KCONFIG:= \ CONFIG_NET_9P \ CONFIG_NET_9P_DEBUG=n \ diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index 1ec89d257..0a4dfc4a6 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -280,9 +280,9 @@ define KernelPackage/mlxreg CONFIG_SENSORS_MLXREG_FAN \ CONFIG_LEDS_MLXREG FILES:= \ - $(LINUX_DIR)/drivers/platform/x86/mlx-platform.ko \ $(LINUX_DIR)/drivers/platform/mellanox/mlxreg-hotplug.ko \ $(LINUX_DIR)/drivers/platform/mellanox/mlxreg-io.ko \ + $(LINUX_DIR)/drivers/platform/mellanox/mlx-platform.ko \ $(LINUX_DIR)/drivers/hwmon/mlxreg-fan.ko \ $(LINUX_DIR)/drivers/leds/leds-mlxreg.ko AUTOLOAD:=$(call AutoProbe,mlx-platform mlxreg-hotplug mlxreg-io mlxreg-fan leds-mlxreg) @@ -709,7 +709,7 @@ define KernelPackage/serial-8250-exar KCONFIG:= CONFIG_SERIAL_8250_EXAR FILES:=$(LINUX_DIR)/drivers/tty/serial/8250/8250_exar.ko AUTOLOAD:=$(call AutoProbe,8250 8250_base 8250_exar) - DEPENDS:=@PCI_SUPPORT +kmod-serial-8250 + DEPENDS:=@PCI_SUPPORT +kmod-serial-8250 +kmod-eeprom-93cx6 endef define KernelPackage/serial-8250-exar/description @@ -804,8 +804,8 @@ $(eval $(call KernelPackage,ikconfig)) define KernelPackage/zram SUBMENU:=$(OTHER_MENU) TITLE:=ZRAM - DEPENDS:=+LINUX_6_12:kmod-lib-lzo +LINUX_6_12:kmod-lib-lz4 \ - +LINUX_6_12:kmod-lib-lz4hc +LINUX_6_12:kmod-lib-zstd + DEPENDS:=+kmod-lib-lzo +kmod-lib-lz4 \ + +kmod-lib-lz4hc +kmod-lib-zstd KCONFIG:= \ CONFIG_ZSMALLOC \ CONFIG_ZRAM \ diff --git a/openwrt/patch/openwrt-6.x/modules/rtc.mk b/openwrt/patch/openwrt-6.x/modules/rtc.mk index 3658e8598..d65608c17 100644 --- a/openwrt/patch/openwrt-6.x/modules/rtc.mk +++ b/openwrt/patch/openwrt-6.x/modules/rtc.mk @@ -120,7 +120,7 @@ define KernelPackage/rtc-pcf8563 SUBMENU:=$(RTC_MENU) TITLE:=Philips PCF8563/Epson RTC8564 RTC support DEFAULT:=m if ALL_KMODS && RTC_SUPPORT - DEPENDS:=+kmod-i2c-core + DEPENDS:=+kmod-i2c-core +kmod-regmap-i2c KCONFIG:=CONFIG_RTC_DRV_PCF8563 \ CONFIG_RTC_CLASS=y FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf8563.ko diff --git a/openwrt/patch/openwrt-6.x/modules/sound.mk b/openwrt/patch/openwrt-6.x/modules/sound.mk index 2a33898c8..3e043a5a6 100644 --- a/openwrt/patch/openwrt-6.x/modules/sound.mk +++ b/openwrt/patch/openwrt-6.x/modules/sound.mk @@ -370,9 +370,9 @@ define KernelPackage/sound-hda-core CONFIG_SND_HDA_PATCH_LOADER=n \ CONFIG_SND_HDA_GENERIC FILES:= \ - $(LINUX_DIR)/sound/hda/snd-hda-core.ko \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec.ko \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-generic.ko + $(LINUX_DIR)/sound/hda/core/snd-hda-core.ko \ + $(LINUX_DIR)/sound/hda/common/snd-hda-codec.ko \ + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-generic.ko AUTOLOAD:=$(call AutoProbe,snd-hda-core snd-hda-codec snd-hda-codec-generic) $(call AddDepends/sound,+kmod-regmap-core) endef @@ -387,10 +387,31 @@ define KernelPackage/sound-hda-codec-realtek SUBMENU:=$(SOUND_MENU) TITLE:= HD Audio Realtek Codec KCONFIG:= \ - CONFIG_SND_HDA_CODEC_REALTEK + CONFIG_SND_HDA_CODEC_REALTEK \ + CONFIG_SND_HDA_CODEC_REALTEK_LIB \ + CONFIG_SND_HDA_CODEC_ALC260 \ + CONFIG_SND_HDA_CODEC_ALC262 \ + CONFIG_SND_HDA_CODEC_ALC268 \ + CONFIG_SND_HDA_CODEC_ALC269 \ + CONFIG_SND_HDA_CODEC_ALC662 \ + CONFIG_SND_HDA_CODEC_ALC680 \ + CONFIG_SND_HDA_CODEC_ALC861 \ + CONFIG_SND_HDA_CODEC_ALC861VD \ + CONFIG_SND_HDA_CODEC_ALC880 \ + CONFIG_SND_HDA_CODEC_ALC882 FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-realtek.ko \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-scodec-component.ko@ge6.12 + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-realtek-lib.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc260.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc262.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc268.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc269.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc662.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc680.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc861.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc861vd.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc880.ko \ + $(LINUX_DIR)/sound/hda/codecs/realtek/snd-hda-codec-alc882.ko \ + $(LINUX_DIR)/sound/hda/codecs/side-codecs/snd-hda-scodec-component.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-realtek) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -407,7 +428,7 @@ define KernelPackage/sound-hda-codec-cmedia KCONFIG:= \ CONFIG_SND_HDA_CODEC_CMEDIA FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-cmedia.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-cmedia.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-cmedia) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -424,7 +445,7 @@ define KernelPackage/sound-hda-codec-analog KCONFIG:= \ CONFIG_SND_HDA_CODEC_ANALOG FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-analog.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-analog.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-analog) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -441,7 +462,7 @@ define KernelPackage/sound-hda-codec-idt KCONFIG:= \ CONFIG_SND_HDA_CODEC_SIGMATEL FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-idt.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-idt.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-idt) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -458,7 +479,7 @@ define KernelPackage/sound-hda-codec-si3054 KCONFIG:= \ CONFIG_SND_HDA_CODEC_SI3054 FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-si3054.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-si3054.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-si3054) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -473,9 +494,14 @@ define KernelPackage/sound-hda-codec-cirrus SUBMENU:=$(SOUND_MENU) TITLE:=HD Audio Cirrus Logic Codec KCONFIG:= \ - CONFIG_SND_HDA_CODEC_CIRRUS + CONFIG_SND_HDA_CODEC_CIRRUS \ + CONFIG_SND_HDA_CODEC_CS420X \ + CONFIG_SND_HDA_CODEC_CS421X \ + CONFIG_SND_HDA_CODEC_CS8409 FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-cirrus.ko + $(LINUX_DIR)/sound/hda/codecs/cirrus/snd-hda-codec-cs420x.ko \ + $(LINUX_DIR)/sound/hda/codecs/cirrus/snd-hda-codec-cs421x.ko \ + $(LINUX_DIR)/sound/hda/codecs/cirrus/snd-hda-codec-cs8409.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-cirrus) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -492,7 +518,7 @@ define KernelPackage/sound-hda-codec-ca0110 KCONFIG:= \ CONFIG_SND_HDA_CODEC_CA0110 FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-ca0110.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-ca0110.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-ca0110) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -510,7 +536,7 @@ define KernelPackage/sound-hda-codec-ca0132 CONFIG_SND_HDA_CODEC_CA0132 \ CONFIG_SND_HDA_CODEC_CA0132_DSP=n FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-ca0132.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-ca0132.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-ca0132) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -527,7 +553,7 @@ define KernelPackage/sound-hda-codec-conexant KCONFIG:= \ CONFIG_SND_HDA_CODEC_CONEXANT FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-conexant.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-conexant.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-conexant) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -544,7 +570,7 @@ define KernelPackage/sound-hda-codec-via KCONFIG:= \ CONFIG_SND_HDA_CODEC_VIA FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-via.ko + $(LINUX_DIR)/sound/hda/codecs/snd-hda-codec-via.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-via) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -561,7 +587,7 @@ define KernelPackage/sound-hda-codec-hdmi KCONFIG:= \ CONFIG_SND_HDA_CODEC_HDMI FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-codec-hdmi.ko + $(LINUX_DIR)/sound/hda/codecs/hdmi/snd-hda-codec-hdmi.ko AUTOLOAD:=$(call AutoProbe,snd-hda-codec-hdmi) $(call AddDepends/sound,kmod-sound-hda-core) endef @@ -580,8 +606,8 @@ define KernelPackage/sound-hda-intel CONFIG_SOUND_PCI \ CONFIG_SND_HDA_INTEL FILES:= \ - $(LINUX_DIR)/sound/pci/hda/snd-hda-intel.ko \ - $(LINUX_DIR)/sound/hda/snd-intel-dspcfg.ko + $(LINUX_DIR)/sound/hda/controllers/snd-hda-intel.ko \ + $(LINUX_DIR)/sound/hda/core/snd-intel-dspcfg.ko AUTOLOAD:=$(call AutoProbe,snd-hda-intel) $(call AddDepends/sound,kmod-sound-hda-core) endef diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index aea2228a2..92c092c1b 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -1297,7 +1297,7 @@ $(eval $(call KernelPackage,usb-net-kaweth)) define KernelPackage/usb-net-lan78xx TITLE:=USB-To-Ethernet Microchip LAN78XX convertors - DEPENDS:=+kmod-fixed-phy +kmod-phy-microchip +PACKAGE_kmod-of-mdio:kmod-of-mdio + DEPENDS:=+kmod-fixed-phy +kmod-phy-microchip +kmod-phylink +PACKAGE_kmod-of-mdio:kmod-of-mdio KCONFIG:=CONFIG_USB_LAN78XX FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/lan78xx.ko AUTOLOAD:=$(call AutoProbe,lan78xx) diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index 4ef3b1643..3a14fc08d 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -289,6 +289,17 @@ endef $(eval $(call KernelPackage,multimedia-input)) +define KernelPackage/cec-core + SUBMENU:=$(VIDEO_MENU) + TITLE:=CEC support + KCONFIG:=CONFIG_CEC_CORE + FILES:=$(LINUX_DIR)/drivers/media/cec/core/cec.ko + AUTOLOAD:=$(call AutoProbe,cec) +endef + +$(eval $(call KernelPackage,cec-core)) + + define KernelPackage/drm SUBMENU:=$(VIDEO_MENU) TITLE:=Direct Rendering Manager (DRM) support @@ -308,6 +319,17 @@ endef $(eval $(call KernelPackage,drm)) +define KernelPackage/drm-client-lib + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Direct Rendering Manager + DEPENDS:=+kmod-drm +kmod-drm-kms-helper + KCONFIG:=CONFIG_DRM_CLIENT_LIB + FILES:=$(LINUX_DIR)/drivers/gpu/drm/clients/drm_client_lib.ko + AUTOLOAD:=$(call AutoProbe,drm_client_lib) +endef + +$(eval $(call KernelPackage,drm-client-lib)) + define KernelPackage/drm-buddy SUBMENU:=$(VIDEO_MENU) TITLE:=A page based buddy allocator @@ -326,7 +348,7 @@ $(eval $(call KernelPackage,drm-buddy)) define KernelPackage/drm-display-helper SUBMENU:=$(VIDEO_MENU) TITLE:=DRM helpers for display adapters drivers - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper +kmod-cec-core KCONFIG:=CONFIG_DRM_DISPLAY_HELPER FILES:=$(LINUX_DIR)/drivers/gpu/drm/display/drm_display_helper.ko AUTOLOAD:=$(call AutoProbe,drm_display_helper) @@ -475,7 +497,8 @@ define KernelPackage/drm-amdgpu CONFIG_DEBUG_KERNEL_DC=n FILES:=$(LINUX_DIR)/drivers/gpu/drm/amd/amdgpu/amdgpu.ko \ $(LINUX_DIR)/drivers/gpu/drm/scheduler/gpu-sched.ko \ - $(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko + $(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko \ + $(LINUX_DIR)/drivers/gpu/drm/drm_panel_backlight_quirks.ko AUTOLOAD:=$(call AutoProbe,amdgpu) endef @@ -616,7 +639,7 @@ $(eval $(call KernelPackage,drm-imx-ldb)) define KernelPackage/drm-panel-mipi-dbi SUBMENU:=$(VIDEO_MENU) TITLE:=Generic MIPI DBI LCD panel - DEPENDS:=+kmod-drm-mipi-dbi +kmod-drm-dma-helper + DEPENDS:=+kmod-drm-mipi-dbi +kmod-drm-dma-helper +kmod-drm-client-lib KCONFIG:=CONFIG_DRM_PANEL_MIPI_DBI \ CONFIG_DRM_FBDEV_EMULATION=y \ CONFIG_DRM_FBDEV_OVERALLOC=100 @@ -695,7 +718,7 @@ define KernelPackage/drm-radeon TITLE:=Radeon DRM support DEPENDS:=@TARGET_x86 @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-kms-helper \ +kmod-drm-ttm +kmod-drm-ttm-helper +kmod-i2c-algo-bit +radeon-firmware \ - +kmod-drm-display-helper +kmod-acpi-video +kmod-drm-suballoc-helper + +kmod-drm-display-helper +kmod-acpi-video +kmod-drm-suballoc-helper +kmod-drm-exec KCONFIG:=CONFIG_DRM_RADEON FILES:=$(LINUX_DIR)/drivers/gpu/drm/radeon/radeon.ko AUTOLOAD:=$(call AutoProbe,radeon) diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.12 b/openwrt/patch/openwrt-6.x/x86/64/config-6.18 similarity index 100% rename from openwrt/patch/openwrt-6.x/x86/64/config-6.12 rename to openwrt/patch/openwrt-6.x/x86/64/config-6.18 diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.12 b/openwrt/patch/openwrt-6.x/x86/config-6.18 similarity index 65% rename from openwrt/patch/openwrt-6.x/x86/config-6.12 rename to openwrt/patch/openwrt-6.x/x86/config-6.18 index 28ea5b3c4..55e3b043e 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.12 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.18 @@ -1,43 +1,64 @@ # CONFIG_60XX_WDT is not set # CONFIG_64BIT is not set +CONFIG_ACPI_EC=y # CONFIG_ACPI is not set +# CONFIG_ACPI_WMI_LEGACY_DEVICE_NAMES is not set # CONFIG_ACQUIRE_WDT is not set +# CONFIG_AD3530R is not set +# CONFIG_AD4080 is not set +# CONFIG_AD4170_4 is not set +# CONFIG_ADE9000 is not set # CONFIG_ADVANTECH_EC_WDT is not set # CONFIG_ADVANTECH_WDT is not set # CONFIG_ALIM1535_WDT is not set # CONFIG_ALIX is not set +# CONFIG_AMD_3D_VCACHE is not set +# CONFIG_AMD_HFI is not set +# CONFIG_AMD_HSMP_ACPI is not set +# CONFIG_AMD_HSMP_PLAT is not set +# CONFIG_AMD_ISP_PLATFORM is not set CONFIG_AMD_NB=y +CONFIG_AMD_NODE=y # CONFIG_AMD_WBRF is not set +# CONFIG_AMD_XGBE_DCB is not set CONFIG_ARCH_32BIT_OFF_T=y CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y +CONFIG_ARCH_DEFAULT_CRASH_DUMP=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +CONFIG_ARCH_MMAP_RND_BITS=16 +CONFIG_ARCH_PKEY_BITS=4 CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SPLIT_ARG64=y CONFIG_ARCH_STACKWALK=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_USES_PG_ARCH_2=y CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y CONFIG_ARCH_WANTS_NO_INSTR=y +# CONFIG_AS21XXX_PHY is not set CONFIG_ATA_GENERIC=y CONFIG_ATA_PIIX=y CONFIG_ATA=y +# CONFIG_AUTOFDO_CLANG is not set # CONFIG_BARCO_P50_GPIO is not set # CONFIG_BASE_SMALL is not set +# CONFIG_BATTERY_CHAGALL is not set +# CONFIG_BHYVE_GUEST is not set +CONFIG_BINARY_PRINTF=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_SD=y -CONFIG_BLK_MQ_PCI=y CONFIG_BOUNCE=y CONFIG_BUFFER_HEAD=y +# CONFIG_CHARGER_MAX8971 is not set CONFIG_CLKBLD_I8253=y CONFIG_CLKEVT_I8253=y CONFIG_CLKSRC_I8253=y -CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100 CONFIG_CLOCKSOURCE_WATCHDOG=y CONFIG_CLONE_BACKWARDS=y @@ -47,8 +68,7 @@ CONFIG_COMPAT_32BIT_TIME=y CONFIG_COMPAT_32=y # CONFIG_COMPAT_VDSO is not set CONFIG_CONSOLE_TRANSLATIONS=y -# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set -# CONFIG_CPU5_WDT is not set +CONFIG_CPUFREQ_ARCH_CUR_FREQ=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set CONFIG_CPU_FREQ_GOV_ATTR_SET=y @@ -60,7 +80,6 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_USERSPACE is not set CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ=y -CONFIG_CPU_IDLE_GOV_HALTPOLL=y CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPU_IDLE_GOV_MENU=y CONFIG_CPU_IDLE_GOV_TEO=y @@ -75,19 +94,23 @@ CONFIG_CPU_SUP_TRANSMETA_32=y CONFIG_CPU_SUP_UMC_32=y CONFIG_CPU_SUP_VORTEX_32=y CONFIG_CPU_SUP_ZHAOXIN=y -CONFIG_CRASH_CORE=y -# CONFIG_CRASH_HOTPLUG is not set CONFIG_CRC16=y +# CONFIG_CRYPTO_BENCHMARK is not set CONFIG_CRYPTO_CRC32C=y -# CONFIG_CRYPTO_CRC32_PCLMUL is not set CONFIG_CRYPTO_CRC32=y -CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +# CONFIG_CRYPTO_DEV_QAT_6XXX is not set +CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_LIB_GF128MUL=y CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1 -CONFIG_CRYPTO_LIB_SHA1=y +CONFIG_CRYPTO_LIB_SHA256=y CONFIG_CRYPTO_LIB_UTILS=y +CONFIG_CRYPTO_RNG2=y +# CONFIG_CRYPTO_SELFTESTS is not set # CONFIG_CRYPTO_SERPENT_SSE2_586 is not set +CONFIG_CRYPTO_SIG2=y # CONFIG_CX_ECAT is not set +# CONFIG_D3323AA is not set +# CONFIG_DASHARO_ACPI is not set CONFIG_DCACHE_WORD_ACCESS=y # CONFIG_DEBUG_BOOT_PARAMS is not set # CONFIG_DEBUG_ENTRY is not set @@ -99,6 +122,7 @@ CONFIG_DEBUG_MISC=y # CONFIG_DEBUG_TLBFLUSH is not set CONFIG_DECOMPRESS_BZIP2=y CONFIG_DECOMPRESS_GZIP=y +CONFIG_DIMLIB=y CONFIG_DMADEVICES=y CONFIG_DMIID=y CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y @@ -106,9 +130,11 @@ CONFIG_DMI_SYSFS=y CONFIG_DMI=y CONFIG_DNOTIFY=y # CONFIG_DRM_AMD_ISP is not set +# CONFIG_DRM_EFIDRM is not set # CONFIG_DRM_I915_DEBUG_WAKEREF is not set # CONFIG_DRM_I915_GVT_KVMGT is not set # CONFIG_DRM_I915_REPLAY_GPU_HANGS_API is not set +# CONFIG_DRM_VESADRM is not set CONFIG_DUMMY_CONSOLE=y CONFIG_DYNAMIC_SIGFRAME=y # CONFIG_EARLY_PRINTK_DBGP is not set @@ -116,44 +142,50 @@ CONFIG_EARLY_PRINTK=y CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y # CONFIG_EDD is not set +CONFIG_EFI_SBAT_FILE="" # CONFIG_EISA is not set # CONFIG_EUROTECH_WDT is not set # CONFIG_EXAR_WDT is not set CONFIG_EXCLUSIVE_SYSTEM_RAM=y +CONFIG_EXECMEM=y CONFIG_EXT4_FS=y CONFIG_F2FS_FS=y # CONFIG_F71808E_WDT is not set CONFIG_FIRMWARE_MEMMAP=y CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FORCE_NR_CPUS=y CONFIG_FRAME_POINTER=y CONFIG_FS_IOMAP=y CONFIG_FS_MBCACHE=y -CONFIG_FUNCTION_ALIGNMENT=16 -CONFIG_FUNCTION_ALIGNMENT_16B=y -CONFIG_FUNCTION_PADDING_BYTES=16 -CONFIG_FUNCTION_PADDING_CFI=11 -# CONFIG_FUN_ETH is not set +CONFIG_FS_STACK=y +CONFIG_FUNCTION_ALIGNMENT=4 +CONFIG_FUNCTION_ALIGNMENT_4B=y +CONFIG_FUNCTION_PADDING_BYTES=4 +CONFIG_FUNCTION_PADDING_CFI=0 # CONFIG_FUSION_CTL is not set # CONFIG_FUSION_LOGGING is not set CONFIG_FUSION_MAX_SGE=128 CONFIG_FUSION_SPI=y CONFIG_FUSION=y +CONFIG_FUTEX_PRIVATE_HASH=y CONFIG_FW_LOADER_PAGED_BUF=y CONFIG_FW_LOADER_SYSFS=y -CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y -# CONFIG_GDS_FORCE_MITIGATION is not set +CONFIG_GCC_NO_STRINGOP_OVERFLOW=y CONFIG_GENERIC_ALLOCATOR=y CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_DEVICES=y CONFIG_GENERIC_CPU_VULNERABILITIES=y CONFIG_GENERIC_EARLY_IOREMAP=y CONFIG_GENERIC_ENTRY=y CONFIG_GENERIC_GETTIMEOFDAY=y CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_ENTRY=y CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y CONFIG_GENERIC_IRQ_RESERVATION_MODE=y CONFIG_GENERIC_IRQ_SHOW=y @@ -163,37 +195,35 @@ CONFIG_GENERIC_PCI_IOMAP=y CONFIG_GENERIC_SMP_IDLE_THREAD=y CONFIG_GENERIC_STRNCPY_FROM_USER=y CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_SYSCALL=y CONFIG_GENERIC_TIME_VSYSCALL=y -CONFIG_GENERIC_VDSO_32=y +CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT=y # CONFIG_GEOS is not set CONFIG_GLOB=y -CONFIG_GPIO_CDEV=y -# CONFIG_GPIO_DS4520 is not set # CONFIG_GPIO_ELKHARTLAKE is not set -# CONFIG_GPIO_SIM is not set +CONFIG_GPIOLIB_LEGACY=y # CONFIG_GPIO_VIRTIO is not set # CONFIG_HANGCHECK_TIMER is not set -# CONFIG_HARDENED_USERCOPY is not set CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_LTO_CLANG=y CONFIG_HID_SUPPORT=y CONFIG_HID=y CONFIG_HIGHMEM4G=y -# CONFIG_HIGHMEM64G is not set CONFIG_HIGHMEM=y -CONFIG_HIGHPTE=y +# CONFIG_HINIC3 is not set CONFIG_HPET_EMULATE_RTC=y CONFIG_HPET_TIMER=y -# CONFIG_HP_WATCHDOG is not set -CONFIG_HW_CONSOLE=y CONFIG_HW_RANDOM_GEODE=y CONFIG_HW_RANDOM_VIA=y CONFIG_HW_RANDOM=y # CONFIG_HYPERVISOR_GUEST is not set +CONFIG_HYPERV_VMBUS=y CONFIG_HZ_PERIODIC=y +# CONFIG_I2C_AMD_ASF is not set CONFIG_I8253_LOCK=y CONFIG_IA32_FEAT_CTL=y # CONFIG_IB700_WDT is not set @@ -201,6 +231,7 @@ CONFIG_IA32_FEAT_CTL=y # CONFIG_IBM_RTL is not set # CONFIG_IE6XX_WDT is not set CONFIG_ILLEGAL_POINTER_VALUE=0 +# CONFIG_INFINEON_TLV493D is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_INPUT_KEYBOARD=y CONFIG_INPUT_VIVALDIFMAP=y @@ -209,20 +240,26 @@ CONFIG_INPUT=y CONFIG_INSTRUCTION_DECODER=y # CONFIG_INTEL_HFI_THERMAL is not set # CONFIG_INTEL_LDMA is not set +# CONFIG_INTEL_OC_WATCHDOG is not set # CONFIG_INTEL_PCH_THERMAL is not set # CONFIG_INTEL_POWERCLAMP is not set # CONFIG_INTEL_SCU_PCI is not set -# CONFIG_INTEL_TCC_COOLING is not set +# CONFIG_INTEL_THC_HID is not set # CONFIG_INTEL_VSEC is not set CONFIG_IO_DELAY_0X80=y # CONFIG_IO_DELAY_0XED is not set # CONFIG_IO_DELAY_NONE is not set # CONFIG_IO_DELAY_UDELAY is not set # CONFIG_IOSF_MBI is not set +# CONFIG_IR_ENE is not set +# CONFIG_IR_FINTEK is not set +# CONFIG_IR_ITE_CIR is not set +# CONFIG_IR_NUVOTON is not set CONFIG_IRQ_DOMAIN_HIERARCHY=y CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_WORK=y +# CONFIG_IR_WINBOND_CIR is not set CONFIG_ISA_DMA_API=y # CONFIG_ISA is not set # CONFIG_IT8712F_WDT is not set @@ -231,12 +268,19 @@ CONFIG_ISA_DMA_API=y CONFIG_JBD2=y CONFIG_KALLSYMS=y CONFIG_KEXEC_CORE=y +# CONFIG_KEXEC_HANDOVER is not set CONFIG_KEXEC=y CONFIG_KEYBOARD_ATKBD=y CONFIG_KMAP_LOCAL=y -# CONFIG_KVM_PROVE_MMU is not set -# CONFIG_LEGACY_PTYS is not set +CONFIG_KVM_HYPERV=y +CONFIG_KVM_IOAPIC=y +# CONFIG_LENOVO_SE30_WDT is not set +# CONFIG_LENOVO_WMI_GAMEZONE is not set +# CONFIG_LENOVO_WMI_HOTKEY_UTILITIES is not set +# CONFIG_LENOVO_WMI_TUNING is not set CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_MM_AND_FIND_VMA=y +CONFIG_LRU_GEN_WALKS_MMU=y # CONFIG_M486 is not set # CONFIG_M486SX is not set # CONFIG_M586 is not set @@ -245,31 +289,46 @@ CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_M686=y # CONFIG_MACHZ_WDT is not set # CONFIG_MATOM is not set -# CONFIG_MCORE2 is not set +# CONFIG_MAXLINEAR_86110_PHY is not set # CONFIG_MCRUSOE is not set # CONFIG_MCYRIXIII is not set +# CONFIG_MDIO_BUS is not set # CONFIG_MEEGOPAD_ANX7428 is not set # CONFIG_MEFFICEON is not set # CONFIG_MELAN is not set +CONFIG_MEMFD_CREATE=y +# CONFIG_MFD_CGBC is not set # CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_UPBOARD_FPGA is not set # CONFIG_MGEODEGX1 is not set # CONFIG_MGEODE_LX is not set -# CONFIG_MICROCODE_LATE_FORCE_MINREV is not set -CONFIG_MICROCODE_LATE_LOADING=y +# CONFIG_MICROCODE_DBG is not set +CONFIG_MICROCODE_INITRD32=y +# CONFIG_MICROCODE_LATE_LOADING is not set CONFIG_MICROCODE=y CONFIG_MIGRATION=y -CONFIG_MITIGATION_ITS=y -# CONFIG_MITIGATION_GDS_FORCE is not set -# CONFIG_MITIGATION_IBPB_ENTRY is not set -# CONFIG_MITIGATION_IBRS_ENTRY is not set -# CONFIG_MITIGATION_PAGE_TABLE_ISOLATION is not set +CONFIG_MITIGATION_GDS=y +CONFIG_MITIGATION_IBPB_ENTRY=y +CONFIG_MITIGATION_IBRS_ENTRY=y +CONFIG_MITIGATION_L1TF=y +CONFIG_MITIGATION_MDS=y +CONFIG_MITIGATION_MMIO_STALE_DATA=y +CONFIG_MITIGATION_PAGE_TABLE_ISOLATION=y +CONFIG_MITIGATION_RETBLEED=y # CONFIG_MITIGATION_RETPOLINE is not set CONFIG_MITIGATION_RFDS=y # CONFIG_MITIGATION_SLS is not set CONFIG_MITIGATION_SPECTRE_BHI=y +CONFIG_MITIGATION_SPECTRE_V1=y +CONFIG_MITIGATION_SPECTRE_V2=y +CONFIG_MITIGATION_SRBDS=y +CONFIG_MITIGATION_SSB=y +CONFIG_MITIGATION_TAA=y +CONFIG_MITIGATION_TSA=y +CONFIG_MITIGATION_VMSCAPE=y # CONFIG_MK6 is not set # CONFIG_MK7 is not set -# CONFIG_MK8 is not set +# CONFIG_MLXREG_DPU is not set CONFIG_MMU_GATHER_MERGE_VMAS=y CONFIG_MMU_LAZY_TLB_REFCOUNT=y # CONFIG_MODIFY_LDT_SYSCALL is not set @@ -279,6 +338,10 @@ CONFIG_MODULES_USE_ELF_REL=y # CONFIG_MPENTIUMIII is not set # CONFIG_MPENTIUMII is not set # CONFIG_MPENTIUMM is not set +# CONFIG_MSHV_ROOT is not set +# CONFIG_MTD_INTEL_DG is not set +# CONFIG_MTD_SBC_GXX is not set +# CONFIG_MTD_SCx200_DOCFLASH is not set # CONFIG_MTRR_SANITIZER is not set CONFIG_MTRR=y # CONFIG_MVIAC3_2 is not set @@ -286,11 +349,13 @@ CONFIG_MTRR=y # CONFIG_MWINCHIP3D is not set # CONFIG_MWINCHIPC6 is not set CONFIG_NAMESPACES=y +# CONFIG_NCT7201 is not set CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y CONFIG_NEED_PER_CPU_KM=y CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_NEED_SG_DMA_LENGTH=y # CONFIG_NET5501 is not set +# CONFIG_NET_DSA_REALTEK is not set CONFIG_NET_EGRESS=y CONFIG_NET_INGRESS=y # CONFIG_NET_NS is not set @@ -298,9 +363,6 @@ CONFIG_NET_INGRESS=y CONFIG_NET_XGRESS=y CONFIG_NLS=y # CONFIG_NMI_CHECK_CPU is not set -# CONFIG_NOHIGHMEM is not set -CONFIG_NO_HZ_COMMON=y -CONFIG_NO_HZ_FULL=y CONFIG_NO_HZ=y CONFIG_NR_CPUS=1 CONFIG_NR_CPUS_DEFAULT=1 @@ -309,21 +371,26 @@ CONFIG_NR_CPUS_RANGE_END=1 # CONFIG_NSC_GPIO is not set # CONFIG_NSM is not set CONFIG_NVRAM=y -# CONFIG_OCTEON_EP is not set +# CONFIG_OBJTOOL_WERROR is not set # CONFIG_OF is not set CONFIG_OLD_SIGACTION=y CONFIG_OLD_SIGSUSPEND3=y # CONFIG_OLPC is not set CONFIG_OUTPUT_FORMAT="elf32-i386" +# CONFIG_OVMF_DEBUG_LOG is not set +# CONFIG_OVPN is not set +# CONFIG_OXP_EC is not set +CONFIG_PAGE_MAPCOUNT=y CONFIG_PAGE_OFFSET=0xC0000000 CONFIG_PAGE_POOL=y +CONFIG_PAGE_SHIFT=12 CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +CONFIG_PAHOLE_HAS_BTF_TAG=y CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y CONFIG_PC104=y # CONFIG_PC8736x_GPIO is not set # CONFIG_PC87413_WDT is not set -# CONFIG_PCENGINES_APU2 is not set CONFIG_PCI_ATS=y CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y @@ -351,27 +418,36 @@ CONFIG_PHYSICAL_START=0x1000000 # CONFIG_PINCTRL_INTEL_PLATFORM is not set # CONFIG_PINCTRL_METEORPOINT is not set # CONFIG_PM_USERSPACE_AUTOSLEEP is not set +CONFIG_PM_USERSPACE_AUTOSLEEP is not set +# CONFIG_PORTWELL_EC is not set CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y CONFIG_POWER_SUPPLY=y +# CONFIG_PREEMPT_LAZY is not set CONFIG_PREEMPT_NONE_BUILD=y # CONFIG_PROCESSOR_SELECT is not set +# CONFIG_PROC_MEM_FORCE_PTRACE is not set +# CONFIG_PROC_MEM_NO_FORCE is not set CONFIG_PROC_PAGE_MONITOR=y CONFIG_PROC_PID_ARCH_STATUS=y +# CONFIG_PROPELLER_CLANG is not set # CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set CONFIG_PTP_1588_CLOCK_OPTIONAL=y +CONFIG_PTP_1588_CLOCK_VMCLOCK=y +CONFIG_PT_RECLAIM=y # CONFIG_PUNIT_ATOM_DEBUG is not set -# CONFIG_RANDOM_KMALLOC_CACHES is not set +# CONFIG_RANDSTRUCT_FULL is not set CONFIG_RANDSTRUCT_NONE=y CONFIG_RATIONAL=y -# CONFIG_RCU_LAZY_DEFAULT_OFF is not set -CONFIG_RCU_LAZY=y -# CONFIG_RCU_NOCB_CPU_DEFAULT_ALL is not set CONFIG_RD_BZIP2=y CONFIG_RD_GZIP=y -CONFIG_RETHUNK=y -CONFIG_RETPOLINE=y +# CONFIG_REDMI_WMI is not set +# CONFIG_ROHM_BD79112 is not set +# CONFIG_ROHM_BD79124 is not set CONFIG_RTC_CLASS=y CONFIG_RTC_MC146818_LIB=y +CONFIG_RUSTC_LLVM_VERSION=170004 +CONFIG_RUSTC_VERSION=107400 +# CONFIG_SAMSUNG_GALAXYBOOK is not set CONFIG_SATA_HOST=y # CONFIG_SBC7240_WDT is not set # CONFIG_SBC8360_WDT is not set @@ -384,25 +460,58 @@ CONFIG_SCSI=y CONFIG_SCx200HR_TIMER=y # CONFIG_SCx200_WDT is not set CONFIG_SCx200=y +# CONFIG_SEN0322 is not set +# CONFIG_SENSORS_GPD is not set +# CONFIG_SERIAL_8250_NI is not set CONFIG_SERIAL_8250_PCILIB=y CONFIG_SERIAL_8250_PCI=y # CONFIG_SERIAL_LANTIQ is not set -CONFIG_SERIAL_MCTRL_GPIO=y CONFIG_SERIO_I8042=y CONFIG_SERIO_LIBPS2=y CONFIG_SERIO_SERPORT=y CONFIG_SERIO=y -# CONFIG_SFC_SIENA is not set +CONFIG_SGL_ALLOC=y CONFIG_SG_POOL=y # CONFIG_SIEMENS_SIMATIC_IPC is not set # CONFIG_SILICOM_PLATFORM is not set -# CONFIG_SLAB_BUCKETS is not set +CONFIG_SLUB=y # CONFIG_SMSC37B787_WDT is not set # CONFIG_SMSC_SCH311X_WDT is not set +# CONFIG_SND_HDA_ACPI is not set +# CONFIG_SND_HDA_CODEC_ALC260 is not set +# CONFIG_SND_HDA_CODEC_ALC262 is not set +# CONFIG_SND_HDA_CODEC_ALC268 is not set +# CONFIG_SND_HDA_CODEC_ALC269 is not set +# CONFIG_SND_HDA_CODEC_ALC662 is not set +# CONFIG_SND_HDA_CODEC_ALC680 is not set +# CONFIG_SND_HDA_CODEC_ALC861 is not set +# CONFIG_SND_HDA_CODEC_ALC861VD is not set +# CONFIG_SND_HDA_CODEC_ALC880 is not set +# CONFIG_SND_HDA_CODEC_ALC882 is not set +# CONFIG_SND_HDA_CODEC_CM9825 is not set +# CONFIG_SND_HDA_CODEC_CS420X is not set +# CONFIG_SND_HDA_CODEC_CS421X is not set +# CONFIG_SND_HDA_CODEC_CS8409 is not set +# CONFIG_SND_HDA_CODEC_HDMI_ATI is not set +CONFIG_SND_HDA_CODEC_HDMI_GENERIC=m +# CONFIG_SND_HDA_CODEC_HDMI_INTEL is not set +# CONFIG_SND_HDA_CODEC_HDMI_NVIDIA is not set +# CONFIG_SND_HDA_CODEC_HDMI_NVIDIA_MCP is not set +CONFIG_SND_HDA_CODEC_HDMI_SIMPLE=m +# CONFIG_SND_HDA_CODEC_HDMI_TEGRA is not set +# CONFIG_SND_HDA_CODEC_SENARYTECH is not set +# CONFIG_SND_HDA_SCODEC_TAS2781_SPI is not set +# CONFIG_SND_SOC_AMD_ACP5x is not set +# CONFIG_SND_USB_US144MKII is not set +# CONFIG_SND_VIRTIO is not set CONFIG_SOFTIRQ_ON_OWN_STACK=y CONFIG_SPARSE_IRQ=y CONFIG_SPARSEMEM_STATIC=y -CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SPI_INTEL_PCI is not set +# CONFIG_SPI_INTEL_PLATFORM is not set +# CONFIG_SPI_VIRTIO is not set +# CONFIG_SQUASHFS_COMP_CACHE_FULL is not set +CONFIG_SQUASHFS_DECOMP_SINGLE=y # CONFIG_STATIC_CALL_SELFTEST is not set # CONFIG_STRICT_SIGALTSTACK_SIZE is not set CONFIG_SYSCTL_EXCEPTION_TRACE=y @@ -411,24 +520,28 @@ CONFIG_SYSCTL_EXCEPTION_TRACE=y # CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set # CONFIG_TEST_DHRY is not set # CONFIG_TEST_FPU is not set +# CONFIG_TEST_KALLSYMS is not set # CONFIG_TEST_MAPLE_TREE is not set -# CONFIG_TEST_OBJPOOL is not set CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 CONFIG_THERMAL_GOV_STEP_WISE=y CONFIG_THERMAL=y CONFIG_THREAD_INFO_IN_TASK=y CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_TI_FPC202 is not set CONFIG_TINY_SRCU=y -# CONFIG_TMPFS_QUOTA is not set CONFIG_TOOLS_SUPPORT_RELR=y # CONFIG_TOSHIBA is not set # CONFIG_TQMX86_WDT is not set CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +# CONFIG_TUXEDO_NB04_WMI_AB is not set CONFIG_UNWINDER_FRAME_POINTER=y # CONFIG_UNWINDER_GUESS is not set CONFIG_UP_LATE_INIT=y +# CONFIG_USB_CDNS3_PCI_WRAP is not set +# CONFIG_USB_CDNSP_PCI is not set CONFIG_USB_COMMON=y +CONFIG_USB_DEFAULT_AUTHORIZATION_MODE=1 # CONFIG_USB_EHCI_HCD_PLATFORM is not set CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_PCI=y @@ -441,6 +554,7 @@ CONFIG_USB_OHCI_HCD=y CONFIG_USB_PCI=y CONFIG_USB_SUPPORT=y CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_USBIO is not set # CONFIG_USB_XEN_HCD is not set CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_PCI=y @@ -448,8 +562,13 @@ CONFIG_USB_XHCI_PCI=y CONFIG_USB=y # CONFIG_USER_NS is not set CONFIG_USER_STACKTRACE_SUPPORT=y +# CONFIG_VEML6046X00 is not set CONFIG_VGA_CONSOLE=y # CONFIG_VIA_WDT is not set +# CONFIG_VIDEO_COBALT is not set +# CONFIG_VIDEO_INTEL_IPU6 is not set +# CONFIG_VIDEO_LT6911UXE is not set +# CONFIG_VIRTIO_RTC is not set CONFIG_VM_EVENT_COUNTERS=y CONFIG_VT_CONSOLE=y CONFIG_VT_HW_CONSOLE_BINDING=y @@ -459,20 +578,41 @@ CONFIG_VT=y # CONFIG_X86_32_IRIS is not set CONFIG_X86_32=y # CONFIG_X86_ANCIENT_MCE is not set +CONFIG_X86_BUS_LOCK_DETECT=y # CONFIG_X86_CHECK_BIOS_CORRUPTION is not set CONFIG_X86_CMOV=y -CONFIG_X86_CMPXCHG64=y # CONFIG_X86_CPA_STATISTICS is not set # CONFIG_X86_CPUFREQ_NFORCE2 is not set # CONFIG_X86_CPUID is not set # CONFIG_X86_CPU_RESCTRL is not set +CONFIG_X86_CX8=y CONFIG_X86_DEBUGCTLMSR=y # CONFIG_X86_DEBUG_FPU is not set # CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_X86_DISABLED_FEATURE_CALL_DEPTH=y +CONFIG_X86_DISABLED_FEATURE_ENQCMD=y +CONFIG_X86_DISABLED_FEATURE_FRED=y +CONFIG_X86_DISABLED_FEATURE_IBT=y +CONFIG_X86_DISABLED_FEATURE_INVLPGB=y +CONFIG_X86_DISABLED_FEATURE_LAM=y +CONFIG_X86_DISABLED_FEATURE_OSPKE=y +CONFIG_X86_DISABLED_FEATURE_PCID=y +CONFIG_X86_DISABLED_FEATURE_PKU=y +CONFIG_X86_DISABLED_FEATURE_PTI=y +CONFIG_X86_DISABLED_FEATURE_RETHUNK=y +CONFIG_X86_DISABLED_FEATURE_RETPOLINE_LFENCE=y +CONFIG_X86_DISABLED_FEATURE_RETPOLINE=y +CONFIG_X86_DISABLED_FEATURE_SEV_SNP=y +CONFIG_X86_DISABLED_FEATURE_SGX=y +CONFIG_X86_DISABLED_FEATURE_TDX_GUEST=y +CONFIG_X86_DISABLED_FEATURE_UNRET=y +CONFIG_X86_DISABLED_FEATURE_USER_SHSTK=y +CONFIG_X86_DISABLED_FEATURE_XENPV=y # CONFIG_X86_EXTENDED_PLATFORM is not set -# CONFIG_X86_FRED is not set +CONFIG_X86_FRED=y CONFIG_X86_GENERIC=y # CONFIG_X86_GX_SUSPMOD is not set +CONFIG_X86_HAVE_PAE=y # CONFIG_X86_INTEL_PSTATE is not set # CONFIG_X86_INTEL_TSX_MODE_AUTO is not set CONFIG_X86_INTEL_TSX_MODE_OFF=y @@ -494,7 +634,9 @@ CONFIG_X86_MCE=y CONFIG_X86_MINIMUM_CPU_FAMILY=6 CONFIG_X86_MPPARSE=y CONFIG_X86_MSR=y +# CONFIG_X86_NATIVE_CPU is not set # CONFIG_X86_P4_CLOCKMOD is not set +# CONFIG_X86_PAE is not set CONFIG_X86_PAT=y CONFIG_X86_PLATFORM_DEVICES=y # CONFIG_X86_PLATFORM_DRIVERS_DELL is not set @@ -502,6 +644,11 @@ CONFIG_X86_PLATFORM_DEVICES=y # CONFIG_X86_POWERNOW_K6 is not set # CONFIG_X86_POWERNOW_K7 is not set # CONFIG_X86_REBOOTFIXUPS is not set +CONFIG_X86_REQUIRED_FEATURE_ALWAYS=y +CONFIG_X86_REQUIRED_FEATURE_CMOV=y +CONFIG_X86_REQUIRED_FEATURE_CX8=y +CONFIG_X86_REQUIRED_FEATURE_FPU=y +CONFIG_X86_REQUIRED_FEATURE_UP=y CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y # CONFIG_X86_SPEEDSTEP_CENTRINO is not set # CONFIG_X86_SPEEDSTEP_ICH is not set @@ -517,6 +664,9 @@ CONFIG_X86_VERBOSE_BOOTUP=y CONFIG_X86_VMX_FEATURE_NAMES=y CONFIG_X86=y # CONFIG_XEN_PRIVCMD_EVENTFD is not set +CONFIG_XXHASH=y CONFIG_XZ_DEC_BCJ=y CONFIG_XZ_DEC_X86=y CONFIG_ZLIB_INFLATE=y +CONFIG_ZSTD_COMMON=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.18/100-fix_cs5535_clockevt.patch similarity index 85% rename from openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch rename to openwrt/patch/openwrt-6.x/x86/patches-6.18/100-fix_cs5535_clockevt.patch index d4de2027b..65c36ccc8 100644 --- a/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch +++ b/openwrt/patch/openwrt-6.x/x86/patches-6.18/100-fix_cs5535_clockevt.patch @@ -1,6 +1,6 @@ --- a/drivers/clocksource/timer-cs5535.c +++ b/drivers/clocksource/timer-cs5535.c -@@ -127,7 +127,9 @@ static irqreturn_t mfgpt_tick(int irq, v +@@ -128,7 +128,9 @@ static irqreturn_t mfgpt_tick(int irq, v cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); diff --git a/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch b/openwrt/patch/openwrt-6.x/x86/patches-6.18/103-pcengines_apu6_platform.patch similarity index 95% rename from openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch rename to openwrt/patch/openwrt-6.x/x86/patches-6.18/103-pcengines_apu6_platform.patch index 4e1761b56..145752e7d 100644 --- a/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch +++ b/openwrt/patch/openwrt-6.x/x86/patches-6.18/103-pcengines_apu6_platform.patch @@ -63,7 +63,7 @@ Sighed-off-by: Philip Prindeville --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig -@@ -753,7 +753,7 @@ config XO1_RFKILL +@@ -572,7 +572,7 @@ config XO1_RFKILL laptop. config PCENGINES_APU2 @@ -72,7 +72,7 @@ Sighed-off-by: Philip Prindeville depends on INPUT && INPUT_KEYBOARD && GPIOLIB depends on LEDS_CLASS select GPIO_AMD_FCH -@@ -761,7 +761,7 @@ config PCENGINES_APU2 +@@ -580,7 +580,7 @@ config PCENGINES_APU2 select LEDS_GPIO help This driver provides support for the front button and LEDs on @@ -159,9 +159,9 @@ Sighed-off-by: Philip Prindeville +#define APU5_GPIO_LINE_SIMSWAP1 7 +#define APU5_GPIO_LINE_SIMSWAP2 8 +#define APU5_GPIO_LINE_SIMSWAP3 9 -+ -/* GPIO device */ ++ +/* GPIO device - APU2/3/4/6 */ static int apu2_gpio_regs[] = { @@ -189,8 +189,8 @@ Sighed-off-by: Philip Prindeville }; static const struct amd_fch_gpio_pdata board_apu2 = { -@@ -72,6 +106,40 @@ static const struct amd_fch_gpio_pdata b - .gpio_names = apu2_gpio_names, +@@ -76,6 +110,40 @@ static const struct software_node apu2_g + .name = AMD_FCH_GPIO_DRIVER_NAME, }; +/* GPIO device - APU5 */ @@ -228,9 +228,9 @@ Sighed-off-by: Philip Prindeville +}; + /* GPIO LEDs device */ - - static const struct gpio_led apu2_leds[] = { -@@ -215,6 +283,24 @@ static const struct dmi_system_id apu_gp + static const struct software_node apu2_leds_node = { + .name = "apu2-leds", +@@ -246,6 +314,24 @@ static const struct dmi_system_id apu_gp }, .driver_data = (void *)&board_apu2, }, @@ -255,7 +255,7 @@ Sighed-off-by: Philip Prindeville {} }; -@@ -249,7 +335,7 @@ static int __init apu_board_init(void) +@@ -283,7 +369,7 @@ static int __init apu_board_init(void) id = dmi_first_match(apu_gpio_dmi_table); if (!id) { @@ -264,7 +264,7 @@ Sighed-off-by: Philip Prindeville return -ENODEV; } -@@ -288,7 +374,7 @@ module_init(apu_board_init); +@@ -332,7 +418,7 @@ module_init(apu_board_init); module_exit(apu_board_exit); MODULE_AUTHOR("Enrico Weigelt, metux IT consult "); diff --git a/openwrt/patch/packages-patches/bpf-headers/900-fix-build.patch b/openwrt/patch/packages-patches/bpf-headers/900-fix-build.patch new file mode 100644 index 000000000..c15ebbfe7 --- /dev/null +++ b/openwrt/patch/packages-patches/bpf-headers/900-fix-build.patch @@ -0,0 +1,22 @@ +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -49,9 +49,6 @@ + #include + #include + #include +-#ifndef COMPILE_OFFSETS +-#include +-#endif + + /* task_struct member predeclarations (sorted alphabetically): */ + struct audit_context; +@@ -2334,6 +2331,9 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); + * + * So use arch_raw_cpu_ptr()/PERCPU_PTR() directly here. + */ ++#ifndef RQ_nr_pinned ++#define RQ_nr_pinned 0 ++#endif + #ifdef CONFIG_SMP + #define this_rq_raw() arch_raw_cpu_ptr(&runqueues) + #else diff --git a/openwrt/patch/packages-patches/cryptodev-linux/6.18/900-fix-linux-6.18.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.18/900-fix-linux-6.18.patch new file mode 100644 index 000000000..51570bf77 --- /dev/null +++ b/openwrt/patch/packages-patches/cryptodev-linux/6.18/900-fix-linux-6.18.patch @@ -0,0 +1,24 @@ +diff --git a/util.c b/util.c +index 9eba483..98be8b3 100644 +--- a/util.c ++++ b/util.c +@@ -21,6 +21,7 @@ + + #include + #include ++#include + #include "util.h" + + /* These were taken from Maxim Levitsky's patch to lkml. +@@ -45,7 +46,11 @@ struct scatterlist *sg_advance(struct scatterlist *sg, int consumed) + + if (sg->offset >= PAGE_SIZE) { + struct page *page = ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 18, 0) ++ page = sg_page(sg) + (sg->offset / PAGE_SIZE); ++#else + nth_page(sg_page(sg), sg->offset / PAGE_SIZE); ++#endif + sg_set_page(sg, page, sg->length, sg->offset % PAGE_SIZE); + } + diff --git a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch index a48fed524..620905e3c 100644 --- a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch +++ b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch @@ -1,7 +1,16 @@ diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -index 52346c2..75f6155 100644 +index 9876dee..87828e0 100644 --- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +@@ -522,7 +522,7 @@ static int gpio_keys_button_probe(struct platform_device *pdev, + /* or the legacy (button->gpio is good) way? */ + error = devm_gpio_request_one(dev, + button->gpio, GPIOF_IN | ( +- button->active_low ? GPIOF_ACTIVE_LOW : ++ button->active_low ? GPIOD_OUT_LOW : + 0), desc); + if (error) { + dev_err_probe(dev, error, @@ -674,7 +674,11 @@ static void gpio_keys_irq_close(struct gpio_keys_button_dev *bdev) } } diff --git a/openwrt/patch/packages-patches/gpio-nct5104d/fix-linux-6.18.patch b/openwrt/patch/packages-patches/gpio-nct5104d/fix-linux-6.18.patch new file mode 100644 index 000000000..892142ebd --- /dev/null +++ b/openwrt/patch/packages-patches/gpio-nct5104d/fix-linux-6.18.patch @@ -0,0 +1,40 @@ +diff --git a/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c b/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c +index ffeab29..50817f3 100644 +--- a/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c ++++ b/package/kernel/gpio-nct5104d/src/gpio-nct5104d.c +@@ -124,7 +124,7 @@ static int nct5104d_gpio_direction_in(struct gpio_chip *chip, unsigned offset); + static int nct5104d_gpio_get(struct gpio_chip *chip, unsigned offset); + static int nct5104d_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value); +-static void nct5104d_gpio_set(struct gpio_chip *chip, unsigned offset, int value); ++static int nct5104d_gpio_set(struct gpio_chip *chip, unsigned offset, int value); + + #define NCT5104D_GPIO_BANK(_base, _ngpio, _regbase) \ + { \ +@@ -219,7 +219,7 @@ static int nct5104d_gpio_direction_out(struct gpio_chip *chip, + return 0; + } + +-static void nct5104d_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ++static int nct5104d_gpio_set(struct gpio_chip *chip, unsigned offset, int value) + { + int err; + struct nct5104d_gpio_bank *bank = gpiochip_get_data(chip); +@@ -228,7 +228,7 @@ static void nct5104d_gpio_set(struct gpio_chip *chip, unsigned offset, int value + + err = superio_enter(sio->addr); + if (err) +- return; ++ return err; + superio_select(sio->addr, SIO_LD_GPIO); + + data_out = superio_inb(sio->addr, gpio_data(bank->regbase)); +@@ -239,6 +239,8 @@ static void nct5104d_gpio_set(struct gpio_chip *chip, unsigned offset, int value + superio_outb(sio->addr, gpio_data(bank->regbase), data_out); + + superio_exit(sio->addr); ++ ++ return 0; + } + + /* diff --git a/openwrt/patch/packages-patches/jool/patches/100-fix-compilation-warning-simple-fix.patch b/openwrt/patch/packages-patches/jool/patches/100-fix-compilation-warning-simple-fix.patch new file mode 100644 index 000000000..8dcd7d69b --- /dev/null +++ b/openwrt/patch/packages-patches/jool/patches/100-fix-compilation-warning-simple-fix.patch @@ -0,0 +1,22 @@ +--- a/src/mod/common/xlator.c ++++ b/src/mod/common/xlator.c +@@ -891,7 +891,7 @@ void xlator_put(struct xlator *jool) + static bool offset_equals(struct instance_entry_usr *offset, + struct jool_instance *instance) + { +- return (offset->ns == ((PTR_AS_UINT_TYPE)instance->jool.ns & 0xFFFFFFFF)) ++ return (offset->ns == ((uintptr_t)instance->jool.ns & 0xFFFFFFFF)) + && (strcmp(offset->iname, instance->jool.iname) == 0); + } + +--- a/src/mod/common/nl/instance.c ++++ b/src/mod/common/nl/instance.c +@@ -38,7 +38,7 @@ static int serialize_instance(struct xla + if (!root) + return 1; + +- error = nla_put_u32(skb, JNLAIE_NS, ((PTR_AS_UINT_TYPE)entry->ns) & 0xFFFFFFFF); ++ error = nla_put_u32(skb, JNLAIE_NS, ((uintptr_t)entry->ns) & 0xFFFFFFFF); + if (error) + goto cancel; + error = nla_put_u8(skb, JNLAIE_XF, xlator_flags2xf(entry->flags)); diff --git a/openwrt/patch/packages-patches/jool/patches/900-fix-build-with-linux-6.18.patch b/openwrt/patch/packages-patches/jool/patches/900-fix-build-with-linux-6.18.patch new file mode 100644 index 000000000..0cd4e5bee --- /dev/null +++ b/openwrt/patch/packages-patches/jool/patches/900-fix-build-with-linux-6.18.patch @@ -0,0 +1,29 @@ +--- a/src/mod/common/rfc7915/6to4.c ++++ b/src/mod/common/rfc7915/6to4.c +@@ -203,7 +203,7 @@ static verdict compute_flowix64(struct x + hdr6 = pkt_ip6_hdr(&state->in); + + flow4->flowi4_mark = state->in.skb->mark; +- flow4->flowi4_tos = xlat_tos(&state->jool.globals, hdr6); ++ flow4->flowi4_dscp = xlat_tos(&state->jool.globals, hdr6); + flow4->flowi4_scope = RT_SCOPE_UNIVERSE; + flow4->flowi4_proto = xlat_proto(hdr6); + /* +@@ -645,7 +645,7 @@ static verdict ttp64_ipv4_external(struc + + hdr4->version = 4; + hdr4->ihl = 5; +- hdr4->tos = flow4->flowi4_tos; ++ hdr4->tos = flow4->flowi4_dscp; + hdr4->tot_len = cpu_to_be16(state->out.skb->len); + generate_ipv4_id(state, hdr4, hdr_frag); + hdr4->frag_off = xlat_frag_off(hdr_frag, state); +--- a/src/mod/common/timer.c ++++ b/src/mod/common/timer.c +@@ -63,5 +63,5 @@ int jtimer_setup(void) + */ + void jtimer_teardown(void) + { +- del_timer_sync(&timer); ++ timer_delete_sync(&timer); + } diff --git a/openwrt/patch/packages-patches/libpfring/patches/901-fix-build-for-linux-6.17.patch b/openwrt/patch/packages-patches/libpfring/patches/901-fix-build-for-linux-6.17.patch new file mode 100644 index 000000000..3760135ba --- /dev/null +++ b/openwrt/patch/packages-patches/libpfring/patches/901-fix-build-for-linux-6.17.patch @@ -0,0 +1,38 @@ +--- a/kernel/pf_ring.c ++++ b/kernel/pf_ring.c +@@ -5196,7 +5196,11 @@ static int is_netdev_promisc(struct net_ + debug_printk(1, "checking promisc for %s\n", netdev->name); + + rtnl_lock(); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,17,0) + if_flags = (short) dev_get_flags(netdev); ++#else ++ if_flags = (short) netif_get_flags(netdev); ++#endif + rtnl_unlock(); + + return !!(if_flags & IFF_PROMISC); +@@ -5211,7 +5215,11 @@ static void set_netdev_promisc(struct ne + + rtnl_lock(); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,17,0) + if_flags = (short) dev_get_flags(netdev); ++#else ++ if_flags = (short) netif_get_flags(netdev); ++#endif + if(!(if_flags & IFF_PROMISC)) { + if_flags |= IFF_PROMISC; + #if(LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) && \ +@@ -5234,7 +5242,11 @@ static void unset_netdev_promisc(struct + + rtnl_lock(); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,17,0) + if_flags = (short) dev_get_flags(netdev); ++#else ++ if_flags = (short) netif_get_flags(netdev); ++#endif + if(if_flags & IFF_PROMISC) { + if_flags &= ~IFF_PROMISC; + #if(LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) && \ diff --git a/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch b/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch new file mode 100644 index 000000000..7101b3024 --- /dev/null +++ b/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch @@ -0,0 +1,22 @@ +--- a/nat46/modules/nat46-module.c ++++ b/nat46/modules/nat46-module.c +@@ -48,7 +48,7 @@ + #define NAT46_CONTROL_PROC_NAME "control" + + #ifndef NAT46_VERSION +-#define NAT46_VERSION __DATE__ " " __TIME__ ++#define NAT46_VERSION "Unknown Version" + #endif + + MODULE_LICENSE("GPL"); +--- a/nat46/modules/nat46-netdev.c ++++ b/nat46/modules/nat46-netdev.c +@@ -113,7 +113,7 @@ static void nat46_netdev_setup(struct ne + #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0) + dev->features = NETIF_F_NETNS_LOCAL; + #else +- dev->features = dev->netns_local; ++ dev->features = dev->netns_immutable; + #endif + dev->flags = IFF_NOARP | IFF_POINTOPOINT; + } diff --git a/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch b/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch deleted file mode 100644 index b3456527a..000000000 --- a/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch +++ /dev/null @@ -1,9 +0,0 @@ ---- a/drivers/net/ovpn-dco/main.c -+++ b/drivers/net/ovpn-dco/main.c -@@ -268,4 +268,6 @@ MODULE_AUTHOR(DRV_COPYRIGHT); - MODULE_LICENSE("GPL"); - MODULE_VERSION(DRV_VERSION); - MODULE_ALIAS_RTNL_LINK(DRV_NAME); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - MODULE_ALIAS_GENL_FAMILY(OVPN_NL_NAME); -+#endif diff --git a/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch b/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch deleted file mode 100644 index c47ea0ac9..000000000 --- a/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/drivers/net/ovpn-dco/main.c -+++ b/drivers/net/ovpn-dco/main.c -@@ -125,7 +125,11 @@ static void ovpn_setup(struct net_device - const int overhead = sizeof(u32) + NONCE_WIRE_SIZE + 16 + sizeof(struct udphdr) + - max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) -+ netdev_features_t feat = NETIF_F_SG | dev->lltx | -+#else - netdev_features_t feat = NETIF_F_SG | NETIF_F_LLTX | -+#endif - NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_GSO | - NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA; - diff --git a/openwrt/patch/packages-patches/ovpn-dco/Makefile b/openwrt/patch/packages-patches/ovpn-dco/Makefile new file mode 100644 index 000000000..d9657b806 --- /dev/null +++ b/openwrt/patch/packages-patches/ovpn-dco/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (C) 2021 Jianhui Zhao +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=ovpn-dco +PKG_VERSION:=0.2.20251017 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL=https://codeload.github.com/OpenVPN/ovpn-dco/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=af88c9bc73b350e0cada9aa5b21c5d4b598f9a9868f0b78b2d06026183a67032 + +PKG_MAINTAINER:=Jianhui Zhao +PKG_LICENSE:=GPL-2.0-only + + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/ovpn-dco-v2 + SUBMENU:=Network Support + TITLE:=OpenVPN data channel offload + DEPENDS:=+kmod-crypto-aead +kmod-udptunnel4 +IPV6:kmod-udptunnel6 + FILES:=$(PKG_BUILD_DIR)/drivers/net/ovpn-dco/ovpn-dco-v2.ko + AUTOLOAD:=$(call AutoLoad,30,ovpn-dco-v2) +endef + +define KernelPackage/ovpn-dco-v2/description + This module enhances the performance of the OpenVPN userspace software + by offloading the data channel processing to kernelspace. +endef + +NOSTDINC_FLAGS += \ + $(KERNEL_NOSTDINC_FLAGS) \ + -I$(PKG_BUILD_DIR)/include \ + -I$(PKG_BUILD_DIR)/compat-include \ + -include $(PKG_BUILD_DIR)/linux-compat.h + +EXTRA_KCONFIG:= \ + CONFIG_OVPN_DCO_V2=m + +PKG_EXTMOD_SUBDIRS = drivers/net/ovpn-dco + +MAKE_OPTS:= \ + $(KERNEL_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)/drivers/net/ovpn-dco" \ + NOSTDINC_FLAGS="$(NOSTDINC_FLAGS)" \ + $(EXTRA_KCONFIG) + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + $(MAKE_OPTS) \ + modules +endef + +$(eval $(call KernelPackage,ovpn-dco-v2)) diff --git a/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch b/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch new file mode 100644 index 000000000..29a6a80f9 --- /dev/null +++ b/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch @@ -0,0 +1,33 @@ +--- a/kernel-module/xt_RTPENGINE.c ++++ b/kernel-module/xt_RTPENGINE.c +@@ -35,16 +35,14 @@ + #include + #include + #include +-#ifndef __RE_EXTERNAL +-#include +-#else + #include "xt_RTPENGINE.h" +-#endif + + #include "rtpengine_config.h" + + MODULE_LICENSE("GPL"); +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,13,0) ++MODULE_IMPORT_NS("CRYPTO_INTERNAL"); ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0) + MODULE_IMPORT_NS(CRYPTO_INTERNAL); + #endif + MODULE_ALIAS("ipt_RTPENGINE"); +--- a/kernel-module/xt_RTPENGINE.h ++++ b/kernel-module/xt_RTPENGINE.h +@@ -1,7 +1,7 @@ + #ifndef XT_RTPPROXY_H + #define XT_RTPPROXY_H + +- ++#define RTPENGINE_VERSION "11.5.1.18" + + #define RTPE_NUM_PAYLOAD_TYPES 32 + #define RTPE_MAX_FORWARD_DESTINATIONS 32 diff --git a/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch b/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch index c23f6395a..a045c078d 100644 --- a/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch +++ b/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch @@ -8,7 +8,7 @@ #define NAME "ubootenv" -@@ -132,18 +133,30 @@ static int ubootenv_probe(struct platfor +@@ -132,13 +133,21 @@ static int ubootenv_probe(struct platfor return misc_register(&data->misc); } @@ -31,12 +31,3 @@ } static struct platform_driver ubootenv_driver = { - .probe = ubootenv_probe, -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - .remove = ubootenv_remove, -+#else -+ .remove_new = ubootenv_remove, -+#endif - .driver = { - .name = NAME, - .owner = THIS_MODULE, diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 035baa2e1..a2b4b9476 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -23,6 +23,8 @@ curl -s $mirror/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-mem curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 #curl -s $mirror/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch | patch -p1 #curl -s $mirror/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch | patch -p1 # attr no-mold [ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 85af43302..4f4c8dba3 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -8,54 +8,53 @@ git clone https://$github/sbwml/autocore-arm -b openwrt-24.10 package/system/aut # rockchip - target - r4s/r5s only rm -rf target/linux/rockchip if [ "$(whoami)" = "sbwml" ]; then - git clone https://$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-24.10 + git clone https://$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b v6.18 else - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b openwrt-24.10 + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b v6.18 fi -# bpf-headers - 6.12 -sed -ri "s/(PKG_PATCHVER:=)[^\"]*/\16.12/" package/kernel/bpf-headers/Makefile - -# x86_64 - target 6.12 -curl -s $mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.12 > target/linux/x86/64/config-6.12 -curl -s $mirror/openwrt/patch/openwrt-6.x/x86/config-6.12 > target/linux/x86/config-6.12 -mkdir -p target/linux/x86/patches-6.12 -curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.12/100-fix_cs5535_clockevt.patch -curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.12/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.12/103-pcengines_apu6_platform.patch -# x86_64 - target -sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.12/" target/linux/x86/Makefile +# bpf-headers - 6.18 +sed -ri "s/(PKG_PATCHVER:=)[^\"]*/\16.18/" package/kernel/bpf-headers/Makefile +sed -ri "s/tar.xz/tar.gz/" package/kernel/bpf-headers/Makefile +curl -s $mirror/openwrt/patch/packages-patches/bpf-headers/900-fix-build.patch > package/kernel/bpf-headers/patches/900-fix-build.patch + +## x86_64 - target 6.18 +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/64/config-6.18 > target/linux/x86/64/config-6.18 +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/config-6.18 > target/linux/x86/config-6.18 +mkdir -p target/linux/x86/patches-6.18 +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.18/100-fix_cs5535_clockevt.patch > target/linux/x86/patches-6.18/100-fix_cs5535_clockevt.patch +curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.18/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.18/103-pcengines_apu6_platform.patch +## x86_64 - target +sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.18/" target/linux/x86/Makefile sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network # armsr/armv8 rm -rf target/linux/armsr -git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b main +git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b v6.18 -# kernel - 6.12 -curl -s $mirror/tags/kernel-6.12 > include/kernel-6.12 +# kernel - 6.18 +curl -s $mirror/tags/kernel-6.18 > include/kernel-6.18 # kenrel Vermagic sed -ie 's/^\(.\).*vermagic$/\1cp $(TOPDIR)\/.vermagic $(LINUX_DIR)\/.vermagic/' include/kernel-defaults.mk -grep HASH include/kernel-6.12 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic +grep HASH include/kernel-6.18 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic # kernel generic patches -curl -s $mirror/openwrt/patch/kernel-6.12/openwrt/linux-6.12-target-linux-generic.patch | patch -p1 -local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-6.12) -release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-6.12 | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') +curl -s $mirror/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch | patch -p1 +local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-6.18) +release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-6.18 | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then - git clone https://$github/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 + git clone https://$github/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.18 --depth=1 else if [ "$(whoami)" = "sbwml" ]; then - git clone https://$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 + git clone https://$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.18 --depth=1 else - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.12 --depth=1 + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.18 --depth=1 fi fi -cp -a target/linux/generic-6.12/* target/linux/generic - -# bcm53xx - fix build kernel with clang -[ "$platform" = "bcm53xx" ] && [ "$KERNEL_CLANG_LTO" = "y" ] && rm -f target/linux/generic/hack-6.6/220-arm-gc_sections.patch target/linux/generic/hack-6.12/220-arm-gc_sections.patch +cp -a target/linux/generic-6.18/* target/linux/generic # kernel modules rm -rf package/kernel/linux @@ -91,69 +90,68 @@ pushd package/kernel/linux/modules curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/wpan.mk popd -# BBRv3 - linux-6.12 -pushd target/linux/generic/backport-6.12 - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch +# BBRv3 - linux-6.18 +pushd target/linux/generic/backport-6.18 + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0019-x86-cfi-bpf-Add-tso_segs-and-skb_marked_lost-to-bpf_.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0020-net-tcp_bbr-v3-silence-Wconstant-logical-operand.patch popd -# LRNG - 6.12 -pushd target/linux/generic/hack-6.12 - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0003-LRNG-proc-interface.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch +# LRNG - 6.18 +pushd target/linux/generic/hack-6.18 + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0001-LRNG-Entropy-Source-and-DRNG-Manager.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0002-LRNG-allocate-one-DRNG-instance-per-NUMA-node.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0003-LRNG-proc-interface.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0004-LRNG-add-switchable-DRNG-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0005-LRNG-add-common-generic-hash-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0006-crypto-DRBG-externalize-DRBG-functions-for-LRNG.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0007-LRNG-add-SP800-90A-DRBG-extension.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0008-LRNG-add-kernel-crypto-API-PRNG-extension.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0009-LRNG-add-atomic-DRNG-implementation.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0010-LRNG-add-common-timer-based-entropy-source-code.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0011-LRNG-add-interrupt-entropy-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0013-LRNG-add-scheduler-based-entropy-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0014-LRNG-add-SP800-90B-compliant-health-tests.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0015-LRNG-add-random.c-entropy-source-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0016-LRNG-CPU-entropy-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0017-LRNG-add-Jitter-RNG-fast-noise-source.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0018-LRNG-add-option-to-enable-runtime-entropy-rate-confi.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0019-LRNG-add-interface-for-gathering-of-raw-entropy.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0020-LRNG-add-power-on-and-runtime-self-tests.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0021-LRNG-sysctls-and-proc-interface.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0022-LRMG-add-drop-in-replacement-random-4-API.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0023-LRNG-add-kernel-crypto-API-interface.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0024-LRNG-add-dev-lrng-device-file-support.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/lrng/011-LRNG-0025-LRNG-add-hwrand-framework-interface.patch popd # linux-rt - i915 -pushd target/linux/generic/hack-6.12 - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0003-drm-i915-Don-t-check-for-atomic-context-on-PREEMPT_R.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0004-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0005-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0006-drm-i915-Drop-the-irqs_disabled-check.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0007-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch - curl -Os $mirror/openwrt/patch/kernel-6.12/linux-rt/012-0008-Revert-drm-i915-Depend-on-PREEMPT_RT.patch +pushd target/linux/generic/hack-6.18 + curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0001-drm-i915-Use-preempt_disable-enable_rt-where-recomme.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0002-drm-i915-Don-t-disable-interrupts-on-PREEMPT_RT-duri.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0003-drm-i915-Disable-tracing-points-on-PREEMPT_RT.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0004-drm-i915-gt-Use-spin_lock_irq-instead-of-local_irq_d.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0005-drm-i915-Drop-the-irqs_disabled-check.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0006-drm-i915-guc-Consider-also-RCU-depth-in-busy-loop.patch + curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0007-Revert-drm-i915-Depend-on-PREEMPT_RT.patch popd # iproute2 - bbr3 @@ -170,31 +168,31 @@ rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch +curl -s $mirror/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch > package/kernel/mt76/patches/102-fix-build-with-linux-6.18.patch # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - 6.16.8 +# mac80211 - 6.18 rm -rf package/kernel/mac80211 -git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b openwrt-24.10 +git clone https://$gitea/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.18 # ath10k-ct rm -rf package/kernel/ath10k-ct -git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.15 +git clone https://$github/sbwml/package_kernel_ath10k-ct package/kernel/ath10k-ct -b v6.18 # kernel patch # btf: silence btf module warning messages -curl -s $mirror/openwrt/patch/kernel-6.12/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-6.12/990-btf-silence-btf-module-warning-messages.patch +curl -s $mirror/openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch > target/linux/generic/hack-6.18/990-btf-silence-btf-module-warning-messages.patch # cpu model -curl -s $mirror/openwrt/patch/kernel-6.12/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/hack-6.12/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch -# fullcone -curl -s $mirror/openwrt/patch/kernel-6.12/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-6.12/952-net-conntrack-events-support-multiple-registrant.patch +curl -s $mirror/openwrt/patch/kernel-6.18/arm64/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch > target/linux/generic/hack-6.18/312-arm64-cpuinfo-Add-model-name-in-proc-cpuinfo-for-64bit-ta.patch # bcm-fullcone -curl -s $mirror/openwrt/patch/kernel-6.12/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-6.12/982-add-bcm-fullcone-support.patch -curl -s $mirror/openwrt/patch/kernel-6.12/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-6.12/983-add-bcm-fullcone-nft_masq-support.patch +curl -s $mirror/openwrt/patch/kernel-6.18/net/982-add-bcm-fullcone-support.patch > target/linux/generic/hack-6.18/982-add-bcm-fullcone-support.patch +curl -s $mirror/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch > target/linux/generic/hack-6.18/983-add-bcm-fullcone-nft_masq-support.patch # shortcut-fe -curl -s $mirror/openwrt/patch/kernel-6.12/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-6.12/601-netfilter-export-udp_get_timeouts-function.patch -curl -s $mirror/openwrt/patch/kernel-6.12/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.12/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +curl -s $mirror/openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeouts-function.patch > target/linux/generic/hack-6.18/601-netfilter-export-udp_get_timeouts-function.patch +curl -s $mirror/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-6.18/952-net-conntrack-events-support-multiple-registrant.patch +curl -s $mirror/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.18/953-net-patch-linux-kernel-to-support-shortcut-fe.patch # rtl8822cs git clone https://$github/sbwml/package_kernel_rtl8822cs package/kernel/rtl8822cs diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index fa9c9dd82..a12c8d6d3 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -# Fix build for 6.12 +# Fix build for 6.18 ### BROKEN sed -i 's/^\([[:space:]]*DEPENDS:=.*\)$/\1 @BROKEN/' package/kernel/rtl8812au-ct/Makefile @@ -9,17 +9,24 @@ sed -i 's/^\([[:space:]]*DEPENDS:=.*\)$/\1 @BROKEN/' package/kernel/rtl8812au-ct mkdir -p package/kernel/cryptodev-linux/patches curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch > package/kernel/cryptodev-linux/patches/0006-Exclude-unused-struct-since-Linux-6.5.patch +curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.18/900-fix-linux-6.18.patch > package/kernel/cryptodev-linux/patches/900-fix-linux-6.18.patch # gpio-button-hotplug curl -s $mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 +# gpio-nct5104d +curl -s $mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-linux-6.18.patch | patch -p1 + # jool +rm -rf feeds/packages/net/jool +mkdir -p feeds/packages/net/jool/patches curl -s $mirror/openwrt/patch/packages-patches/jool/Makefile > feeds/packages/net/jool/Makefile +curl -s $mirror/openwrt/patch/packages-patches/jool/patches/100-fix-compilation-warning-simple-fix.patch > feeds/packages/net/jool/patches/100-fix-compilation-warning-simple-fix.patch +curl -s $mirror/openwrt/patch/packages-patches/jool/patches/900-fix-build-with-linux-6.18.patch > feeds/packages/net/jool/patches/900-fix-build-with-linux-6.18.patch # ovpn-dco -mkdir -p feeds/packages/kernel/ovpn-dco/patches -curl -s $mirror/openwrt/patch/packages-patches/ovpn-dco/901-fix-linux-6.11.patch > feeds/packages/kernel/ovpn-dco/patches/901-fix-linux-6.11.patch -curl -s $mirror/openwrt/patch/packages-patches/ovpn-dco/902-fix-linux-6.12.patch > feeds/packages/kernel/ovpn-dco/patches/902-fix-linux-6.12.patch +rm -rf feeds/packages/kernel/ovpn-dco/patches +curl -s $mirror/openwrt/patch/packages-patches/ovpn-dco/Makefile > feeds/packages/kernel/ovpn-dco/Makefile # libpfring rm -rf feeds/packages/libs/libpfring @@ -29,18 +36,21 @@ pushd feeds/packages/libs/libpfring/patches curl -Os $mirror/openwrt/patch/packages-patches/libpfring/patches/0001-fix-cross-compiling.patch curl -Os $mirror/openwrt/patch/packages-patches/libpfring/patches/100-fix-compilation-warning.patch curl -Os $mirror/openwrt/patch/packages-patches/libpfring/patches/900-fix-linux-6.6.patch + curl -Os $mirror/openwrt/patch/packages-patches/libpfring/patches/901-fix-build-for-linux-6.17.patch popd # nat46 mkdir -p package/kernel/nat46/patches curl -s $mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch > package/kernel/nat46/patches/100-fix-build-with-kernel-6.9.patch curl -s $mirror/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch > package/kernel/nat46/patches/101-fix-build-with-kernel-6.12.patch +curl -s $mirror/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch > package/kernel/nat46/patches/102-fix-build-with-kernel-6.18.patch # openvswitch sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile # rtpengine curl -s $mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch +curl -s $mirror/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch > feeds/telephony/net/rtpengine/patches/901-fix-build-for-linux-6.18.patch # ubootenv-nvram - 6.12 mkdir -p package/kernel/ubootenv-nvram/patches @@ -70,7 +80,7 @@ curl -s $mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2- if [ "$KERNEL_CLANG_LTO" = "y" ]; then # xtables-addons module rm -rf feeds/packages/net/xtables-addons - git clone https://$github/sbwml/kmod_packages_net_xtables-addons feeds/packages/net/xtables-addons + git clone https://$github/sbwml/kmod_packages_net_xtables-addons feeds/packages/net/xtables-addons -b v6.18 # netatop sed -i 's/$(MAKE)/$(KERNEL_MAKE)/g' feeds/packages/admin/netatop/Makefile curl -s $mirror/openwrt/patch/packages-patches/clang/netatop/900-fix-build-with-clang.patch > feeds/packages/admin/netatop/patches/900-fix-build-with-clang.patch diff --git a/tags/kernel-6.12 b/tags/kernel-6.12 deleted file mode 100644 index 1b89660b4..000000000 --- a/tags/kernel-6.12 +++ /dev/null @@ -1,2 +0,0 @@ -LINUX_VERSION-6.12 = .54 -LINUX_KERNEL_HASH-6.12.54 = 1b0dcd3390efeec44e528748609bafcf36eae895bb68c8f62ac5e5940943de62 diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 new file mode 100644 index 000000000..134e6ef8f --- /dev/null +++ b/tags/kernel-6.18 @@ -0,0 +1,2 @@ +LINUX_VERSION-6.18 = -rc3 +LINUX_KERNEL_HASH-6.18-rc3 = b74e58937e196289c59238d84208ca668d60c8497e50e01775ce696f864a170c diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index b744dcc68..f526afa12 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -5,10 +5,10 @@ set -e ROOT="./" # LTS -KERNEL_VERSION=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "6_12") | .version'` -KERNEL_HASH=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "6_12") | .checksum'` +KERNEL_VERSION=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "mainline") | .version'` +KERNEL_HASH=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "mainline") | .checksum'` TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` [ -z $TAG ] && TAG="" || TAG=.$TAG -echo "LINUX_VERSION-6.12 = $TAG -LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.12 +echo "LINUX_VERSION-6.18 = $TAG +LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.18 From 8bc172473b04c67fde6c5fc799a109dfd7ea0ecb Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 4 Nov 2025 09:41:02 +0800 Subject: [PATCH 305/425] linux-6.18: bump to 6.18-rc4 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 134e6ef8f..8bbbe579c 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = -rc3 -LINUX_KERNEL_HASH-6.18-rc3 = b74e58937e196289c59238d84208ca668d60c8497e50e01775ce696f864a170c +LINUX_VERSION-6.18 = -rc4 +LINUX_KERNEL_HASH-6.18-rc4 = 0ed47cb05c1ec56cb3a277664575da49b1d9ed6fd02b674cc29ff37e0f93b0a1 From 1c0fe6055a0a6e3f592d4440e120d13c4eb6812a Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 10 Nov 2025 23:06:26 +0800 Subject: [PATCH 306/425] openwrt: refresh patch Signed-off-by: sbwml --- openwrt/24-config-musl-r4s | 1 + openwrt/24-config-musl-r76s | 2 +- ...r-update-kernel-config-options-for-l.patch | 12 ++++---- .../target-modify_for_aarch64_x86_64.patch | 28 +++++++++++++++++++ openwrt/patch/target-modify_for_armsr.patch | 15 ---------- .../patch/target-modify_for_rockchip.patch | 15 ---------- openwrt/patch/target-modify_for_x86_64.patch | 13 --------- ...vim-fix-renamed-defaults-config-file.patch | 12 ++++---- openwrt/scripts/00-prepare_base.sh | 8 +----- 9 files changed, 42 insertions(+), 64 deletions(-) create mode 100644 openwrt/patch/target-modify_for_aarch64_x86_64.patch delete mode 100644 openwrt/patch/target-modify_for_armsr.patch delete mode 100644 openwrt/patch/target-modify_for_rockchip.patch delete mode 100644 openwrt/patch/target-modify_for_x86_64.patch diff --git a/openwrt/24-config-musl-r4s b/openwrt/24-config-musl-r4s index 2bd107954..0e307b839 100644 --- a/openwrt/24-config-musl-r4s +++ b/openwrt/24-config-musl-r4s @@ -8,6 +8,7 @@ CONFIG_ALL_KMODS=y CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" +CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a72.cortex-a53+crypto+crc -mtune=cortex-a72.cortex-a53" CONFIG_KERNEL_MEMCG_V1=y CONFIG_KERNEL_MPTCP=y CONFIG_KERNEL_MPTCP_IPV6=y diff --git a/openwrt/24-config-musl-r76s b/openwrt/24-config-musl-r76s index 71ec2accd..42619616b 100644 --- a/openwrt/24-config-musl-r76s +++ b/openwrt/24-config-musl-r76s @@ -8,7 +8,7 @@ CONFIG_ALL_KMODS=y CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" -CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a73+crypto+crc -mtune=cortex-a73" +CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a72.cortex-a53+crypto+crc -mtune=cortex-a72.cortex-a53" CONFIG_KERNEL_MEMCG_V1=y CONFIG_KERNEL_MPTCP=y CONFIG_KERNEL_MPTCP_IPV6=y diff --git a/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch b/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch index d0954dce1..bf3243b90 100644 --- a/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch +++ b/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch @@ -10,23 +10,21 @@ Signed-off-by: sbwml 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/netfilter.mk b/include/netfilter.mk -index 255e478..6c4ce9d 100644 +index 255e478..afe9d4d 100644 --- a/include/netfilter.mk +++ b/include/netfilter.mk -@@ -29,7 +29,7 @@ endef - # kernel only +@@ -30,6 +30,7 @@ endef $(eval $(if $(NF_KMOD),$(call nf_add,NF_REJECT,CONFIG_NF_REJECT_IPV4, $(P_V4)nf_reject_ipv4),)) --$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES, $(P_V4)ip_tables),)) + $(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES, $(P_V4)ip_tables),)) +$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES_LEGACY, $(P_V4)ip_tables),)) $(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_NETFILTER_XTABLES, $(P_XT)x_tables),)) $(eval $(if $(NF_KMOD),$(call nf_add,IPT_CORE,CONFIG_NETFILTER_XTABLES, $(P_XT)xt_tcpudp),)) -@@ -282,7 +282,7 @@ $(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNCOUNT,CONFIG_NETFILTER_CONNCOUNT, $( - # ebtables +@@ -283,6 +284,7 @@ $(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNCOUNT,CONFIG_NETFILTER_CONNCOUNT, $( # --$(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES, $(P_EBT)ebtables),)) + $(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES, $(P_EBT)ebtables),)) +$(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES_LEGACY, $(P_EBT)ebtables),)) # ebtables: tables diff --git a/openwrt/patch/target-modify_for_aarch64_x86_64.patch b/openwrt/patch/target-modify_for_aarch64_x86_64.patch new file mode 100644 index 000000000..af782b842 --- /dev/null +++ b/openwrt/patch/target-modify_for_aarch64_x86_64.patch @@ -0,0 +1,28 @@ +diff --git a/include/target.mk b/include/target.mk +index 02ea68b..28b3f56 100644 +--- a/include/target.mk ++++ b/include/target.mk +@@ -221,7 +221,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt + ifeq ($(DUMP),1) + BuildTarget=$(BuildTargets/DumpCurrent) + +- CPU_CFLAGS = -Os -pipe ++ CPU_CFLAGS = -O3 -mtune=generic -pipe + ifneq ($(findstring mips,$(ARCH)),) + ifneq ($(findstring mips64,$(ARCH)),) + CPU_TYPE ?= mips64 +@@ -282,6 +282,14 @@ ifeq ($(DUMP),1) + CPU_CFLAGS := -O2 -pipe + CPU_CFLAGS_generic:=-march=loongarch64 + endif ++ ifeq ($(BOARD),armsr) ++ CPU_CFLAGS = -O3 -pipe ++ CPU_CFLAGS_generic = -march=armv8-a+crc+crypto ++ endif ++ ifeq ($(BOARD),rockchip) ++ CPU_CFLAGS = -O3 -Wl,--gc-sections -pipe ++ CPU_CFLAGS_generic = -march=armv8-a+crc+crypto ++ endif + ifneq ($(CPU_TYPE),) + ifndef CPU_CFLAGS_$(CPU_TYPE) + $(warning CPU_TYPE "$(CPU_TYPE)" doesn't correspond to a known type) diff --git a/openwrt/patch/target-modify_for_armsr.patch b/openwrt/patch/target-modify_for_armsr.patch deleted file mode 100644 index 7eb6e07b4..000000000 --- a/openwrt/patch/target-modify_for_armsr.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/include/target.mk b/include/target.mk -index 0108bce..4ceb81e 100644 ---- a/include/target.mk -+++ b/include/target.mk -@@ -318,6 +318,10 @@ ifeq ($(DUMP),1) - CPU_CFLAGS := -O2 -pipe - CPU_CFLAGS_generic:=-march=loongarch64 - endif -+ ifeq ($(BOARD),armsr) -+ CPU_CFLAGS = -O3 -pipe -+ CPU_CFLAGS_generic = -march=armv8-a+crc+crypto -+ endif - ifneq ($(CPU_TYPE),) - ifndef CPU_CFLAGS_$(CPU_TYPE) - $(warning CPU_TYPE "$(CPU_TYPE)" doesn't correspond to a known type) diff --git a/openwrt/patch/target-modify_for_rockchip.patch b/openwrt/patch/target-modify_for_rockchip.patch deleted file mode 100644 index 9f31ae529..000000000 --- a/openwrt/patch/target-modify_for_rockchip.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/include/target.mk b/include/target.mk -index 0108bce..5577072 100644 ---- a/include/target.mk -+++ b/include/target.mk -@@ -318,6 +318,10 @@ ifeq ($(DUMP),1) - CPU_CFLAGS := -O2 -pipe - CPU_CFLAGS_generic:=-march=loongarch64 - endif -+ ifeq ($(BOARD),rockchip) -+ CPU_CFLAGS = -O3 -Wl,--gc-sections -pipe -+ CPU_CFLAGS_generic = -march=armv8-a+crc+crypto -+ endif - ifneq ($(CPU_TYPE),) - ifndef CPU_CFLAGS_$(CPU_TYPE) - $(warning CPU_TYPE "$(CPU_TYPE)" doesn't correspond to a known type) diff --git a/openwrt/patch/target-modify_for_x86_64.patch b/openwrt/patch/target-modify_for_x86_64.patch deleted file mode 100644 index f6927b494..000000000 --- a/openwrt/patch/target-modify_for_x86_64.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/include/target.mk b/include/target.mk -index 0108bce..45ade4b 100644 ---- a/include/target.mk -+++ b/include/target.mk -@@ -257,7 +257,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt - ifeq ($(DUMP),1) - BuildTarget=$(BuildTargets/DumpCurrent) - -- CPU_CFLAGS = -Os -pipe -+ CPU_CFLAGS = -O3 -mtune=generic -pipe - ifneq ($(findstring mips,$(ARCH)),) - ifneq ($(findstring mips64,$(ARCH)),) - CPU_TYPE ?= mips64 diff --git a/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch b/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch index ef77c7087..5a472860f 100644 --- a/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch +++ b/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch @@ -1,4 +1,4 @@ -From 7388298a7c008c1b999ae3f819ad6308738ea733 Mon Sep 17 00:00:00 2001 +From 0ce3488d0852c204c5b96f46cd551c6205b3d993 Mon Sep 17 00:00:00 2001 From: Leonard de Vries Date: Thu, 21 Sep 2023 09:40:12 +0200 Subject: [PATCH] vim: fix renamed defaults config file @@ -17,10 +17,10 @@ Signed-off-by: Leonard de Vries rename utils/vim/files/{vimrc.full => defaults.vim.full} (100%) diff --git a/utils/vim/Makefile b/utils/vim/Makefile -index 125acbf99..59ae674fa 100644 +index 7726765..a6d6dd2 100644 --- a/utils/vim/Makefile +++ b/utils/vim/Makefile -@@ -73,12 +73,12 @@ define Package/xxd +@@ -74,12 +74,12 @@ define Package/xxd endef define Package/vim-full/conffiles @@ -35,7 +35,7 @@ index 125acbf99..59ae674fa 100644 /root/.vimrc endef -@@ -208,7 +208,7 @@ define Package/vim/install +@@ -209,7 +209,7 @@ define Package/vim/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/vim_tiny $(1)/usr/bin/vim $(INSTALL_DIR) $(1)/usr/share/vim @@ -44,7 +44,7 @@ index 125acbf99..59ae674fa 100644 endef define Package/vim-full/install -@@ -216,7 +216,7 @@ define Package/vim-full/install +@@ -217,7 +217,7 @@ define Package/vim-full/install $(INSTALL_BIN) $(PKG_BUILD_DIR)/vim_normal $(1)/usr/bin/vim $(INSTALL_DIR) $(1)/usr/share/vim $(LN) vim $(1)/usr/bin/vimdiff @@ -53,7 +53,7 @@ index 125acbf99..59ae674fa 100644 endef -@@ -226,7 +226,7 @@ define Package/vim-fuller/install +@@ -227,7 +227,7 @@ define Package/vim-fuller/install $(INSTALL_DIR) $(1)/usr/share/vim $(LN) vim $(1)/usr/bin/vimdiff $(CP) $(PKG_INSTALL_DIR)/usr/share/vim/vim$(VIMVER) $(1)/usr/share/vim diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index a2b4b9476..25dd4dde1 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -70,13 +70,7 @@ git clone https://$github/sbwml/package_kernel_r8126 package/kernel/r8126 git clone https://$github/sbwml/package_kernel_r8127 package/kernel/r8127 # GCC Optimization level -O3 -if [ "$platform" = "x86_64" ]; then - curl -s $mirror/openwrt/patch/target-modify_for_x86_64.patch | patch -p1 -elif [ "$platform" = "armv8" ]; then - curl -s $mirror/openwrt/patch/target-modify_for_armsr.patch | patch -p1 -else - curl -s $mirror/openwrt/patch/target-modify_for_rockchip.patch | patch -p1 -fi +curl -s $mirror/openwrt/patch/target-modify_for_aarch64_x86_64.patch | patch -p1 # libubox sed -i '/TARGET_CFLAGS/ s/$/ -Os/' package/libs/libubox/Makefile From fa820a15a1bf175d376793f49bebd28e389c54e3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 10 Nov 2025 23:06:58 +0800 Subject: [PATCH 307/425] linux-6.18: bump to 6.18-rc5 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 8bbbe579c..7f28d275b 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = -rc4 -LINUX_KERNEL_HASH-6.18-rc4 = 0ed47cb05c1ec56cb3a277664575da49b1d9ed6fd02b674cc29ff37e0f93b0a1 +LINUX_VERSION-6.18 = -rc5 +LINUX_KERNEL_HASH-6.18-rc5 = 828cc7d4cac534124fcc53b1a17e10fb2e88341d71cbb314fd1f3551191652a3 From 01d5b08756796123633b75426888d54c2ecbf393 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 11 Nov 2025 00:01:32 +0800 Subject: [PATCH 308/425] config: fix kernel cflags Signed-off-by: sbwml --- openwrt/24-config-musl-r4s | 2 +- openwrt/24-config-musl-r76s | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/24-config-musl-r4s b/openwrt/24-config-musl-r4s index 0e307b839..0bd813d9e 100644 --- a/openwrt/24-config-musl-r4s +++ b/openwrt/24-config-musl-r4s @@ -8,7 +8,7 @@ CONFIG_ALL_KMODS=y CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" -CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a72.cortex-a53+crypto+crc -mtune=cortex-a72.cortex-a53" +CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto+crc -mtune=cortex-a72" CONFIG_KERNEL_MEMCG_V1=y CONFIG_KERNEL_MPTCP=y CONFIG_KERNEL_MPTCP_IPV6=y diff --git a/openwrt/24-config-musl-r76s b/openwrt/24-config-musl-r76s index 42619616b..c00172533 100644 --- a/openwrt/24-config-musl-r76s +++ b/openwrt/24-config-musl-r76s @@ -8,7 +8,7 @@ CONFIG_ALL_KMODS=y CONFIG_ALL_NONSHARED=y CONFIG_KERNEL_BUILD_DOMAIN="cooluc.com" CONFIG_KERNEL_BUILD_USER="admin" -CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a72.cortex-a53+crypto+crc -mtune=cortex-a72.cortex-a53" +CONFIG_KERNEL_CFLAGS="-march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto+crc -mtune=cortex-a72" CONFIG_KERNEL_MEMCG_V1=y CONFIG_KERNEL_MPTCP=y CONFIG_KERNEL_MPTCP_IPV6=y From e0e1f666729706a4b03010cba8a620c53401d933 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Nov 2025 00:20:31 +0800 Subject: [PATCH 309/425] firewall/docker: remove iptables and using only nftables Signed-off-by: sbwml --- openwrt/24-config-common | 15 --------------- openwrt/24-config-minimal-common | 13 +++++++++++++ openwrt/scripts/00-prepare_base.sh | 10 +++++----- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index fccaffc0f..27c2b51fd 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -12,23 +12,10 @@ CONFIG_LIBCURL_OPENSSL=y ### Firewall CONFIG_PACKAGE_nat6=y -CONFIG_PACKAGE_ip6tables-nft=y -CONFIG_PACKAGE_iptables-mod-conntrack-extra=y -CONFIG_PACKAGE_iptables-mod-iprange=y -CONFIG_PACKAGE_iptables-mod-nat-extra=y -CONFIG_PACKAGE_iptables-mod-socket=y -CONFIG_PACKAGE_iptables-mod-tproxy=y -CONFIG_PACKAGE_iptables-nft=y -CONFIG_PACKAGE_xtables-nft=y -# CONFIG_PACKAGE_iptables-legacy is not set # Natflow CONFIG_PACKAGE_natflow=m -# SFE -CONFIG_PACKAGE_kmod-fast-classifier=y -CONFIG_PACKAGE_kmod-shortcut-fe-cm=y - ### Zram CONFIG_PACKAGE_zram-swap=y CONFIG_ZRAM_DEF_COMP_LZ4=y @@ -195,8 +182,6 @@ CONFIG_PACKAGE_kmod-ikconfig=y CONFIG_PACKAGE_kmod-inet-diag=y CONFIG_PACKAGE_kmod-ipsec4=y CONFIG_PACKAGE_kmod-ipsec6=y -CONFIG_PACKAGE_kmod-ipt-nat6=y -CONFIG_PACKAGE_kmod-ipt-tproxy=y CONFIG_PACKAGE_kmod-iptunnel6=y CONFIG_PACKAGE_kmod-mac80211=y CONFIG_PACKAGE_kmod-nf-socket=y diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index 4f9215f2b..7af2c7efd 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -10,6 +10,19 @@ CONFIG_LIBCURL_OPENSSL=y # CONFIG_LIBCURL_NOSSL is not set # CONFIG_LIBCURL_WOLFSSL is not set +### Docker +CONFIG_DOCKER_CGROUP_OPTIONS=y +CONFIG_DOCKER_NET_ENCRYPT=y +CONFIG_DOCKER_NET_MACVLAN=y +CONFIG_DOCKER_NET_OVERLAY=y +CONFIG_DOCKER_NET_TFTP=y +CONFIG_DOCKER_OPTIONAL_FEATURES=y +CONFIG_DOCKER_STO_BTRFS=y +CONFIG_DOCKER_STO_EXT4=y +CONFIG_PACKAGE_luci-app-dockerman=y +CONFIG_PACKAGE_luci-lib-docker=y +# CONFIG_PACKAGE_cgroupfs-mount is not set + ### Firewall CONFIG_PACKAGE_nat6=y diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 25dd4dde1..46cac9f9a 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -240,13 +240,13 @@ git clone https://$github/sbwml/feeds_packages_net_curl feeds/packages/net/curl # Docker rm -rf feeds/luci/applications/luci-app-dockerman -git clone https://$gitea/sbwml/luci-app-dockerman -b openwrt-24.10 feeds/luci/applications/luci-app-dockerman +git clone https://$gitea/sbwml/luci-app-dockerman -b nft feeds/luci/applications/luci-app-dockerman if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} - git clone https://$github/sbwml/packages_utils_docker feeds/packages/utils/docker - git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd - git clone https://$github/sbwml/packages_utils_containerd feeds/packages/utils/containerd - git clone https://$github/sbwml/packages_utils_runc feeds/packages/utils/runc + git clone https://$gitea/sbwml/packages_utils_docker feeds/packages/utils/docker + git clone https://$gitea/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd + git clone https://$gitea/sbwml/packages_utils_containerd feeds/packages/utils/containerd + git clone https://$gitea/sbwml/packages_utils_runc feeds/packages/utils/runc fi # cgroupfs-mount From 319a0acca4712fd43bd4764e59d17a6271d10e38 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 13 Nov 2025 12:27:38 +0800 Subject: [PATCH 310/425] config-common: dnsmasq: remove `ipset` Signed-off-by: sbwml --- openwrt/24-config-common | 1 - 1 file changed, 1 deletion(-) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index 27c2b51fd..f7673cd85 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -31,7 +31,6 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y ### Dnsmasq CONFIG_PACKAGE_dnsmasq-full=y -CONFIG_PACKAGE_dnsmasq_full_ipset=y # CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set # CONFIG_PACKAGE_dnsmasq is not set From 07c547a0bb9c75516694728fc345a7177e8b4e80 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 17 Nov 2025 20:56:08 +0800 Subject: [PATCH 311/425] toolchain: gcc: update GCC 15 to 15.2.0 Signed-off-by: sbwml --- .../202-toolchain-gcc-add-support-for-GCC-15.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch index ba3e90fae..d598a2ec0 100644 --- a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch +++ b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch @@ -76,7 +76,7 @@ index 49bb368..9ecca5d 100644 default "11.3.0" if GCC_VERSION_11 default "12.3.0" if GCC_VERSION_12 default "14.2.0" if GCC_VERSION_14 -+ default "15.1.0" if GCC_VERSION_15 ++ default "15.2.0" if GCC_VERSION_15 default "13.3.0" config GCC_USE_DEFAULT_VERSION @@ -88,8 +88,8 @@ index 0ccf55b..1dd644f 100644 PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 endif -+ifeq ($(PKG_VERSION),15.1.0) -+ PKG_HASH:=e2b09ec21660f01fecffb715e0120265216943f038d0e48a9868713e54f06cea ++ifeq ($(PKG_VERSION),15.2.0) ++ PKG_HASH:=438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e +endif + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x From a552690e34787e9521899a241dbd2949f31a5ffa Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 17 Nov 2025 20:56:44 +0800 Subject: [PATCH 312/425] std-common: remove iptables and using only nftables Signed-off-by: sbwml --- openwrt/24-config-minimal-common | 13 -------- openwrt/24-config-std-common | 13 -------- openwrt/patch/sqm-scripts/Makefile | 45 +++++++++++++++++++++++++++ openwrt/scripts/02-prepare_package.sh | 3 ++ 4 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 openwrt/patch/sqm-scripts/Makefile diff --git a/openwrt/24-config-minimal-common b/openwrt/24-config-minimal-common index 7af2c7efd..4f9215f2b 100644 --- a/openwrt/24-config-minimal-common +++ b/openwrt/24-config-minimal-common @@ -10,19 +10,6 @@ CONFIG_LIBCURL_OPENSSL=y # CONFIG_LIBCURL_NOSSL is not set # CONFIG_LIBCURL_WOLFSSL is not set -### Docker -CONFIG_DOCKER_CGROUP_OPTIONS=y -CONFIG_DOCKER_NET_ENCRYPT=y -CONFIG_DOCKER_NET_MACVLAN=y -CONFIG_DOCKER_NET_OVERLAY=y -CONFIG_DOCKER_NET_TFTP=y -CONFIG_DOCKER_OPTIONAL_FEATURES=y -CONFIG_DOCKER_STO_BTRFS=y -CONFIG_DOCKER_STO_EXT4=y -CONFIG_PACKAGE_luci-app-dockerman=y -CONFIG_PACKAGE_luci-lib-docker=y -# CONFIG_PACKAGE_cgroupfs-mount is not set - ### Firewall CONFIG_PACKAGE_nat6=y diff --git a/openwrt/24-config-std-common b/openwrt/24-config-std-common index 02c057f15..366b01e88 100644 --- a/openwrt/24-config-std-common +++ b/openwrt/24-config-std-common @@ -12,15 +12,6 @@ CONFIG_LIBCURL_OPENSSL=y ### Firewall CONFIG_PACKAGE_nat6=y -CONFIG_PACKAGE_ip6tables-nft=y -CONFIG_PACKAGE_iptables-mod-conntrack-extra=y -CONFIG_PACKAGE_iptables-mod-iprange=y -CONFIG_PACKAGE_iptables-mod-nat-extra=y -CONFIG_PACKAGE_iptables-mod-socket=y -CONFIG_PACKAGE_iptables-mod-tproxy=y -CONFIG_PACKAGE_iptables-nft=y -CONFIG_PACKAGE_xtables-nft=y -# CONFIG_PACKAGE_iptables-legacy is not set # Natflow CONFIG_PACKAGE_natflow=m @@ -40,7 +31,6 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y ### Dnsmasq CONFIG_PACKAGE_dnsmasq-full=y -CONFIG_PACKAGE_dnsmasq_full_ipset=y # CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set # CONFIG_PACKAGE_dnsmasq is not set @@ -153,8 +143,6 @@ CONFIG_PACKAGE_kmod-ikconfig=y CONFIG_PACKAGE_kmod-inet-diag=y CONFIG_PACKAGE_kmod-ipsec4=y CONFIG_PACKAGE_kmod-ipsec6=y -CONFIG_PACKAGE_kmod-ipt-nat6=y -CONFIG_PACKAGE_kmod-ipt-tproxy=y CONFIG_PACKAGE_kmod-iptunnel6=y CONFIG_PACKAGE_kmod-mac80211=y CONFIG_PACKAGE_kmod-nf-socket=y @@ -222,7 +210,6 @@ CONFIG_PACKAGE_telnet-bsd=y CONFIG_PACKAGE_tree=y CONFIG_PACKAGE_unzip=y CONFIG_PACKAGE_usbutils=y -CONFIG_PACKAGE_vim=y CONFIG_PACKAGE_wget-ssl=y CONFIG_PACKAGE_wpad-openssl=y CONFIG_PACKAGE_xfs-admin=y diff --git a/openwrt/patch/sqm-scripts/Makefile b/openwrt/patch/sqm-scripts/Makefile new file mode 100644 index 000000000..f5c6b7299 --- /dev/null +++ b/openwrt/patch/sqm-scripts/Makefile @@ -0,0 +1,45 @@ +# +# Copyright (C) 2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=sqm-scripts +PKG_SOURCE_VERSION:=33a89d8e7f6c82acc0adced84cf5cd95447e6bb5 +PKG_VERSION:=1.6.0 +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/tohojo/sqm-scripts +PKG_MIRROR_HASH:=abe04270207177fb3ba4df103ffce3db4037d52d601ce1ce4e75206ad4b21377 + +PKG_MAINTAINER:=Toke Høiland-Jørgensen +PKG_LICENSE:=GPL-2.0-only + +include $(INCLUDE_DIR)/package.mk + +define Package/sqm-scripts + SECTION:=net + CATEGORY:=Base system + DEPENDS:=+tc +kmod-sched-cake +kmod-ifb + TITLE:=SQM Scripts (QoS) + PKGARCH:=all +endef + +define Package/sqm-scripts/description + A set of scripts that does simple SQM configuration. +endef + +define Package/sqm-scripts/conffiles +/etc/config/sqm +/etc/sqm/sqm.conf +endef + +define Package/sqm-scripts/install + make -C $(PKG_BUILD_DIR) DESTDIR=$(1) PLATFORM=openwrt install +endef + +$(eval $(call BuildPackage,sqm-scripts)) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 87e5a3eee..adfcbaa2e 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -180,3 +180,6 @@ true > feeds/packages/utils/watchcat/files/watchcat.config # libpcap rm -rf package/libs/libpcap git clone https://$github/sbwml/package_libs_libpcap package/libs/libpcap + +# sqm-scripts +curl -s $mirror/openwrt/patch/sqm-scripts/Makefile > feeds/packages/net/sqm-scripts/Makefile From dbf5ba401edf3ebfd2387be0f76287dd5d2068d2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 17 Nov 2025 20:57:10 +0800 Subject: [PATCH 313/425] linux-6.18: bump to 6.18-rc6 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 7f28d275b..8ef1fb200 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = -rc5 -LINUX_KERNEL_HASH-6.18-rc5 = 828cc7d4cac534124fcc53b1a17e10fb2e88341d71cbb314fd1f3551191652a3 +LINUX_VERSION-6.18 = -rc6 +LINUX_KERNEL_HASH-6.18-rc6 = 1a3c0b2432d61b98290816dde184b5b4f810f1bc878466bf0170ee51e85c6d36 From b3c07ede9424bb6c56c3b4b9cdfd03033371c7d7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 20 Nov 2025 22:43:25 +0800 Subject: [PATCH 314/425] script: add source mirror Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 46cac9f9a..a6709283f 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -26,6 +26,9 @@ curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-f curl -s $mirror/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch | patch -p1 +# add source mirror +sed -i '/"@OPENWRT": \[/a\\t\t"https://source.cooluc.com",' scripts/projectsmirrors.json + # attr no-mold [ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile From c2df2ce4e568448bb80220d685ca485a8f3ab616 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 2 Dec 2025 12:22:58 +0800 Subject: [PATCH 315/425] linux-6.18: bump to 6.18 Signed-off-by: sbwml --- ...hack-packet_steering-for-nanopi-r76s.patch | 46 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 3 ++ tags/kernel-6.18 | 4 +- 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.patch diff --git a/openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.patch b/openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.patch new file mode 100644 index 000000000..cfc352535 --- /dev/null +++ b/openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.patch @@ -0,0 +1,46 @@ +diff --git a/package/network/config/netifd/files/etc/init.d/packet_steering b/package/network/config/netifd/files/etc/init.d/packet_steering +index 5266a931ae..cec2002683 100755 +--- a/package/network/config/netifd/files/etc/init.d/packet_steering ++++ b/package/network/config/netifd/files/etc/init.d/packet_steering +@@ -1,5 +1,7 @@ + #!/bin/sh /etc/rc.common + ++. /lib/functions/uci-defaults.sh ++ + START=25 + USE_PROCD=1 + +@@ -16,10 +18,29 @@ service_triggers() { + reload_service() { + packet_steering="$(uci -q get "network.@globals[0].packet_steering")" + steering_flows="$(uci -q get "network.@globals[0].steering_flows")" +- [ "${steering_flows:-0}" -gt 0 ] && opts="-l $steering_flows" +- if [ -e "/usr/libexec/platform/packet-steering.sh" ]; then +- /usr/libexec/platform/packet-steering.sh "$packet_steering" ++ if [ "$packet_steering" = "0" ] && [ "$(board_name)" = "friendlyarm,nanopi-r76s" ]; then ++ for iface in eth0 eth1; do ++ [ -d "/sys/class/net/$iface" ] || continue ++ ++ case "$iface" in ++ eth0) mask="30" ;; # CPU4-5 ++ eth1) mask="c0" ;; # CPU6-7 ++ esac ++ ++ for q in /sys/class/net/$iface/queues/rx-*; do ++ [ -e "$q/rps_cpus" ] && echo "$mask" > "$q/rps_cpus" ++ done ++ ++ for q in /sys/class/net/$iface/queues/tx-*; do ++ [ -e "$q/xps_cpus" ] && echo "$mask" > "$q/xps_cpus" ++ done ++ done + else +- /usr/libexec/network/packet-steering.uc $opts "$packet_steering" ++ [ "${steering_flows:-0}" -gt 0 ] && opts="-l $steering_flows" ++ if [ -e "/usr/libexec/platform/packet-steering.sh" ]; then ++ /usr/libexec/platform/packet-steering.sh "$packet_steering" ++ else ++ /usr/libexec/network/packet-steering.uc $opts "$packet_steering" ++ fi + fi + } diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index a6709283f..fa37c31d3 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -291,6 +291,9 @@ sed -i '/ubus_parallel_req/a\ ubus_script_timeout 300;' feeds/packages/ne curl -s $mirror/openwrt/nginx/luci.locations > feeds/packages/net/nginx/files-luci-support/luci.locations curl -s $mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template +# netifd +curl -s $mirror/openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.patch | patch -p1 + # opkg mkdir -p package/system/opkg/patches curl -s $mirror/openwrt/patch/opkg/900-opkg-download-disable-hsts.patch > package/system/opkg/patches/900-opkg-download-disable-hsts.patch diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 8ef1fb200..f731e6879 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = -rc6 -LINUX_KERNEL_HASH-6.18-rc6 = 1a3c0b2432d61b98290816dde184b5b4f810f1bc878466bf0170ee51e85c6d36 +LINUX_VERSION-6.18 = +LINUX_KERNEL_HASH-6.18 = 9106a4605da9e31ff17659d958782b815f9591ab308d03b0ee21aad6c7dced4b From ee5b3453a77079ae73b9a4d4ba4f40791704f72e Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 10 Dec 2025 19:04:31 +0800 Subject: [PATCH 316/425] config-common: add luci-app-rtp2httpd Signed-off-by: sbwml --- openwrt/24-config-common | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/24-config-common b/openwrt/24-config-common index f7673cd85..8fc323dc9 100644 --- a/openwrt/24-config-common +++ b/openwrt/24-config-common @@ -99,6 +99,7 @@ CONFIG_PACKAGE_luci-app-oaf=y CONFIG_PACKAGE_luci-app-openlist2=y CONFIG_PACKAGE_luci-app-qbittorrent=y CONFIG_PACKAGE_luci-app-ramfree=y +CONFIG_PACKAGE_luci-app-rtp2httpd=y CONFIG_PACKAGE_luci-app-samba4=y CONFIG_PACKAGE_luci-app-socat=y CONFIG_PACKAGE_luci-app-sqm=y From ebe1eb8eaa3aa6036e360e0b9ac2b34b364c6de4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 10 Dec 2025 19:15:08 +0800 Subject: [PATCH 317/425] Linux 6.18 designated as 2025 LTS Signed-off-by: sbwml --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9723b0c2b..945f8df66 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ --------------- -## 基于 Linux 6.12 LTS 固件下载: +## 基于 Linux 6.18 LTS 固件下载: #### NanoPi R4S: https://r4s.cooluc.com @@ -176,19 +176,19 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r4s ### nanopi-r5s/r5c ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r5s ``` ### nanopi-r76s ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r76s ``` ### x86_64 ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 x86_64 ``` @@ -196,25 +196,25 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 x86_64 ### nanopi-r4s ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r4s ``` ### nanopi-r5s/r5c ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r5s ``` ### nanopi-r76s ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://init2.cooluc.com/build.sh) dev nanopi-r76s ``` ### x86_64 ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 ``` @@ -245,19 +245,19 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 #### nanopi-r4s openwrt-24.10 ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 nanopi-r4s ``` #### nanopi-r5s/r5c openwrt-24.10 ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 nanopi-r5s ``` #### x86_64 openwrt-24.10 ```shell -# linux-6.12 +# linux-6.18 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 x86_64 ``` From 0b74d1f012aee69c20f2c0e6ece0f15a30f5ee9c Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 10 Dec 2025 20:10:02 +0800 Subject: [PATCH 318/425] build.sh: update ota url Signed-off-by: sbwml --- openwrt/build.sh | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 2d8c5b186..f85325e5e 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -37,9 +37,9 @@ ip_info=`curl -sk https://ip.cooluc.com`; # script url if [ "$isCN" = "CN" ]; then - export mirror=https://init3.cooluc.com + export mirror=https://init.cooluc.com else - export mirror=https://init3.cooluc.com + export mirror=https://init2.cooluc.com fi # github actions - caddy server @@ -502,9 +502,9 @@ if [ "$platform" = "x86_64" ]; then if [ "$1" = "rc2" ]; then mkdir -p ota if [ "$MINIMAL_BUILD" = "y" ]; then - OTA_URL="https://x86.cooluc.com/d/minimal/openwrt-24.10" + OTA_URL="https://dev.cooluc.com/minimal/x86_64" else - OTA_URL="https://github.com/sbwml/builder/releases/download" + OTA_URL="https://dev.cooluc.com/release/x86_64" fi VERSION=$(sed 's/v//g' version.txt) SHA256=$(sha256sum bin/targets/x86/64*/*-generic-squashfs-combined-efi.img.gz | awk '{print $1}') @@ -514,7 +514,7 @@ if [ "$platform" = "x86_64" ]; then { "build_date": "$CURRENT_DATE", "sha256sum": "$SHA256", - "url": "$OTA_URL/v$VERSION/openwrt-$VERSION-x86-64-generic-squashfs-combined-efi.img.gz" + "url": "$OTA_URL/openwrt-$VERSION-x86-64-generic-squashfs-combined-efi.img.gz" } ] } @@ -549,6 +549,11 @@ elif [ "$platform" = "armv8" ]; then # OTA json if [ "$1" = "rc2" ]; then mkdir -p ota + if [ "$MINIMAL_BUILD" = "y" ]; then + OTA_URL="https://dev.cooluc.com/minimal/armv8" + else + OTA_URL="https://dev.cooluc.com/release/armv8" + fi VERSION=$(sed 's/v//g' version.txt) SHA256=$(sha256sum bin/targets/armsr/armv8*/*-generic-squashfs-combined-efi.img.gz | awk '{print $1}') cat > ota/fw.json < ota/fw.json < ota/fw.json < ota/fw.json < Date: Sat, 13 Dec 2025 12:27:00 +0800 Subject: [PATCH 319/425] linux-6.18: bump to 6.18.1 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 3 +-- tags/kernel-6.18 | 4 ++-- tags/kernel-tag.sh | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 4f4c8dba3..b8ca7ba4a 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -15,7 +15,6 @@ fi # bpf-headers - 6.18 sed -ri "s/(PKG_PATCHVER:=)[^\"]*/\16.18/" package/kernel/bpf-headers/Makefile -sed -ri "s/tar.xz/tar.gz/" package/kernel/bpf-headers/Makefile curl -s $mirror/openwrt/patch/packages-patches/bpf-headers/900-fix-build.patch > package/kernel/bpf-headers/patches/900-fix-build.patch ## x86_64 - target 6.18 @@ -175,7 +174,7 @@ curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/fi # mac80211 - 6.18 rm -rf package/kernel/mac80211 -git clone https://$gitea/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.18 +git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.18 # ath10k-ct rm -rf package/kernel/ath10k-ct diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index f731e6879..22e76a734 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = -LINUX_KERNEL_HASH-6.18 = 9106a4605da9e31ff17659d958782b815f9591ab308d03b0ee21aad6c7dced4b +LINUX_VERSION-6.18 = .1 +LINUX_KERNEL_HASH-6.18.1 = d0a78bf3f0d12aaa10af3b5adcaed5bc767b5b78705e5ef885d5e930b72e25d5 diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index f526afa12..b2762e968 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -5,8 +5,8 @@ set -e ROOT="./" # LTS -KERNEL_VERSION=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "mainline") | .version'` -KERNEL_HASH=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "mainline") | .checksum'` +KERNEL_VERSION=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "stable") | .version' | tail -n1` +KERNEL_HASH=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "stable") | .checksum' | tail -n1` TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` [ -z $TAG ] && TAG="" || TAG=.$TAG From 916d3dbe57e273035f30291b7869f360ec241979 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 13 Dec 2025 18:17:30 +0800 Subject: [PATCH 320/425] v4l2loopback: fix build for linux 6.18 Signed-off-by: sbwml --- openwrt/6.18-disable-config | 3 -- openwrt/patch/packages-patches/README.md | 2 +- .../packages-patches/v4l2loopback/Makefile | 50 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 1 + openwrt/scripts/04-fix_kmod.sh | 5 ++ 5 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 openwrt/patch/packages-patches/v4l2loopback/Makefile diff --git a/openwrt/6.18-disable-config b/openwrt/6.18-disable-config index f07a6f9c4..f33afafb7 100644 --- a/openwrt/6.18-disable-config +++ b/openwrt/6.18-disable-config @@ -1,7 +1,4 @@ -# package/feeds/packages/v4l2loopback -# CONFIG_PACKAGE_kmod-v4l2loopback is not set - # package/new/shortcut-fe/shortcut-fe # CONFIG_PACKAGE_kmod-shortcut-fe is not set # CONFIG_PACKAGE_kmod-shortcut-fe-cm is not set diff --git a/openwrt/patch/packages-patches/README.md b/openwrt/patch/packages-patches/README.md index 42a5e6472..7f05e7e90 100644 --- a/openwrt/patch/packages-patches/README.md +++ b/openwrt/patch/packages-patches/README.md @@ -1 +1 @@ -### Fix build for linux-6.6 \ No newline at end of file +### Fix build for linux-6.18 diff --git a/openwrt/patch/packages-patches/v4l2loopback/Makefile b/openwrt/patch/packages-patches/v4l2loopback/Makefile new file mode 100644 index 000000000..19e12749d --- /dev/null +++ b/openwrt/patch/packages-patches/v4l2loopback/Makefile @@ -0,0 +1,50 @@ +# This software is in the public domain, furnished "as is", without technical +# support, and with no warranty, express or implied, as to its usefulness for +# any purpose. + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=v4l2loopback +PKG_VERSION:=0.15.3 +PKG_RELEASE:=1 + +PKG_SOURCE:=v4l2loopback-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/umlaeute/v4l2loopback/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=2758ea287da8dd34a0421c0dd50094a0342d22414e1bbccbbe92f41bbaa26b2d + +PKG_MAINTAINER:=Michel Promonet +PKG_CPE_ID:=cpe:/o:v4l2loopback_project:v4l2loopback + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/v4l2loopback + SUBMENU:=Video Support + TITLE:=v4l2loopback kernel module + FILES:=$(PKG_BUILD_DIR)/v4l2loopback.ko + DEPENDS:=+kmod-video-core + AUTOLOAD:=$(call AutoProbe,v4l2loopback) +endef + +define KernelPackage/v4l2loopback/description + This module allows you to create "virtual video devices". + Normal (v4l2) applications will read these devices as if + they were ordinary video devices, but the video will not be + read from e.g. a capture card but instead it is generated + by another application. +endef + +MAKE_OPTS:= \ + ARCH="$(LINUX_KARCH)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + M="$(PKG_BUILD_DIR)" + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + $(MAKE_OPTS) \ + CONFIG_PACKAGE_kmod-v4l2loopback=m \ + modules +endef + +$(eval $(call KernelPackage,v4l2loopback)) + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index fa37c31d3..4979846de 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -27,6 +27,7 @@ curl -s $mirror/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-m curl -s $mirror/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch | patch -p1 # add source mirror +#sed -i '/"@OPENWRT": \[/a\\t\t"https://sources-cdn-openwrt.cooluc.com",' scripts/projectsmirrors.json sed -i '/"@OPENWRT": \[/a\\t\t"https://source.cooluc.com",' scripts/projectsmirrors.json # attr no-mold diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index a12c8d6d3..a64bea05c 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -62,6 +62,11 @@ curl -s $mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_ # driver that is broken on 6.12 anyway. rm -rf feeds/packages/libs/xr_usb_serial_common +# v4l2loopback +rm -rf feeds/packages/kernel/v4l2loopback +mkdir -p feeds/packages/kernel/v4l2loopback +curl -s $mirror/openwrt/patch/packages-patches/v4l2loopback/Makefile > feeds/packages/kernel/v4l2loopback/Makefile + # xtables-addons curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch > feeds/packages/net/xtables-addons/patches/302-fix-build-for-linux-6.12rc2.patch From 0fdaec974074f8aa44326c7bd06dc10d85425293 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 13 Dec 2025 19:46:08 +0800 Subject: [PATCH 321/425] dahdi-linux: fix build for linux 6.18 Signed-off-by: sbwml --- openwrt/6.18-disable-config | 6 ------ openwrt/scripts/04-fix_kmod.sh | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/openwrt/6.18-disable-config b/openwrt/6.18-disable-config index f33afafb7..a6b200469 100644 --- a/openwrt/6.18-disable-config +++ b/openwrt/6.18-disable-config @@ -6,11 +6,5 @@ # package/new/shortcut-fe/fast-classifier # CONFIG_PACKAGE_kmod-fast-classifier is not set -# package/feeds/telephony/dahdi-linux -# CONFIG_PACKAGE_kmod-dahdi is not set -# CONFIG_PACKAGE_kmod-dahdi-dummy is not set -# CONFIG_PACKAGE_kmod-dahdi-echocan-oslec is not set -# CONFIG_PACKAGE_kmod-dahdi-hfcs is not set - # package/feeds/routing/batman-adv # CONFIG_PACKAGE_kmod-batman-adv is not set diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index a64bea05c..e6a45a7e8 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -75,7 +75,7 @@ curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for- pushd feeds/telephony # dahdi-linux rm -rf libs/dahdi-linux - git clone https://$github/sbwml/feeds_telephony_libs_dahdi-linux libs/dahdi-linux + git clone https://$github/sbwml/feeds_telephony_libs_dahdi-linux libs/dahdi-linux -b v6.18 popd # routing - batman-adv fix build with linux-6.12 From 76c7fd5744d030b126ed04e3f3f147e8f6d2b03f Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 17 Dec 2025 18:51:31 +0800 Subject: [PATCH 322/425] script: fix snapshot-24.10 Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index adfcbaa2e..2642f07df 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -43,8 +43,10 @@ rm -rf feeds/packages/utils/lrzsz git clone https://$github/sbwml/packages_utils_lrzsz package/new/lrzsz # irqbalance: disable build with numa -curl -s $mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch -sed -i '/-Dcapng=disabled/i\\t-Dnuma=disabled \\' feeds/packages/utils/irqbalance/Makefile +if [ "$version" = "rc2" ]; then + curl -s $mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch + sed -i '/-Dcapng=disabled/i\\t-Dnuma=disabled \\' feeds/packages/utils/irqbalance/Makefile +fi # frpc sed -i 's/procd_set_param stdout $stdout/procd_set_param stdout 0/g' feeds/packages/net/frp/files/frpc.init From 7e1ed039f7bddf422697a0bd83cefc7cf28b5b4f Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 17 Dec 2025 18:52:36 +0800 Subject: [PATCH 323/425] build: add openwrt-25.12 build keys Signed-off-by: sbwml --- openwrt/patch/key2.tar.gz | Bin 0 -> 771 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 openwrt/patch/key2.tar.gz diff --git a/openwrt/patch/key2.tar.gz b/openwrt/patch/key2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..81cd3e99da40337f32e2b7791e458961593c8401 GIT binary patch literal 771 zcmV+e1N{6SiwFP!000001MQSsbDBUD$9>*Uv9V4}nn5m#X*y$O5D^*U1*5q%ZJia6 z5ad#>#uQ3>DB?ZU305{_9mebUD)m4Bwt zOto5|S(>i1b(W!$b(*2-)dHk;mQjw-50D38!Joy};tzh??Effl_Q=rp$eCf2njOIz z@^1mqmagLkaLA22jbdp$7?Membi>xCs^O8hjvu5O-j`B`A^H}oR> z1o!u$wlo4r0g!BOln&fjJp|l{?@Wgr-{nN%JXu7s35j;OScYZtGe79JC2>0DMxrpD zuDg=(tLqtd087mGGJJ@0m_{a6uvl7i-Uxp#i3f-90Kf##O7k>qRa;i>e8+|^QcR?4 zeg&zs%mcY5v`kxF!jIW^3PE^|lY~w#vbJh!_dbyn`UQQUeVX&58&i=NN=6Oo0T1496VgZ@ceLAz=WR3XQGQ~68z$Yza zYD9KtBE56Py?>}sdPZ`t8d`1=aqf5)3gDx%z;C(0TMkZxr>7F=aZ?C*nyWnc)w~j& zYZncGq9#jO*T73l#`Z? zXBrg`?k`o%aC=~RDL2)lNnaZ{h+DM`5mBqr$%SvSSF6YfWl3)|K$fh~Z~gWTFJ0nS zO``vBwlI_(%73f=nL4wne~M Date: Fri, 19 Dec 2025 12:33:29 +0800 Subject: [PATCH 324/425] linux-6.18: bump to 6.18.2 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 22e76a734..7540006ec 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .1 -LINUX_KERNEL_HASH-6.18.1 = d0a78bf3f0d12aaa10af3b5adcaed5bc767b5b78705e5ef885d5e930b72e25d5 +LINUX_VERSION-6.18 = .2 +LINUX_KERNEL_HASH-6.18.2 = 558c6bbab749492b34f99827fe807b0039a744693c21d3a7e03b3a48edaab96a From 0926b0009da082c4a603c57bec49552e180c4331 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 19 Dec 2025 12:33:46 +0800 Subject: [PATCH 325/425] OpenWrt 24.10.5 Signed-off-by: sbwml --- openwrt/patch/irqbalance/011-meson-numa.patch | 26 ------------------- openwrt/scripts/02-prepare_package.sh | 6 ----- openwrt/scripts/05-fix-source.sh | 7 +++++ tags/v24 | 2 +- 4 files changed, 8 insertions(+), 33 deletions(-) delete mode 100644 openwrt/patch/irqbalance/011-meson-numa.patch diff --git a/openwrt/patch/irqbalance/011-meson-numa.patch b/openwrt/patch/irqbalance/011-meson-numa.patch deleted file mode 100644 index 33582fe8e..000000000 --- a/openwrt/patch/irqbalance/011-meson-numa.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- a/meson.build -+++ b/meson.build -@@ -10,11 +10,12 @@ m_dep = cc.find_library('m', required: false) - capng_dep = dependency('libcap-ng', required: get_option('capng')) - ncurses_dep = dependency('curses', required: get_option('ui')) - systemd_dep = dependency('libsystemd', required: get_option('systemd')) -+numa_dep = dependency('libnuma', required: get_option('numa')) - - cdata = configuration_data() - cdata.set('HAVE_GETOPT_LONG', cc.has_function('getopt_long')) - cdata.set('HAVE_IRQBALANCEUI', ncurses_dep.found()) --cdata.set('HAVE_NUMA_H', cc.has_header('numa.h')) -+cdata.set('HAVE_NUMA_H', numa_dep.found()) - cdata.set('HAVE_LIBCAP_NG', capng_dep.found()) - cdata.set('HAVE_LIBSYSTEMD', systemd_dep.found()) - cdata.set_quoted('VERSION', meson.project_version()) ---- a/meson_options.txt -+++ b/meson_options.txt -@@ -9,3 +9,7 @@ option('systemd', type : 'feature', - option('ui', type : 'feature', - description : 'Build the UI component', - ) -+ -+option('numa', type : 'feature', -+ description : 'Build with numa support', -+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 2642f07df..32963df9d 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -42,12 +42,6 @@ curl -s $mirror/openwrt/patch/pcre/Config.in > package/libs/pcre/Config.in rm -rf feeds/packages/utils/lrzsz git clone https://$github/sbwml/packages_utils_lrzsz package/new/lrzsz -# irqbalance: disable build with numa -if [ "$version" = "rc2" ]; then - curl -s $mirror/openwrt/patch/irqbalance/011-meson-numa.patch > feeds/packages/utils/irqbalance/patches/011-meson-numa.patch - sed -i '/-Dcapng=disabled/i\\t-Dnuma=disabled \\' feeds/packages/utils/irqbalance/Makefile -fi - # frpc sed -i 's/procd_set_param stdout $stdout/procd_set_param stdout 0/g' feeds/packages/net/frp/files/frpc.init sed -i 's/procd_set_param stderr $stderr/procd_set_param stderr 0/g' feeds/packages/net/frp/files/frpc.init diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 9bc01592d..70d0b7bad 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,5 +1,12 @@ #!/bin/bash +# 24.10 xcrypt +if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then + git clone https://github.com/openwrt/openwrt -b openwrt-25.12 --depth=1 openwrt-25.12 + mv openwrt-25.12/package/libs/xcrypt package/libs + rm -rf openwrt-25.12 +fi + # apk-tools curl -s $mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch diff --git a/tags/v24 b/tags/v24 index 986f41dfb..c1a8e0edf 100644 --- a/tags/v24 +++ b/tags/v24 @@ -1 +1 @@ -24.10.4 +24.10.5 From 82c0284afb22c97ad55df1edd4238a026614de61 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 26 Dec 2025 13:05:07 +0800 Subject: [PATCH 326/425] init openwrt-25.12 Signed-off-by: sbwml --- README.md | 18 +- .../{24-config-common => 25-config-common} | 0 ...inimal-common => 25-config-minimal-common} | 0 ...armsr-armv8 => 25-config-musl-armsr-armv8} | 0 ...{24-config-musl-r4s => 25-config-musl-r4s} | 2 +- ...{24-config-musl-r5s => 25-config-musl-r5s} | 2 +- ...4-config-musl-r76s => 25-config-musl-r76s} | 0 ...{24-config-musl-x86 => 25-config-musl-x86} | 0 ...config-std-common => 25-config-std-common} | 0 openwrt/build.sh | 85 +- ... => 999-hack-for-linux-pre-releases.patch} | 4 +- .../0001-fix-cgroupfs-mount.patch | 26 - ...2-hierarchy-to-sys-fs-cgroup-cgroup2.patch | 29 - .../901-fix-cgroupfs-umount.patch | 29 - ...oup-systemd-for-docker-systemd-suppo.patch | 29 - .../001-fix-fw4-flow-offload.patch | 2 +- ....uc-adept-kernel-version-type-of-x.x.patch | 23 - ...0-fw4-add-custom-nft-command-support.patch | 30 + ...99-01-firewall4-add-fullcone-support.patch | 34 +- ...irewall4-add-bcm-fullconenat-support.patch | 12 +- ...ftnl-add-fullcone-expression-support.patch | 6 +- ...2-libnftnl-add-brcm-fullcone-support.patch | 18 +- ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 0 ...-app-firewall-add-shortcut-fe-option.patch | 0 ...uci-app-firewall-add-ipv6-nat-option.patch | 0 ...firewall-add-custom-nft-rule-support.patch | 0 ...firewall-add-natflow-offload-support.patch | 0 ...l-enable-hardware-offload-only-on-de.patch | 0 ...l-add-fullcone6-option-for-nftables-.patch | 0 ...bles-add-fullcone-expression-support.patch | 20 +- ...ftables-add-brcm-fullconenat-support.patch | 26 +- .../nftables/0003-drop-rej-file.patch | 29 - ...d-legacy-cgroup-v1-memory-controller.patch | 34 - ...hfs4-enable-zstd-compression-support.patch | 124 -- ...toolchain-gcc-add-support-for-GCC-15.patch | 800 -------- .../0001-tools-add-upx-tools.patch | 8 +- ...2-rootfs-add-upx-compression-support.patch | 8 +- ...ermissions-for-UCI-configuration-fil.patch | 8 +- ...rt-for-local-kmod-installation-sourc.patch | 12 +- ...-Add-support-for-llvm-clang-compiler.patch | 10 +- ...kernel-add-out-of-tree-kernel-config.patch | 12 +- ...ernel-add-miss-config-for-linux-6.11.patch | 8 +- ...rm-variable-to-cross-compilation-fil.patch | 8 +- ...-enable-lz4-zstd-compression-support.patch | 29 + ...REEMPT_RT-support-for-aarch64-x86_64.patch | 6 +- ...age-add-support-for-squashfs-zstd-c.patch} | 25 +- ...ernel-Always-collect-module-symvers.patch} | 4 +- ...-update-kernel-config-options-for-l.patch} | 10 +- ...ss-output-TCP-BBRv3-diag-information.patch | 158 -- ...roduce-the-ecn_low-per-route-feature.patch | 114 -- ...ow-if-tcp_info-tcpi_options-TCPI_OPT.patch | 52 - .../linux-6.18-target-linux-generic.patch | 339 ++-- openwrt/patch/key.tar.gz | Bin 1424 -> 0 bytes openwrt/patch/key2.tar.gz | Bin 771 -> 773 bytes ...m-add-modal-overlay-dialog-to-reboot.patch | 6 +- ...displays-actual-process-memory-usage.patch | 8 +- ...storage-index-applicable-only-to-val.patch | 6 +- ...firewall-disable-legacy-firewall-rul.patch | 12 +- ...-system-add-refresh-interval-setting.patch | 10 +- ...mounts-add-docker-directory-mount-po.patch | 4 +- ...add-ucitrack-luci-mod-system-zram.js.patch | 6 +- ...s-IV-to-EVP_CipherInit_ex-for-evp-ru.patch | 22 - ...d.c-Fix-the-benchmarking-for-AEAD-ci.patch | 488 ----- ...-Add-support-for-BoringSSL-QUIC-APIs.patch | 1746 ----------------- ...New-method-to-get-QUIC-secret-length.patch | 90 - ...ake-temp-secret-names-less-confusing.patch | 71 - ...ransport-params-to-encrypted-extensi.patch | 21 - ...UIC-Use-proper-secrets-for-handshake.patch | 50 - ...IC-Handle-partial-handshake-messages.patch | 67 - ...-quic_transport-constructors-parsers.patch | 82 - ...state-in-SSL_process_quic_post_hands.patch | 34 - ...-Don-t-process-an-incomplete-message.patch | 46 - ...uick-fix-s2c-to-c2s-for-early-secret.patch | 20 - ...-client-early-traffic-secret-storage.patch | 43 - ...012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch | 23 - ...C-Correctly-disable-middlebox-compat.patch | 29 - ...ode-out-of-tls13_change_cipher_state.patch | 327 --- ...C-Tweeks-to-quic_change_cipher_state.patch | 121 -- ...16-QUIC-Add-support-for-more-secrets.patch | 39 - .../0017-QUIC-Fix-resumption-secret.patch | 49 - ...ndle-EndOfEarlyData-and-MaxEarlyData.patch | 87 - .../0019-QUIC-Fall-through-for-0RTT.patch | 26 - ...me-cleanup-for-the-main-QUIC-changes.patch | 640 ------ ...0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch | 70 - .../0022-QUIC-Test-KeyUpdate-rejection.patch | 32 - ...3-QUIC-Buffer-all-provided-quic-data.patch | 208 -- ...sistent-encryption-level-for-handsha.patch | 51 - ...UIC-add-v1-quic_transport_parameters.patch | 634 ------ ...-success-when-no-post-handshake-data.patch | 22 - ...akes-no-sense-for-void-return-values.patch | 20 - ...-remove-SSL_R_BAD_DATA_LENGTH-unused.patch | 41 - ...29-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch | 152 -- ...d-compile-run-time-checking-for-QUIC.patch | 90 - .../0031-QUIC-Add-early-data-support.patch | 485 ----- ...ovide_quic_data-accept-0-length-data.patch | 23 - ...tiple-post-handshake-messages-in-a-s.patch | 68 - .../patch/openssl/quic/0034-QUIC-Fix-CI.patch | 84 - ...QUIC-Break-up-header-body-processing.patch | 136 -- ...-QUIC-Don-t-muck-with-FIPS-checksums.patch | 113 -- .../0037-QUIC-Update-RFC-references.patch | 99 - .../0038-QUIC-revert-white-space-change.patch | 19 - ...-QUIC-use-SSL_IS_QUIC-in-more-places.patch | 44 - ...rror-when-non-empty-session_id-in-CH.patch | 27 - ...-Update-SSL_clear-to-clear-quic-data.patch | 130 -- .../quic/0042-QUIC-Better-SSL_clear.patch | 206 -- .../quic/0043-QUIC-Fix-extension-test.patch | 39 - .../0044-QUIC-Update-metadata-version.patch | 5 - .../gmp/001-fix-build-with-gcc-15.patch | 11 - openwrt/patch/openwrt-6.x/gcc-15/README.md | 1 - ...string-initialization-error-on-gcc15.patch | 40 - ...string-initialization-error-on-gcc15.patch | 15 - ...string-initialization-error-on-gcc15.patch | 26 - .../patch/openwrt-6.x/modules/bluetooth.mk | 165 ++ openwrt/patch/openwrt-6.x/modules/fs.mk | 85 +- openwrt/patch/openwrt-6.x/modules/gpio.mk | 17 + openwrt/patch/openwrt-6.x/modules/hwmon.mk | 26 +- openwrt/patch/openwrt-6.x/modules/i2c.mk | 74 +- openwrt/patch/openwrt-6.x/modules/iio.mk | 52 + openwrt/patch/openwrt-6.x/modules/input.mk | 102 + openwrt/patch/openwrt-6.x/modules/leds.mk | 34 + openwrt/patch/openwrt-6.x/modules/lib.mk | 29 - .../patch/openwrt-6.x/modules/netdevices.mk | 385 +++- .../patch/openwrt-6.x/modules/netsupport.mk | 16 - openwrt/patch/openwrt-6.x/modules/other.mk | 169 +- openwrt/patch/openwrt-6.x/modules/rtc.mk | 18 + openwrt/patch/openwrt-6.x/modules/spi.mk | 38 + openwrt/patch/openwrt-6.x/modules/usb.mk | 113 +- openwrt/patch/openwrt-6.x/modules/video.mk | 164 +- openwrt/patch/openwrt-6.x/modules/w1.mk | 16 + .../901-fix-linux-6.12rc2-builds.patch | 16 - .../openwrt-fix-build-with-clang.patch | 20 + ..._verbosity-sysctl-for-Linux-6.11-rc1.patch | 37 - ...xclude-unused-struct-since-Linux-6.5.patch | 58 - .../gpio-button-hotplug/fix-linux-6.12.patch | 35 - .../gpio-button-hotplug/fix-linux-6.18.patch | 29 + .../900-meson-add-numa-option.patch | 38 + .../nat46/100-fix-build-with-kernel-6.9.patch | 74 - .../101-fix-build-with-kernel-6.12.patch | 14 - .../102-fix-build-with-kernel-6.18.patch | 13 +- .../900-fix-linux-6.12-11.5.1.18.patch | 13 - .../901-fix-build-for-linux-6.18.patch | 12 +- ...inter-type-error-for-signal-function.patch | 11 - .../010-fix-build-for-linux-6.18.patch | 12 + ...nv_remove-return-void-for-linux-6.12.patch | 33 - .../301-fix-build-with-linux-6.12.patch | 15 - .../302-fix-build-for-linux-6.12rc2.patch | 14 - .../target-modify_for_aarch64_x86_64.patch | 6 +- ...vim-fix-renamed-defaults-config-file.patch | 75 - openwrt/scripts/00-prepare_base.sh | 132 +- openwrt/scripts/01-prepare_base-mainline.sh | 32 +- openwrt/scripts/02-prepare_package.sh | 3 +- openwrt/scripts/04-fix_kmod.sh | 22 +- openwrt/scripts/05-fix-source.sh | 105 +- tags/openwrt-tag.sh | 2 +- tags/v24 | 1 - tags/v25 | 1 + 156 files changed, 1725 insertions(+), 9858 deletions(-) rename openwrt/{24-config-common => 25-config-common} (100%) rename openwrt/{24-config-minimal-common => 25-config-minimal-common} (100%) rename openwrt/{24-config-musl-armsr-armv8 => 25-config-musl-armsr-armv8} (100%) rename openwrt/{24-config-musl-r4s => 25-config-musl-r4s} (96%) rename openwrt/{24-config-musl-r5s => 25-config-musl-r5s} (96%) rename openwrt/{24-config-musl-r76s => 25-config-musl-r76s} (100%) rename openwrt/{24-config-musl-x86 => 25-config-musl-x86} (100%) rename openwrt/{24-config-std-common => 25-config-std-common} (100%) rename openwrt/patch/apk-tools/{9999-hack-for-linux-pre-releases.patch => 999-hack-for-linux-pre-releases.patch} (79%) delete mode 100644 openwrt/patch/cgroupfs-mount/0001-fix-cgroupfs-mount.patch delete mode 100644 openwrt/patch/cgroupfs-mount/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch delete mode 100644 openwrt/patch/cgroupfs-mount/901-fix-cgroupfs-umount.patch delete mode 100644 openwrt/patch/cgroupfs-mount/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch delete mode 100644 openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch create mode 100644 openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch rename openwrt/patch/firewall4/{luci-24.10 => luci-25.12}/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch (100%) rename openwrt/patch/firewall4/{luci-24.10 => luci-25.12}/0002-luci-app-firewall-add-shortcut-fe-option.patch (100%) rename openwrt/patch/firewall4/{luci-24.10 => luci-25.12}/0003-luci-app-firewall-add-ipv6-nat-option.patch (100%) rename openwrt/patch/firewall4/{luci-24.10 => luci-25.12}/0004-luci-add-firewall-add-custom-nft-rule-support.patch (100%) rename openwrt/patch/firewall4/{luci-24.10 => luci-25.12}/0005-luci-app-firewall-add-natflow-offload-support.patch (100%) rename openwrt/patch/firewall4/{luci-24.10 => luci-25.12}/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch (100%) rename openwrt/patch/firewall4/{luci-24.10 => luci-25.12}/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch (100%) delete mode 100644 openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch delete mode 100644 openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch delete mode 100644 openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch delete mode 100644 openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch rename openwrt/patch/{generic-24.10 => generic-25.12}/0001-tools-add-upx-tools.patch (89%) rename openwrt/patch/{generic-24.10 => generic-25.12}/0002-rootfs-add-upx-compression-support.patch (83%) rename openwrt/patch/{generic-24.10 => generic-25.12}/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch (74%) rename openwrt/patch/{generic-24.10 => generic-25.12}/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch (83%) rename openwrt/patch/{generic-24.10 => generic-25.12}/0005-kernel-Add-support-for-llvm-clang-compiler.patch (90%) rename openwrt/patch/{generic-24.10 => generic-25.12}/0006-build-kernel-add-out-of-tree-kernel-config.patch (95%) rename openwrt/patch/{generic-24.10 => generic-25.12}/0007-include-kernel-add-miss-config-for-linux-6.11.patch (78%) rename openwrt/patch/{generic-24.10 => generic-25.12}/0008-meson-add-platform-variable-to-cross-compilation-fil.patch (82%) create mode 100644 openwrt/patch/generic-25.12/0009-tools-squashfs4-enable-lz4-zstd-compression-support.patch rename openwrt/patch/{generic-24.10 => generic-25.12}/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch (88%) rename openwrt/patch/{generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch => generic-25.12/0011-config-include-image-add-support-for-squashfs-zstd-c.patch} (61%) rename openwrt/patch/{generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch => generic-25.12/0012-include-kernel-Always-collect-module-symvers.patch} (90%) rename openwrt/patch/{generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch => generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch} (82%) delete mode 100644 openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch delete mode 100644 openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch delete mode 100644 openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch delete mode 100644 openwrt/patch/key.tar.gz delete mode 100644 openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch delete mode 100644 openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch delete mode 100644 openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch delete mode 100644 openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch delete mode 100644 openwrt/patch/openssl/quic/0003-QUIC-Make-temp-secret-names-less-confusing.patch delete mode 100644 openwrt/patch/openssl/quic/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch delete mode 100644 openwrt/patch/openssl/quic/0005-QUIC-Use-proper-secrets-for-handshake.patch delete mode 100644 openwrt/patch/openssl/quic/0006-QUIC-Handle-partial-handshake-messages.patch delete mode 100644 openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch delete mode 100644 openwrt/patch/openssl/quic/0008-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch delete mode 100644 openwrt/patch/openssl/quic/0009-QUIC-Don-t-process-an-incomplete-message.patch delete mode 100644 openwrt/patch/openssl/quic/0010-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch delete mode 100644 openwrt/patch/openssl/quic/0011-QUIC-Add-client-early-traffic-secret-storage.patch delete mode 100644 openwrt/patch/openssl/quic/0012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch delete mode 100644 openwrt/patch/openssl/quic/0013-QUIC-Correctly-disable-middlebox-compat.patch delete mode 100644 openwrt/patch/openssl/quic/0014-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch delete mode 100644 openwrt/patch/openssl/quic/0015-QUIC-Tweeks-to-quic_change_cipher_state.patch delete mode 100644 openwrt/patch/openssl/quic/0016-QUIC-Add-support-for-more-secrets.patch delete mode 100644 openwrt/patch/openssl/quic/0017-QUIC-Fix-resumption-secret.patch delete mode 100644 openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch delete mode 100644 openwrt/patch/openssl/quic/0019-QUIC-Fall-through-for-0RTT.patch delete mode 100644 openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch delete mode 100644 openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch delete mode 100644 openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch delete mode 100644 openwrt/patch/openssl/quic/0023-QUIC-Buffer-all-provided-quic-data.patch delete mode 100644 openwrt/patch/openssl/quic/0024-QUIC-Enforce-consistent-encryption-level-for-handsha.patch delete mode 100644 openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch delete mode 100644 openwrt/patch/openssl/quic/0026-QUIC-return-success-when-no-post-handshake-data.patch delete mode 100644 openwrt/patch/openssl/quic/0027-QUIC-__owur-makes-no-sense-for-void-return-values.patch delete mode 100644 openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch delete mode 100644 openwrt/patch/openssl/quic/0029-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch delete mode 100644 openwrt/patch/openssl/quic/0030-QUIC-Add-compile-run-time-checking-for-QUIC.patch delete mode 100644 openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch delete mode 100644 openwrt/patch/openssl/quic/0032-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch delete mode 100644 openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch delete mode 100644 openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch delete mode 100644 openwrt/patch/openssl/quic/0035-QUIC-Break-up-header-body-processing.patch delete mode 100644 openwrt/patch/openssl/quic/0036-QUIC-Don-t-muck-with-FIPS-checksums.patch delete mode 100644 openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch delete mode 100644 openwrt/patch/openssl/quic/0038-QUIC-revert-white-space-change.patch delete mode 100644 openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch delete mode 100644 openwrt/patch/openssl/quic/0040-QUIC-Error-when-non-empty-session_id-in-CH.patch delete mode 100644 openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch delete mode 100644 openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch delete mode 100644 openwrt/patch/openssl/quic/0043-QUIC-Fix-extension-test.patch delete mode 100644 openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-15/README.md delete mode 100644 openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch delete mode 100644 openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch create mode 100644 openwrt/patch/openwrt-6.x/modules/bluetooth.mk delete mode 100644 openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch create mode 100644 openwrt/patch/packages-patches/clang/linux-atm/openwrt-fix-build-with-clang.patch delete mode 100644 openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch delete mode 100644 openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch delete mode 100644 openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch create mode 100644 openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.18.patch create mode 100644 openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch delete mode 100644 openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch delete mode 100644 openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch delete mode 100644 openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch delete mode 100644 openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch create mode 100644 openwrt/patch/packages-patches/ubootenv-nvram/010-fix-build-for-linux-6.18.patch delete mode 100644 openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch delete mode 100644 openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch delete mode 100644 openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch delete mode 100644 openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch delete mode 100644 tags/v24 create mode 100644 tags/v25 diff --git a/README.md b/README.md index 945f8df66..532105b7b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ #### X86_64: https://x86.cooluc.com -#### Snapshot 24.10: https://snapshot.cooluc.com +#### Snapshot 25.12: https://snapshot.cooluc.com #### 构建来源: https://github.com/sbwml/builder @@ -92,9 +92,9 @@ export ENABLE_BPF=y export ENABLE_LRNG=y ``` -### 启用 [Glibc](https://www.gnu.org/software/libc/) 库构建 (实验性) -##### 启用 glibc 库进行构建时,构建的固件将会同时兼容 musl/glibc 的预构建二进制程序,但缺失 `opkg install` 安装源支持 -##### 只需在构建固件前执行以下命令即可启用 glibc 构建 +### ~~启用 [Glibc](https://www.gnu.org/software/libc/) 库构建 (实验性)~~ +##### ~~启用 glibc 库进行构建时,构建的固件将会同时兼容 musl/glibc 的预构建二进制程序,但缺失 `apk install` 安装源支持~~ +##### ~~只需在构建固件前执行以下命令即可启用 glibc 构建~~ ``` export ENABLE_GLIBC=y @@ -166,7 +166,7 @@ export NO_KMOD=y --------------- -## 构建 OpenWrt 24.10 最新 Releases +## 构建 OpenWrt 25.12 最新 Releases ### nanopi-r4s ```shell @@ -192,7 +192,7 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 nanopi-r76s bash <(curl -sS https://init2.cooluc.com/build.sh) rc2 x86_64 ``` -## 构建 OpenWrt 24.10 开发版(24.10-SNAPSHOT) +## 构建 OpenWrt 25.12 开发版(25.12-SNAPSHOT) ### nanopi-r4s ```shell @@ -243,19 +243,19 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 ### 三、在本地 Linux 执行基于你自己仓库的构建脚本,即可编译所需固件 -#### nanopi-r4s openwrt-24.10 +#### nanopi-r4s openwrt-25.12 ```shell # linux-6.18 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 nanopi-r4s ``` -#### nanopi-r5s/r5c openwrt-24.10 +#### nanopi-r5s/r5c openwrt-25.12 ```shell # linux-6.18 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 nanopi-r5s ``` -#### x86_64 openwrt-24.10 +#### x86_64 openwrt-25.12 ```shell # linux-6.18 bash <(curl -sS https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master/openwrt/build.sh) rc2 x86_64 diff --git a/openwrt/24-config-common b/openwrt/25-config-common similarity index 100% rename from openwrt/24-config-common rename to openwrt/25-config-common diff --git a/openwrt/24-config-minimal-common b/openwrt/25-config-minimal-common similarity index 100% rename from openwrt/24-config-minimal-common rename to openwrt/25-config-minimal-common diff --git a/openwrt/24-config-musl-armsr-armv8 b/openwrt/25-config-musl-armsr-armv8 similarity index 100% rename from openwrt/24-config-musl-armsr-armv8 rename to openwrt/25-config-musl-armsr-armv8 diff --git a/openwrt/24-config-musl-r4s b/openwrt/25-config-musl-r4s similarity index 96% rename from openwrt/24-config-musl-r4s rename to openwrt/25-config-musl-r4s index 0bd813d9e..bacf85ebf 100644 --- a/openwrt/24-config-musl-r4s +++ b/openwrt/25-config-musl-r4s @@ -18,7 +18,7 @@ CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y -CONFIG_TARGET_KERNEL_PARTSIZE=16 +CONFIG_TARGET_KERNEL_PARTSIZE=32 CONFIG_TARGET_ROOTFS_PARTSIZE=944 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r5s b/openwrt/25-config-musl-r5s similarity index 96% rename from openwrt/24-config-musl-r5s rename to openwrt/25-config-musl-r5s index c5224bfee..ded403445 100644 --- a/openwrt/24-config-musl-r5s +++ b/openwrt/25-config-musl-r5s @@ -20,7 +20,7 @@ CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y CONFIG_PACKAGE_coremark=y CONFIG_PACKAGE_default-settings=y -CONFIG_TARGET_KERNEL_PARTSIZE=16 +CONFIG_TARGET_KERNEL_PARTSIZE=32 CONFIG_TARGET_ROOTFS_PARTSIZE=944 CONFIG_COREMARK_NUMBER_OF_THREADS=6 # CONFIG_KERNEL_KALLSYMS is not set diff --git a/openwrt/24-config-musl-r76s b/openwrt/25-config-musl-r76s similarity index 100% rename from openwrt/24-config-musl-r76s rename to openwrt/25-config-musl-r76s diff --git a/openwrt/24-config-musl-x86 b/openwrt/25-config-musl-x86 similarity index 100% rename from openwrt/24-config-musl-x86 rename to openwrt/25-config-musl-x86 diff --git a/openwrt/24-config-std-common b/openwrt/25-config-std-common similarity index 100% rename from openwrt/24-config-std-common rename to openwrt/25-config-std-common diff --git a/openwrt/build.sh b/openwrt/build.sh index f85325e5e..ee7fbd418 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -36,11 +36,7 @@ ip_info=`curl -sk https://ip.cooluc.com`; [ -n "$ip_info" ] && export isCN=`echo $ip_info | grep -Po 'country_code\":"\K[^"]+'` || export isCN=US # script url -if [ "$isCN" = "CN" ]; then - export mirror=https://init.cooluc.com -else - export mirror=https://init2.cooluc.com -fi +export mirror=https://init.cooluc.com # github actions - caddy server if [ "$(whoami)" = "runner" ] && [ "$git_name" != "private" ]; then @@ -92,10 +88,10 @@ fi # Source branch if [ "$1" = "dev" ]; then - export branch=openwrt-24.10 + export branch=openwrt-25.12 export version=dev elif [ "$1" = "rc2" ]; then - latest_release="v$(curl -s $mirror/tags/v24)" + latest_release="v$(curl -s $mirror/tags/v25)" export branch=$latest_release export version=rc2 fi @@ -136,7 +132,7 @@ elif [ "$USE_GCC14" = y ]; then elif [ "$USE_GCC15" = y ]; then export USE_GCC15=y gcc_version=15 else - export USE_GCC14=y gcc_version=14 + export USE_GCC15=y gcc_version=15 fi [ "$ENABLE_MOLD" = y ] && export ENABLE_MOLD=y @@ -224,7 +220,7 @@ git clone https://$github/immortalwrt/packages master/immortalwrt_packages --dep if [ -d openwrt ]; then cd openwrt - curl -Os $mirror/openwrt/patch/key.tar.gz && tar zxf key.tar.gz && rm -f key.tar.gz + curl -Os $mirror/openwrt/patch/key2.tar.gz && tar zxf key2.tar.gz && rm -f key2.tar.gz else echo -e "${RED_COLOR}Failed to download source code${RES}" exit 1 @@ -307,25 +303,25 @@ rm -rf ../master # Load devices Config if [ "$platform" = "x86_64" ]; then - curl -s $mirror/openwrt/24-config-musl-x86 > .config + curl -s $mirror/openwrt/25-config-musl-x86 > .config elif [ "$platform" = "rk3568" ]; then - curl -s $mirror/openwrt/24-config-musl-r5s > .config + curl -s $mirror/openwrt/25-config-musl-r5s > .config elif [ "$platform" = "rk3576" ]; then - curl -s $mirror/openwrt/24-config-musl-r76s > .config + curl -s $mirror/openwrt/25-config-musl-r76s > .config elif [ "$platform" = "armv8" ]; then - curl -s $mirror/openwrt/24-config-musl-armsr-armv8 > .config + curl -s $mirror/openwrt/25-config-musl-armsr-armv8 > .config else - curl -s $mirror/openwrt/24-config-musl-r4s > .config + curl -s $mirror/openwrt/25-config-musl-r4s > .config fi # config-common if [ "$MINIMAL_BUILD" = "y" ]; then - curl -s $mirror/openwrt/24-config-minimal-common >> .config + curl -s $mirror/openwrt/25-config-minimal-common >> .config echo 'VERSION_TYPE="minimal"' >> package/base-files/files/usr/lib/os-release elif [ "$STD_BUILD" = "y" ]; then - curl -s $mirror/openwrt/24-config-std-common >> .config + curl -s $mirror/openwrt/25-config-std-common >> .config else - curl -s $mirror/openwrt/24-config-common >> .config + curl -s $mirror/openwrt/25-config-common >> .config [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi @@ -383,16 +379,11 @@ if [ "$ENABLE_LOCAL_KMOD" = "y" ]; then echo "CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES=y" >> .config fi -# gcc15 patches -[ "$(whoami)" = "runner" ] && group "patching toolchain" -curl -s $mirror/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch | patch -p1 - # gcc config echo -e "\n# gcc ${gcc_version}" >> .config echo -e "CONFIG_DEVEL=y" >> .config echo -e "CONFIG_TOOLCHAINOPTS=y" >> .config echo -e "CONFIG_GCC_USE_VERSION_${gcc_version}=y\n" >> .config -[ "$(whoami)" = "runner" ] && endgroup # uhttpd [ "$ENABLE_UHTTPD" = "y" ] && sed -i '/nginx/d' .config && echo 'CONFIG_PACKAGE_ariang=y' >> .config @@ -427,7 +418,7 @@ if [ "$BUILD_FAST" = "y" ]; then if [ "$PLATFORM_ID" = "platform:el9" ]; then TOOLCHAIN_URL="http://127.0.0.1:8080" else - TOOLCHAIN_URL=https://"$github_proxy"github.com/sbwml/openwrt_caches/releases/download/openwrt-24.10 + TOOLCHAIN_URL=https://"$github_proxy"github.com/sbwml/openwrt_caches/releases/download/openwrt-25.12 fi curl -L ${TOOLCHAIN_URL}/toolchain_${LIBC}_${toolchain_arch}_gcc-${gcc_version}${tools_suffix}.tar.zst -o toolchain.tar.zst $CURL_BAR echo -e "\n${GREEN_COLOR}Process Toolchain ...${RES}" @@ -482,17 +473,17 @@ if [ "$platform" = "x86_64" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/x86_64/base/rtl88*a-firmware*.ipk $kmodpkg_name/ - cp -a bin/packages/x86_64/base/natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/rtl88*a-firmware*.apk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/natflow*.apk $kmodpkg_name/ || true [ "$OPENWRT_CORE" = "y" ] && { - cp -a bin/packages/x86_64/base/*3ginfo*.ipk $kmodpkg_name/ - cp -a bin/packages/x86_64/base/*modemband*.ipk $kmodpkg_name/ - cp -a bin/packages/x86_64/base/*sms-tool*.ipk $kmodpkg_name/ - cp -a bin/packages/x86_64/base/*quectel*.ipk $kmodpkg_name/ + cp -a bin/packages/x86_64/base/*3ginfo*.apk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/*modemband*.apk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/*sms-tool*.apk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/*quectel*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { - cp -a bin/packages/x86_64/base/*dpdk*.ipk $kmodpkg_name/ || true - cp -a bin/packages/x86_64/base/*numa*.ipk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/*dpdk*.apk $kmodpkg_name/ || true + cp -a bin/packages/x86_64/base/*numa*.apk $kmodpkg_name/ || true } bash kmod-sign $kmodpkg_name tar zcf x86_64-$kmodpkg_name.tar.gz $kmodpkg_name @@ -530,17 +521,17 @@ elif [ "$platform" = "armv8" ]; then if [ "$NO_KMOD" != "y" ]; then cp -a bin/targets/armsr/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true [ "$OPENWRT_CORE" = "y" ] && { - cp -a bin/packages/aarch64_generic/base/*3ginfo*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*modemband*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*sms-tool*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*quectel*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*3ginfo*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*modemband*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*sms-tool*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*quectel*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { - cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true - cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*dpdk*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*numa*.apk $kmodpkg_name/ || true } bash kmod-sign $kmodpkg_name tar zcf armv8-$kmodpkg_name.tar.gz $kmodpkg_name @@ -573,17 +564,17 @@ else if [ "$NO_KMOD" != "y" ] && [ "$platform" != "rk3399" ]; then cp -a bin/targets/rockchip/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* - cp -a bin/packages/aarch64_generic/base/rtl88*-firmware*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/natflow*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/rtl88*-firmware*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true [ "$OPENWRT_CORE" = "y" ] && { - cp -a bin/packages/aarch64_generic/base/*3ginfo*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*modemband*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*sms-tool*.ipk $kmodpkg_name/ - cp -a bin/packages/aarch64_generic/base/*quectel*.ipk $kmodpkg_name/ + cp -a bin/packages/aarch64_generic/base/*3ginfo*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*modemband*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*sms-tool*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*quectel*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { - cp -a bin/packages/aarch64_generic/base/*dpdk*.ipk $kmodpkg_name/ || true - cp -a bin/packages/aarch64_generic/base/*numa*.ipk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*dpdk*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/*numa*.apk $kmodpkg_name/ || true } bash kmod-sign $kmodpkg_name tar zcf aarch64-$kmodpkg_name.tar.gz $kmodpkg_name diff --git a/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch b/openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch similarity index 79% rename from openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch rename to openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch index 55fdbdd55..2355c9a86 100644 --- a/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch +++ b/openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch @@ -1,6 +1,6 @@ --- a/src/apk_adb.c +++ b/src/apk_adb.c -@@ -177,7 +177,6 @@ static struct adb_scalar_schema scalar_n +@@ -194,7 +194,6 @@ static struct adb_scalar_schema scalar_name = { static adb_val_t version_fromstring(struct adb *db, apk_blob_t val) { @@ -8,7 +8,7 @@ return adb_w_blob(db, val); } -@@ -338,12 +337,6 @@ static int dependency_fromstring(struct +@@ -355,12 +354,6 @@ static int dependency_fromstring(struct adb_obj *obj, apk_blob_t bdep) apk_blob_t bname, bver; int op; diff --git a/openwrt/patch/cgroupfs-mount/0001-fix-cgroupfs-mount.patch b/openwrt/patch/cgroupfs-mount/0001-fix-cgroupfs-mount.patch deleted file mode 100644 index 0c03d5878..000000000 --- a/openwrt/patch/cgroupfs-mount/0001-fix-cgroupfs-mount.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/utils/cgroupfs-mount/files/cgroupfs-mount.init b/utils/cgroupfs-mount/files/cgroupfs-mount.init -index 0d6b68d..4ae3185 100755 ---- a/utils/cgroupfs-mount/files/cgroupfs-mount.init -+++ b/utils/cgroupfs-mount/files/cgroupfs-mount.init -@@ -4,9 +4,17 @@ START=01 - - boot() { - # Procd mounts non-hierarchical cgroupfs so unmount first before cgroupfs-mount -- if mountpoint -q /sys/fs/cgroup; then -- umount /sys/fs/cgroup/ -- fi -+ umount_cgroup() { -+ for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do -+ if mountpoint -q /sys/fs/cgroup/$sys; then -+ umount /sys/fs/cgroup/$sys || true -+ fi -+ done -+ if mountpoint -q /sys/fs/cgroup; then -+ umount /sys/fs/cgroup || true -+ fi -+ } - -- cgroupfs-mount -+ umount_cgroup -+ cgroupfs-mount - } diff --git a/openwrt/patch/cgroupfs-mount/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch b/openwrt/patch/cgroupfs-mount/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch deleted file mode 100644 index 05fbbe2d9..000000000 --- a/openwrt/patch/cgroupfs-mount/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 3855430e665c09b8b36d177a39245d0a69453397 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 23 Aug 2023 20:10:30 +0800 -Subject: [PATCH 1/2] mount cgroup v2 hierarchy to /sys/fs/cgroup/cgroup2 - ---- - cgroupfs-mount | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/cgroupfs-mount b/cgroupfs-mount -index 40810ba..114f7a1 100755 ---- a/cgroupfs-mount -+++ b/cgroupfs-mount -@@ -41,6 +41,12 @@ for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do - fi - done - -+# mount cgroup v2 hierarchy to /sys/fs/cgroup/cgroup2 if kernel support cgroup2 filesystem -+if grep -q cgroup2 /proc/filesystems; then -+ mkdir -p /sys/fs/cgroup/cgroup2 -+ mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime,nsdelegate cgroup2 /sys/fs/cgroup/cgroup2 -+fi -+ - # example /proc/cgroups: - # #subsys_name hierarchy num_cgroups enabled - # cpuset 2 3 1 --- -2.34.8 - diff --git a/openwrt/patch/cgroupfs-mount/901-fix-cgroupfs-umount.patch b/openwrt/patch/cgroupfs-mount/901-fix-cgroupfs-umount.patch deleted file mode 100644 index 85c652e28..000000000 --- a/openwrt/patch/cgroupfs-mount/901-fix-cgroupfs-umount.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 712d45f93d6d499f8c6e6da44084ed2bfdae1605 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 23 Aug 2023 20:11:57 +0800 -Subject: [PATCH 2/2] fix cgroupfs-umount - ---- - cgroupfs-umount | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/cgroupfs-umount b/cgroupfs-umount -index ac26b6b..5b4c86e 100755 ---- a/cgroupfs-umount -+++ b/cgroupfs-umount -@@ -24,8 +24,11 @@ for sys in *; do - umount $sys - fi - if [ -d $sys ]; then -- rmdir $sys || true -+ rm -rf $sys || true - fi - done - -+cd / -+umount /sys/fs/cgroup || true -+ - exit 0 --- -2.34.8 - diff --git a/openwrt/patch/cgroupfs-mount/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch b/openwrt/patch/cgroupfs-mount/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch deleted file mode 100644 index 31b000152..000000000 --- a/openwrt/patch/cgroupfs-mount/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 7f6837183da98c4ec5697d9c609e7da4ce354dea Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 23 Aug 2023 21:41:37 +0800 -Subject: [PATCH] mount /sys/fs/cgroup/systemd for docker systemd support - ---- - cgroupfs-mount | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/cgroupfs-mount b/cgroupfs-mount -index 8274c7c..4c1f954 100755 ---- a/cgroupfs-mount -+++ b/cgroupfs-mount -@@ -47,6 +47,12 @@ if grep -q cgroup2 /proc/filesystems; then - mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime,nsdelegate cgroup2 /sys/fs/cgroup/cgroup2 - fi - -+# mount /sys/fs/cgroup/systemd for docker systemd -+mkdir -p /sys/fs/cgroup/systemd -+if ! mountpoint -q /sys/fs/cgroup/systemd; then -+ mount -t cgroup -o none,name=systemd systemd /sys/fs/cgroup/systemd -+fi -+ - # example /proc/cgroups: - # #subsys_name hierarchy num_cgroups enabled - # cpuset 2 3 1 --- -2.34.8 - diff --git a/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch b/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch index 3a2c443bc..f9aa1ac9b 100644 --- a/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch +++ b/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch @@ -1,6 +1,6 @@ --- a/root/usr/share/ucode/fw4.uc +++ b/root/usr/share/ucode/fw4.uc -@@ -2045,8 +2045,8 @@ return { +@@ -2068,8 +2068,8 @@ return { }); } diff --git a/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch b/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch deleted file mode 100644 index 386531b5c..000000000 --- a/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch +++ /dev/null @@ -1,23 +0,0 @@ -From ba78896dffc386e641ac0eb9397761a24f4b5d87 Mon Sep 17 00:00:00 2001 -From: ZiMing Mo -Date: Sun, 7 Aug 2022 15:52:55 +0800 -Subject: [PATCH] fix(fw4.uc): adept kernel version type of x.x - -fix kernel version match if the kernel version type is x.x (not x.x.x) - -Signed-off-by: ZiMing Mo ---- - root/usr/share/ucode/fw4.uc | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/root/usr/share/ucode/fw4.uc -+++ b/root/usr/share/ucode/fw4.uc -@@ -496,7 +496,7 @@ return { - v = 0; - - if (fd) { -- let m = match(fd.read("line"), /^Linux version ([0-9]+)\.([0-9]+)\.([0-9]+)/); -+ let m = match(fd.read("line"), /^Linux version ([0-9]+)\.([0-9]+)\.?([0-9]+)?/); - - v = m ? (+m[1] << 24) | (+m[2] << 16) | (+m[3] << 8) : 0; - fd.close(); diff --git a/openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch b/openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch new file mode 100644 index 000000000..6030936b3 --- /dev/null +++ b/openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch @@ -0,0 +1,30 @@ +From c359ce4457ac48bb65767ae5415f296e3d25a51d Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Thu, 14 Mar 2024 12:10:03 +0800 +Subject: [PATCH] fw4: add custom nft command support + +Signed-off-by: sbwml +--- + root/etc/firewall4.user | 3 +++ + root/sbin/fw4 | 3 ++- + 2 files changed, 5 insertions(+), 1 deletion(-) + create mode 100644 root/etc/firewall4.user + +--- /dev/null ++++ b/root/etc/firewall4.user +@@ -0,0 +1,3 @@ ++# This file is interpreted as shell script. ++# Put your custom nft rules here, they will ++# be executed with each firewall (re-)start. +--- a/root/sbin/fw4 ++++ b/root/sbin/fw4 +@@ -33,7 +33,8 @@ start() { + esac + + ACTION=start \ +- utpl -S $MAIN | nft $VERBOSE -f $STDIN ++ utpl -S $MAIN | nft $VERBOSE -f $STDIN \ ++ ; /bin/sh /etc/firewall4.user + + ACTION=includes \ + utpl -S $MAIN diff --git a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch index d71475925..1ca27c189 100644 --- a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch +++ b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch @@ -25,22 +25,22 @@ IPv6 traffic do NOT need this FullCone NAT functionality. option forward REJECT # Uncomment this line to disable ipv6 rules # option disable_ipv6 1 -+ option fullcone '1' ++ option fullcone 1 config zone option name lan -@@ -20,6 +21,8 @@ config zone - option input REJECT - option output ACCEPT - option forward REJECT -+ option fullcone4 '1' -+ option fullcone6 '1' +@@ -22,6 +23,8 @@ config zone + option forward DROP option masq 1 option mtu_fix 1 ++ option fullcone4 1 ++ option fullcone6 1 + config forwarding + option src lan --- a/root/usr/share/firewall4/templates/ruleset.uc +++ b/root/usr/share/firewall4/templates/ruleset.uc -@@ -327,6 +327,12 @@ table inet fw4 { +@@ -323,6 +323,12 @@ table inet fw4 { {% for (let redirect in fw4.redirects(`dstnat_${zone.name}`)): %} {%+ include("redirect.uc", { fw4, zone, redirect }) %} {% endfor %} @@ -53,7 +53,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. {% fw4.includes('chain-append', `dstnat_${zone.name}`) %} } -@@ -337,20 +343,26 @@ table inet fw4 { +@@ -333,20 +339,26 @@ table inet fw4 { {% for (let redirect in fw4.redirects(`srcnat_${zone.name}`)): %} {%+ include("redirect.uc", { fw4, zone, redirect }) %} {% endfor %} @@ -123,7 +123,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. return { read_kernel_version: function() { -@@ -832,6 +853,18 @@ return { +@@ -855,6 +876,18 @@ return { warn(`[!] ${msg}\n`); }, @@ -142,7 +142,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. get: function(sid, opt) { return this.cursor.get("firewall", sid, opt); }, -@@ -1013,6 +1046,21 @@ return { +@@ -1036,6 +1069,21 @@ return { } }, @@ -164,7 +164,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. parse_policy: function(val) { return this.parse_enum(val, [ "accept", -@@ -1452,6 +1500,7 @@ return { +@@ -1475,6 +1523,7 @@ return { "dnat", "snat", "masquerade", @@ -172,7 +172,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. "accept", "reject", "drop" -@@ -1923,6 +1972,7 @@ return { +@@ -1946,6 +1995,7 @@ return { } let defs = this.parse_options(data, { @@ -180,7 +180,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. input: [ "policy", "drop" ], output: [ "policy", "drop" ], forward: [ "policy", "drop" ], -@@ -1957,6 +2007,11 @@ return { +@@ -1980,6 +2030,11 @@ return { delete defs.syn_flood; @@ -192,7 +192,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. this.state.defaults = defs; }, -@@ -1981,6 +2036,8 @@ return { +@@ -2004,6 +2059,8 @@ return { masq_dest: [ "network", null, PARSE_LIST ], masq6: [ "bool" ], @@ -201,7 +201,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. extra: [ "string", null, UNSUPPORTED ], extra_src: [ "string", null, UNSUPPORTED ], -@@ -2013,6 +2070,18 @@ return { +@@ -2036,6 +2093,18 @@ return { } } @@ -220,7 +220,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. if (zone.mtu_fix && this.kernel < 0x040a0000) { this.warn_section(data, "option 'mtu_fix' requires kernel 4.10 or later"); return; -@@ -2182,10 +2251,15 @@ return { +@@ -2205,10 +2274,15 @@ return { zone.related_subnets = related_subnets; zone.related_physdevs = related_physdevs; diff --git a/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch b/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch index 4d32e6e08..a054ec4a5 100644 --- a/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch +++ b/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch @@ -3,10 +3,10 @@ @@ -6,6 +6,9 @@ config defaults # Uncomment this line to disable ipv6 rules # option disable_ipv6 1 - option fullcone '1' + option fullcone 1 +# 0 - use nft_fullcone originated from Chion82 +# 1 - use bcm fullconenat from broadcom ASUS Merlin -+ option brcmfullcone '0' ++ option brcmfullcone 0 config zone option name lan @@ -81,7 +81,7 @@ return { read_kernel_version: function() { -@@ -1972,6 +1986,7 @@ return { +@@ -1995,6 +2009,7 @@ return { } let defs = this.parse_options(data, { @@ -89,7 +89,7 @@ fullcone: [ "bool", "0" ], input: [ "policy", "drop" ], output: [ "policy", "drop" ], -@@ -2007,9 +2022,20 @@ return { +@@ -2030,9 +2045,20 @@ return { delete defs.syn_flood; @@ -113,7 +113,7 @@ } this.state.defaults = defs; -@@ -2075,6 +2101,10 @@ return { +@@ -2098,6 +2124,10 @@ return { zone.fullcone4 = false; zone.fullcone6 = false; } @@ -124,7 +124,7 @@ if (zone.fullcone4) { this.myinfo_section(data, "IPv4 fullcone enabled for zone '" + zone.name + "'"); } -@@ -2259,6 +2289,9 @@ return { +@@ -2282,6 +2312,9 @@ return { if (zone.masq || zone.masq6) zone.dflags.snat = true; diff --git a/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch b/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch index c55f55624..ffbc608f1 100644 --- a/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch +++ b/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch @@ -15,7 +15,7 @@ Signed-off-by: Syrone Wong --- a/include/libnftnl/expr.h +++ b/include/libnftnl/expr.h -@@ -272,6 +272,12 @@ enum { +@@ -273,6 +273,12 @@ enum { }; enum { @@ -30,7 +30,7 @@ Signed-off-by: Syrone Wong NFTNL_EXPR_REDIR_FLAGS, --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h -@@ -1464,6 +1464,22 @@ enum nft_masq_attributes { +@@ -1510,6 +1510,22 @@ enum nft_masq_attributes { #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) /** @@ -55,7 +55,7 @@ Signed-off-by: Syrone Wong * @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) --- a/src/Makefile.am +++ b/src/Makefile.am -@@ -55,6 +55,7 @@ libnftnl_la_SOURCES = utils.c \ +@@ -56,6 +56,7 @@ libnftnl_la_SOURCES = utils.c \ expr/target.c \ expr/tunnel.c \ expr/masq.c \ diff --git a/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch b/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch index 7606571f9..6cdd9392b 100644 --- a/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch +++ b/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch @@ -12,7 +12,7 @@ Signed-off-by: sbwml --- a/include/libnftnl/expr.h +++ b/include/libnftnl/expr.h -@@ -268,6 +268,8 @@ enum { +@@ -269,6 +269,8 @@ enum { NFTNL_EXPR_MASQ_FLAGS = NFTNL_EXPR_BASE, NFTNL_EXPR_MASQ_REG_PROTO_MIN, NFTNL_EXPR_MASQ_REG_PROTO_MAX, @@ -23,7 +23,7 @@ Signed-off-by: sbwml --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h -@@ -1453,12 +1453,16 @@ enum nft_tproxy_attributes { +@@ -1499,12 +1499,16 @@ enum nft_tproxy_attributes { * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) @@ -42,7 +42,7 @@ Signed-off-by: sbwml #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/src/expr/masq.c +++ b/src/expr/masq.c -@@ -24,6 +24,8 @@ struct nftnl_expr_masq { +@@ -20,6 +20,8 @@ struct nftnl_expr_masq { uint32_t flags; enum nft_registers sreg_proto_min; enum nft_registers sreg_proto_max; @@ -51,7 +51,7 @@ Signed-off-by: sbwml }; static int -@@ -42,6 +44,12 @@ nftnl_expr_masq_set(struct nftnl_expr *e +@@ -38,6 +40,12 @@ nftnl_expr_masq_set(struct nftnl_expr *e case NFTNL_EXPR_MASQ_REG_PROTO_MAX: memcpy(&masq->sreg_proto_max, data, data_len); break; @@ -64,7 +64,7 @@ Signed-off-by: sbwml } return 0; } -@@ -62,6 +70,12 @@ nftnl_expr_masq_get(const struct nftnl_e +@@ -58,6 +66,12 @@ nftnl_expr_masq_get(const struct nftnl_e case NFTNL_EXPR_MASQ_REG_PROTO_MAX: *data_len = sizeof(masq->sreg_proto_max); return &masq->sreg_proto_max; @@ -77,7 +77,7 @@ Signed-off-by: sbwml } return NULL; } -@@ -78,6 +92,8 @@ static int nftnl_expr_masq_cb(const stru +@@ -74,6 +88,8 @@ static int nftnl_expr_masq_cb(const stru case NFTA_MASQ_REG_PROTO_MIN: case NFTA_MASQ_REG_PROTO_MAX: case NFTA_MASQ_FLAGS: @@ -86,7 +86,7 @@ Signed-off-by: sbwml if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; -@@ -100,6 +116,12 @@ nftnl_expr_masq_build(struct nlmsghdr *n +@@ -96,6 +112,12 @@ nftnl_expr_masq_build(struct nlmsghdr *n if (e->flags & (1 << NFTNL_EXPR_MASQ_REG_PROTO_MAX)) mnl_attr_put_u32(nlh, NFTA_MASQ_REG_PROTO_MAX, htobe32(masq->sreg_proto_max)); @@ -99,7 +99,7 @@ Signed-off-by: sbwml } static int -@@ -125,6 +147,16 @@ nftnl_expr_masq_parse(struct nftnl_expr +@@ -121,6 +143,16 @@ nftnl_expr_masq_parse(struct nftnl_expr be32toh(mnl_attr_get_u32(tb[NFTA_MASQ_REG_PROTO_MAX])); e->flags |= (1 << NFTNL_EXPR_MASQ_REG_PROTO_MAX); } @@ -116,7 +116,7 @@ Signed-off-by: sbwml return 0; } -@@ -149,6 +181,16 @@ static int nftnl_expr_masq_snprintf(char +@@ -145,6 +177,16 @@ static int nftnl_expr_masq_snprintf(char ret = snprintf(buf + offset, remain, "flags 0x%x ", masq->flags); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } diff --git a/openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch similarity index 100% rename from openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch rename to openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch diff --git a/openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch similarity index 100% rename from openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch rename to openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch diff --git a/openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch similarity index 100% rename from openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch rename to openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch diff --git a/openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch similarity index 100% rename from openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch rename to openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch diff --git a/openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch similarity index 100% rename from openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch rename to openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch diff --git a/openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch b/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch similarity index 100% rename from openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch rename to openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch diff --git a/openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch b/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch similarity index 100% rename from openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch rename to openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch diff --git a/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch b/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch index 086bf8f79..a62cb4505 100644 --- a/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch +++ b/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch @@ -16,7 +16,7 @@ Signed-off-by: Syrone Wong --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h -@@ -1485,6 +1485,22 @@ enum nft_masq_attributes { +@@ -1500,6 +1500,22 @@ enum nft_masq_attributes { #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) /** @@ -51,7 +51,7 @@ Signed-off-by: Syrone Wong --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c -@@ -1467,6 +1467,53 @@ out_err: +@@ -1521,6 +1521,53 @@ out_err: stmt_free(stmt); } @@ -105,7 +105,7 @@ Signed-off-by: Syrone Wong static void netlink_parse_redir(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) -@@ -1897,6 +1944,7 @@ static const struct expr_handler netlink +@@ -1952,6 +1999,7 @@ static const struct expr_handler netlink { .name = "tproxy", .parse = netlink_parse_tproxy }, { .name = "notrack", .parse = netlink_parse_notrack }, { .name = "masq", .parse = netlink_parse_masq }, @@ -115,7 +115,7 @@ Signed-off-by: Syrone Wong { .name = "queue", .parse = netlink_parse_queue }, --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c -@@ -1226,6 +1226,13 @@ static void netlink_gen_nat_stmt(struct +@@ -1266,6 +1266,13 @@ static void netlink_gen_nat_stmt(struct nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN; nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX; break; @@ -131,7 +131,7 @@ Signed-off-by: Syrone Wong --- a/src/parser_bison.y +++ b/src/parser_bison.y -@@ -643,6 +643,7 @@ int nft_lex(void *, void *, void *); +@@ -668,6 +668,7 @@ int nft_lex(void *, void *, void *); %token SNAT "snat" %token DNAT "dnat" %token MASQUERADE "masquerade" @@ -139,7 +139,7 @@ Signed-off-by: Syrone Wong %token REDIRECT "redirect" %token RANDOM "random" %token FULLY_RANDOM "fully-random" -@@ -784,8 +785,8 @@ int nft_lex(void *, void *, void *); +@@ -814,8 +815,8 @@ int nft_lex(void *, void *, void *); %type limit_burst_pkts limit_burst_bytes limit_mode limit_bytes time_unit quota_mode %type reject_stmt reject_stmt_alloc %destructor { stmt_free($$); } reject_stmt reject_stmt_alloc @@ -150,7 +150,7 @@ Signed-off-by: Syrone Wong %type nf_nat_flags nf_nat_flag offset_opt %type tproxy_stmt %destructor { stmt_free($$); } tproxy_stmt -@@ -3216,6 +3217,7 @@ stmt : verdict_stmt +@@ -3274,6 +3275,7 @@ stmt : verdict_stmt | queue_stmt | ct_stmt | masq_stmt close_scope_nat @@ -158,7 +158,7 @@ Signed-off-by: Syrone Wong | redir_stmt close_scope_nat | dup_stmt close_scope_dup | fwd_stmt close_scope_fwd -@@ -3999,6 +4001,28 @@ masq_stmt_args : TO COLON stmt_expr +@@ -4105,6 +4107,28 @@ masq_stmt_args : TO COLON stmt_expr { $0->nat.proto = $3; } @@ -189,7 +189,7 @@ Signed-off-by: Syrone Wong $0->nat.proto = $3; --- a/src/scanner.l +++ b/src/scanner.l -@@ -462,6 +462,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr +@@ -470,6 +470,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr "snat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; } "dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; } "masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; } @@ -199,7 +199,7 @@ Signed-off-by: Syrone Wong { --- a/src/statement.c +++ b/src/statement.c -@@ -674,6 +674,7 @@ const char *nat_etype2str(enum nft_nat_e +@@ -681,6 +681,7 @@ const char *nat_etype2str(enum nft_nat_e [NFT_NAT_SNAT] = "snat", [NFT_NAT_DNAT] = "dnat", [NFT_NAT_MASQ] = "masquerade", diff --git a/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch b/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch index 25c5f830b..95fbd8878 100644 --- a/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch +++ b/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch @@ -15,7 +15,7 @@ Signed-off-by: sbwml --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h -@@ -1474,12 +1474,16 @@ enum nft_tproxy_attributes { +@@ -1489,12 +1489,16 @@ enum nft_tproxy_attributes { * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) @@ -34,7 +34,7 @@ Signed-off-by: sbwml #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c -@@ -1426,6 +1426,7 @@ static void netlink_parse_masq(struct ne +@@ -1480,6 +1480,7 @@ static void netlink_parse_masq(struct ne { enum nft_registers reg1, reg2; struct expr *proto; @@ -42,7 +42,7 @@ Signed-off-by: sbwml struct stmt *stmt; uint32_t flags = 0; -@@ -1461,6 +1462,29 @@ static void netlink_parse_masq(struct ne +@@ -1515,6 +1516,29 @@ static void netlink_parse_masq(struct ne stmt->nat.proto = proto; } @@ -74,7 +74,7 @@ Signed-off-by: sbwml out_err: --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c -@@ -1205,7 +1205,10 @@ static void netlink_gen_nat_stmt(struct +@@ -1245,7 +1245,10 @@ static void netlink_gen_nat_stmt(struct int registers = 0; int nftnl_flag_attr; int nftnl_reg_pmin, nftnl_reg_pmax; @@ -85,7 +85,7 @@ Signed-off-by: sbwml switch (stmt->nat.type) { case NFT_NAT_SNAT: case NFT_NAT_DNAT: -@@ -1225,6 +1228,8 @@ static void netlink_gen_nat_stmt(struct +@@ -1265,6 +1268,8 @@ static void netlink_gen_nat_stmt(struct nftnl_flag_attr = NFTNL_EXPR_MASQ_FLAGS; nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN; nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX; @@ -94,7 +94,7 @@ Signed-off-by: sbwml break; case NFT_NAT_FULLCONE: nle = alloc_nft_expr("fullcone"); -@@ -1258,13 +1263,13 @@ static void netlink_gen_nat_stmt(struct +@@ -1298,13 +1303,13 @@ static void netlink_gen_nat_stmt(struct netlink_gen_expr(ctx, stmt->nat.addr->left, amin_reg); netlink_gen_expr(ctx, stmt->nat.addr->right, amax_reg); @@ -111,7 +111,7 @@ Signed-off-by: sbwml amin_reg); if (stmt->nat.addr->etype == EXPR_MAP && stmt->nat.addr->mappings->set->data->flags & EXPR_F_INTERVAL) { -@@ -1273,7 +1278,7 @@ static void netlink_gen_nat_stmt(struct +@@ -1313,7 +1318,7 @@ static void netlink_gen_nat_stmt(struct netlink_put_register(nle, nftnl_reg_pmin, amin_reg); } else { @@ -120,7 +120,7 @@ Signed-off-by: sbwml amin_reg); } } -@@ -1289,7 +1294,7 @@ static void netlink_gen_nat_stmt(struct +@@ -1329,7 +1334,7 @@ static void netlink_gen_nat_stmt(struct if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL) { pmin_reg += netlink_register_space(nat_addrlen(family)); @@ -131,7 +131,7 @@ Signed-off-by: sbwml --- a/src/parser_bison.y +++ b/src/parser_bison.y -@@ -644,6 +644,7 @@ int nft_lex(void *, void *, void *); +@@ -669,6 +669,7 @@ int nft_lex(void *, void *, void *); %token DNAT "dnat" %token MASQUERADE "masquerade" %token FULLCONE "fullcone" @@ -139,7 +139,7 @@ Signed-off-by: sbwml %token REDIRECT "redirect" %token RANDOM "random" %token FULLY_RANDOM "fully-random" -@@ -4010,6 +4011,15 @@ masq_stmt_args : TO COLON stmt_expr +@@ -4116,6 +4117,15 @@ masq_stmt_args : TO COLON stmt_expr { $0->nat.flags = $1; } @@ -157,7 +157,7 @@ Signed-off-by: sbwml fullcone_stmt : fullcone_stmt_alloc fullcone_stmt_args --- a/src/scanner.l +++ b/src/scanner.l -@@ -463,6 +463,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr +@@ -471,6 +471,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr "dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; } "masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; } "fullcone" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return FULLCONE; } @@ -167,7 +167,7 @@ Signed-off-by: sbwml { --- a/src/statement.c +++ b/src/statement.c -@@ -683,6 +683,7 @@ const char *nat_etype2str(enum nft_nat_e +@@ -690,6 +690,7 @@ const char *nat_etype2str(enum nft_nat_e static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { @@ -175,7 +175,7 @@ Signed-off-by: sbwml nft_print(octx, "%s", nat_etype2str(stmt->nat.type)); if (stmt->nat.addr || stmt->nat.proto) { switch (stmt->nat.family) { -@@ -696,11 +697,13 @@ static void nat_stmt_print(const struct +@@ -703,11 +704,13 @@ static void nat_stmt_print(const struct if (stmt->nat.type_flags & STMT_NAT_F_PREFIX) nft_print(octx, " prefix"); diff --git a/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch b/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch deleted file mode 100644 index d9eba3069..000000000 --- a/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch +++ /dev/null @@ -1,29 +0,0 @@ -From ffe0a07aaf5534cf1047238f52d7cda346444046 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Sun, 17 Nov 2024 21:19:18 +0800 -Subject: [PATCH 3/3] drop rej file - -Signed-off-by: sbwml ---- - tests/shell/run-tests.sh.rej | 15 --------------- - 1 file changed, 15 deletions(-) - delete mode 100644 tests/shell/run-tests.sh.rej - ---- 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/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch b/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch deleted file mode 100644 index 96fb1065d..000000000 --- a/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 360c76c16bb63cd2a7a5eb188c063468ce99073c Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 10 Oct 2024 21:40:05 +0800 -Subject: [PATCH 09/10] kernel: add legacy cgroup v1 memory controller - -Signed-off-by: sbwml ---- - config/Config-kernel.in | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index 91678cf..eb0f000 100644 ---- a/config/Config-kernel.in -+++ b/config/Config-kernel.in -@@ -953,6 +953,16 @@ if KERNEL_CGROUPS - the kmem extension can use it to guarantee that no group of processes - will ever exhaust kernel resources alone. - -+ config KERNEL_MEMCG_V1 -+ bool "Legacy cgroup v1 memory controller" -+ depends on KERNEL_MEMCG -+ help -+ Legacy cgroup v1 memory controller which has been deprecated by -+ cgroup v2 implementation. The v1 is there for legacy applications -+ which haven't migrated to the new cgroup v2 interface yet. If you -+ do not have any such application then you are completely fine leaving -+ this option disabled. -+ - config KERNEL_CGROUP_PERF - bool "Enable perf_event per-cpu per-container group (cgroup) monitoring" - select KERNEL_PERF_EVENTS --- -2.43.5 - diff --git a/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch b/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch deleted file mode 100644 index 6dc62030b..000000000 --- a/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch +++ /dev/null @@ -1,124 +0,0 @@ -From baebc1fe503f69e2e0cdd3d932dc328a86be1b7d Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 29 May 2025 17:11:26 +0800 -Subject: [PATCH 11/12] tools: squashfs4: enable zstd compression support - -Signed-off-by: sbwml ---- - tools/Makefile | 2 +- - tools/squashfs4/Makefile | 1 + - ...negative-levels-for-zstd-compression.patch | 77 +++++++++++++++++++ - 3 files changed, 79 insertions(+), 1 deletion(-) - create mode 100644 tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch - -diff --git a/tools/Makefile b/tools/Makefile -index 702184a..d706c13 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -129,7 +129,7 @@ $(curdir)/pkgconf/compile := $(curdir)/meson/compile - $(curdir)/quilt/compile := $(curdir)/autoconf/compile $(curdir)/findutils/compile - $(curdir)/sdcc/compile := $(curdir)/bison/compile - $(curdir)/squashfs3-lzma/compile := $(curdir)/lzma-old/compile --$(curdir)/squashfs4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile -+$(curdir)/squashfs4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile $(curdir)/zstd/compile - $(curdir)/util-linux/compile := $(curdir)/bison/compile $(curdir)/automake/compile - $(curdir)/yafut/compile := $(curdir)/cmake/compile - -diff --git a/tools/squashfs4/Makefile b/tools/squashfs4/Makefile -index 38c3e52..e3065bf 100644 ---- a/tools/squashfs4/Makefile -+++ b/tools/squashfs4/Makefile -@@ -27,6 +27,7 @@ define Host/Compile - XZ_SUPPORT=1 \ - LZMA_XZ_SUPPORT=1 \ - XZ_EXTENDED_OPTIONS=1 \ -+ ZSTD_SUPPORT=1 \ - EXTRA_CFLAGS="-I$(STAGING_DIR_HOST)/include" \ - mksquashfs unsquashfs - endef -diff --git a/tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch b/tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch -new file mode 100644 -index 0000000..b219d9f ---- /dev/null -+++ b/tools/squashfs4/patches/100-Support-negative-levels-for-zstd-compression.patch -@@ -0,0 +1,77 @@ -+From 31f103dc9b0cce526adc35a5f49437d58b6799c0 Mon Sep 17 00:00:00 2001 -+From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= -+Date: Sun, 16 Feb 2025 13:42:53 +0100 -+Subject: [PATCH] Support negative levels for zstd compression -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+These levels correspond to the --fast option of the zstd program, -+and offers better compression speed for worse compression rate. -+ -+Signed-off-by: Anders F Björklund -+--- -+ squashfs-tools/zstd_wrapper.c | 27 +++++++++++++++++++++------ -+ 1 file changed, 21 insertions(+), 6 deletions(-) -+ -+--- a/squashfs-tools/zstd_wrapper.c -++++ b/squashfs-tools/zstd_wrapper.c -+@@ -51,12 +51,25 @@ static int zstd_options(char *argv[], in -+ fprintf(stderr, "zstd: -Xcompression-level missing " -+ "compression level\n"); -+ fprintf(stderr, "zstd: -Xcompression-level it should " -+- "be 1 <= n <= %d\n", ZSTD_maxCLevel()); -++ "be %d <= n <= -1 or 1 <= n <= %d\n", -++ ZSTD_minCLevel(), ZSTD_maxCLevel()); -+ goto failed; -+ } -+ -+ compression_level = atoi(argv[1]); -+- if (compression_level < 1 || -++ if (compression_level == 0) { -++ fprintf(stderr, "zstd: -Xcompression-level invalid, it " -++ "should be %d <= n <= -1 or 1 <= n <= %d\n", -++ ZSTD_minCLevel(), ZSTD_maxCLevel()); -++ goto failed; -++ } -++ if (compression_level < 0 && -++ compression_level < ZSTD_minCLevel()) { -++ fprintf(stderr, "zstd: -Xcompression-level invalid, it " -++ "should be %d <= n <= -1\n", ZSTD_minCLevel()); -++ goto failed; -++ } -++ if (compression_level > 0 && -+ compression_level > ZSTD_maxCLevel()) { -+ fprintf(stderr, "zstd: -Xcompression-level invalid, it " -+ "should be 1 <= n <= %d\n", ZSTD_maxCLevel()); -+@@ -132,7 +145,8 @@ static int zstd_extract_options(int bloc -+ -+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts); -+ -+- if (comp_opts->compression_level < 1 || -++ if (comp_opts->compression_level == 0 || -++ comp_opts->compression_level < ZSTD_minCLevel() || -+ comp_opts->compression_level > ZSTD_maxCLevel()) { -+ fprintf(stderr, "zstd: bad compression level in compression " -+ "options structure\n"); -+@@ -160,7 +174,8 @@ static void zstd_display_options(void *b -+ -+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts); -+ -+- if (comp_opts->compression_level < 1 || -++ if (comp_opts->compression_level == 0 || -++ comp_opts->compression_level < ZSTD_minCLevel() || -+ comp_opts->compression_level > ZSTD_maxCLevel()) { -+ fprintf(stderr, "zstd: bad compression level in compression " -+ "options structure\n"); -+@@ -235,8 +250,8 @@ static int zstd_uncompress(void *dest, v -+ static void zstd_usage(FILE *stream) -+ { -+ fprintf(stream, "\t -Xcompression-level \n"); -+- fprintf(stream, "\t\t should be 1 .. %d (default " -+- "%d)\n", ZSTD_maxCLevel(), ZSTD_DEFAULT_COMPRESSION_LEVEL); -++ fprintf(stream, "\t\t should be %d .. -1 or 1 .. %d (default %d). Negative compression levels correspond to the zstd --fast option.\n", -++ ZSTD_minCLevel(), ZSTD_maxCLevel(), ZSTD_DEFAULT_COMPRESSION_LEVEL); -+ } -+ -+ --- -2.43.5 - diff --git a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch b/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch deleted file mode 100644 index d598a2ec0..000000000 --- a/openwrt/patch/generic-24.10/202-toolchain-gcc-add-support-for-GCC-15.patch +++ /dev/null @@ -1,800 +0,0 @@ -From b6419cff44d0e951d3805dcd70f3d462f40baa8f Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 7 Nov 2024 01:13:32 +0800 -Subject: [PATCH] toolchain: gcc: add support for GCC 15 - -Signed-off-by: sbwml ---- - toolchain/gcc/Config.in | 3 + - toolchain/gcc/Config.version | 5 + - toolchain/gcc/common.mk | 4 + - .../patches-15.x/002-case_insensitive.patch | 24 +++ - ...t-choke-when-building-32bit-on-64bit.patch | 13 ++ - .../gcc/patches-15.x/010-documentation.patch | 35 +++++ - .../gcc/patches-15.x/230-musl_libssp.patch | 13 ++ - .../300-mips_Os_cpu_rtx_cost_model.patch | 21 +++ - .../810-arm-softfloat-libgcc.patch | 33 ++++ - .../gcc/patches-15.x/820-libgcc_pic.patch | 44 ++++++ - .../840-armv4_pass_fix-v4bx_to_ld.patch | 28 ++++ - .../patches-15.x/850-use_shared_libgcc.patch | 54 +++++++ - .../patches-15.x/851-libgcc_no_compat.patch | 22 +++ - .../patches-15.x/870-ppc_no_crtsavres.patch | 11 ++ - .../gcc/patches-15.x/881-no_tm_section.patch | 11 ++ - .../gcc/patches-15.x/900-bad-mips16-crt.patch | 9 ++ - .../gcc/patches-15.x/910-mbsd_multi.patch | 146 ++++++++++++++++++ - .../920-specs_nonfatal_getenv.patch | 22 +++ - ...mpilation-when-making-cross-compiler.patch | 67 ++++++++ - .../970-macos_arm64-building-fix.patch | 45 ++++++ - 20 files changed, 610 insertions(+) - create mode 100644 toolchain/gcc/patches-15.x/002-case_insensitive.patch - create mode 100644 toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch - create mode 100644 toolchain/gcc/patches-15.x/010-documentation.patch - create mode 100644 toolchain/gcc/patches-15.x/230-musl_libssp.patch - create mode 100644 toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch - create mode 100644 toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch - create mode 100644 toolchain/gcc/patches-15.x/820-libgcc_pic.patch - create mode 100644 toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch - create mode 100644 toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch - create mode 100644 toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch - create mode 100644 toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch - create mode 100644 toolchain/gcc/patches-15.x/881-no_tm_section.patch - create mode 100644 toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch - create mode 100644 toolchain/gcc/patches-15.x/910-mbsd_multi.patch - create mode 100644 toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch - create mode 100644 toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch - create mode 100644 toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch - -diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in -index b306040..3ab16a8 100644 ---- a/toolchain/gcc/Config.in -+++ b/toolchain/gcc/Config.in -@@ -17,6 +17,9 @@ choice - - config GCC_USE_VERSION_14 - bool "gcc 14.x" -+ -+ config GCC_USE_VERSION_15 -+ bool "gcc 15.x" - endchoice - - config GCC_USE_GRAPHITE -diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version -index 49bb368..9ecca5d 100644 ---- a/toolchain/gcc/Config.version -+++ b/toolchain/gcc/Config.version -@@ -10,12 +10,17 @@ config GCC_VERSION_14 - default y if GCC_USE_VERSION_14 - bool - -+config GCC_VERSION_15 -+ default y if GCC_USE_VERSION_15 -+ bool -+ - config GCC_VERSION - string - default EXTERNAL_GCC_VERSION if EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN - default "11.3.0" if GCC_VERSION_11 - default "12.3.0" if GCC_VERSION_12 - default "14.2.0" if GCC_VERSION_14 -+ default "15.2.0" if GCC_VERSION_15 - default "13.3.0" - - config GCC_USE_DEFAULT_VERSION -diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk -index 0ccf55b..1dd644f 100644 ---- a/toolchain/gcc/common.mk -+++ b/toolchain/gcc/common.mk -@@ -46,6 +46,10 @@ ifeq ($(PKG_VERSION),14.2.0) - PKG_HASH:=a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9 - endif - -+ifeq ($(PKG_VERSION),15.2.0) -+ PKG_HASH:=438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e -+endif -+ - PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x - - BUGURL=http://bugs.openwrt.org/ -diff --git a/toolchain/gcc/patches-15.x/002-case_insensitive.patch b/toolchain/gcc/patches-15.x/002-case_insensitive.patch -new file mode 100644 -index 0000000..409497e ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/002-case_insensitive.patch -@@ -0,0 +1,24 @@ -+commit 81cc26c706b2bc8c8c1eb1a322e5c5157900836e -+Author: Felix Fietkau -+Date: Sun Oct 19 21:45:51 2014 +0000 -+ -+ gcc: do not assume that the Mac OS X filesystem is case insensitive -+ -+ Signed-off-by: Felix Fietkau -+ -+ SVN-Revision: 42973 -+ -+--- a/include/filenames.h -++++ b/include/filenames.h -+@@ -44,11 +44,6 @@ extern "C" { -+ # define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c) -+ # define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f) -+ #else /* not DOSish */ -+-# if defined(__APPLE__) -+-# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM -+-# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 -+-# endif -+-# endif /* __APPLE__ */ -+ # define HAS_DRIVE_SPEC(f) (0) -+ # define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c) -+ # define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f) -diff --git a/toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch b/toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch -new file mode 100644 -index 0000000..c41f35e ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/003-dont-choke-when-building-32bit-on-64bit.patch -@@ -0,0 +1,13 @@ -+--- a/gcc/real.h -++++ b/gcc/real.h -+@@ -77,8 +77,10 @@ struct GTY(()) real_value { -+ + (REAL_VALUE_TYPE_SIZE%HOST_BITS_PER_WIDE_INT ? 1 : 0)) /* round up */ -+ -+ /* Verify the guess. */ -++#ifndef __LP64__ -+ extern char test_real_width -+ [sizeof (REAL_VALUE_TYPE) <= REAL_WIDTH * sizeof (HOST_WIDE_INT) ? 1 : -1]; -++#endif -+ -+ /* Calculate the format for CONST_DOUBLE. We need as many slots as -+ are necessary to overlay a REAL_VALUE_TYPE on them. This could be -diff --git a/toolchain/gcc/patches-15.x/010-documentation.patch b/toolchain/gcc/patches-15.x/010-documentation.patch -new file mode 100644 -index 0000000..b3f0e12 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/010-documentation.patch -@@ -0,0 +1,35 @@ -+commit 098bd91f5eae625c7d2ee621e10930fc4434e5e2 -+Author: Luka Perkov -+Date: Tue Feb 26 16:16:33 2013 +0000 -+ -+ gcc: don't build documentation -+ -+ This closes #13039. -+ -+ Signed-off-by: Luka Perkov -+ -+ SVN-Revision: 35807 -+ -+--- a/gcc/Makefile.in -++++ b/gcc/Makefile.in -+@@ -3747,18 +3747,10 @@ doc/gcc.info: $(TEXI_GCC_FILES) -+ doc/gccint.info: $(TEXI_GCCINT_FILES) -+ doc/cppinternals.info: $(TEXI_CPPINT_FILES) -+ -+-doc/%.info: %.texi -+- if [ x$(BUILD_INFO) = xinfo ]; then \ -+- $(MAKEINFO) $(MAKEINFOFLAGS) -I . -I $(gcc_docdir) \ -+- -I $(gcc_docdir)/include -o $@ $<; \ -+- fi -++doc/%.info: -+ -+ # Duplicate entry to handle renaming of gccinstall.info -+-doc/gccinstall.info: $(TEXI_GCCINSTALL_FILES) -+- if [ x$(BUILD_INFO) = xinfo ]; then \ -+- $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \ -+- -I $(gcc_docdir)/include -o $@ $<; \ -+- fi -++doc/gccinstall.info: -+ -+ doc/cpp.dvi: $(TEXI_CPP_FILES) -+ doc/gcc.dvi: $(TEXI_GCC_FILES) -diff --git a/toolchain/gcc/patches-15.x/230-musl_libssp.patch b/toolchain/gcc/patches-15.x/230-musl_libssp.patch -new file mode 100644 -index 0000000..34eaac4 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/230-musl_libssp.patch -@@ -0,0 +1,13 @@ -+--- a/gcc/gcc.cc -++++ b/gcc/gcc.cc -+@@ -992,7 +992,9 @@ proper position among the other output f -+ #endif -+ -+ #ifndef LINK_SSP_SPEC -+-#ifdef TARGET_LIBC_PROVIDES_SSP -++#if DEFAULT_LIBC == LIBC_MUSL -++#define LINK_SSP_SPEC "-lssp_nonshared" -++#elif defined(TARGET_LIBC_PROVIDES_SSP) -+ #define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \ -+ "|fstack-protector-strong|fstack-protector-explicit:}" -+ #else -diff --git a/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch b/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch -new file mode 100644 -index 0000000..27b9657 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/300-mips_Os_cpu_rtx_cost_model.patch -@@ -0,0 +1,21 @@ -+commit ecf7671b769fe96f7b5134be442089f8bdba55d2 -+Author: Felix Fietkau -+Date: Thu Aug 4 20:29:45 2016 +0200 -+ -+gcc: add a patch to generate better code with Os on mips -+ -+Also happens to reduce compressed code size a bit -+ -+Signed-off-by: Felix Fietkau -+ -+--- a/gcc/config/mips/mips.cc -++++ b/gcc/config/mips/mips.cc -+@@ -20599,7 +20599,7 @@ mips_option_override (void) -+ flag_pcc_struct_return = 0; -+ -+ /* Decide which rtx_costs structure to use. */ -+- if (optimize_size) -++ if (0 && optimize_size) -+ mips_cost = &mips_rtx_cost_optimize_size; -+ else -+ mips_cost = &mips_rtx_cost_data[mips_tune]; -diff --git a/toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch b/toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch -new file mode 100644 -index 0000000..5c9d86a ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/810-arm-softfloat-libgcc.patch -@@ -0,0 +1,33 @@ -+commit 8570c4be394cff7282f332f97da2ff569a927ddb -+Author: Imre Kaloz -+Date: Wed Feb 2 20:06:12 2011 +0000 -+ -+ fixup arm soft-float symbols -+ -+ SVN-Revision: 25325 -+ -+--- a/libgcc/config/arm/t-linux -++++ b/libgcc/config/arm/t-linux -+@@ -1,6 +1,10 @@ -+ LIB1ASMSRC = arm/lib1funcs.S -+ LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \ -+- _ctzsi2 _arm_addsubdf3 _arm_addsubsf3 -++ _ctzsi2 _arm_addsubdf3 _arm_addsubsf3 \ -++ _arm_negdf2 _arm_muldivdf3 _arm_cmpdf2 _arm_unorddf2 \ -++ _arm_fixdfsi _arm_fixunsdfsi _arm_truncdfsf2 \ -++ _arm_negsf2 _arm_muldivsf3 _arm_cmpsf2 _arm_unordsf2 \ -++ _arm_fixsfsi _arm_fixunssfsi -+ -+ # Just for these, we omit the frame pointer since it makes such a big -+ # difference. -+--- a/gcc/config/arm/linux-elf.h -++++ b/gcc/config/arm/linux-elf.h -+@@ -58,8 +58,6 @@ -+ %{shared:-lc} \ -+ %{!shared:%{profile:-lc_p}%{!profile:-lc}}" -+ -+-#define LIBGCC_SPEC "%{mfloat-abi=soft*:-lfloat} -lgcc" -+- -+ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2" -+ -+ #define LINUX_TARGET_LINK_SPEC "%{h*} \ -diff --git a/toolchain/gcc/patches-15.x/820-libgcc_pic.patch b/toolchain/gcc/patches-15.x/820-libgcc_pic.patch -new file mode 100644 -index 0000000..f9691e5 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/820-libgcc_pic.patch -@@ -0,0 +1,44 @@ -+commit c96312958c0621e72c9b32da5bc224ffe2161384 -+Author: Felix Fietkau -+Date: Mon Oct 19 23:26:09 2009 +0000 -+ -+ gcc: create a proper libgcc_pic.a static library for relinking (4.3.3+ for now, backport will follow) -+ -+ SVN-Revision: 18086 -+ -+--- a/libgcc/Makefile.in -++++ b/libgcc/Makefile.in -+@@ -944,11 +944,12 @@ $(libgcov-driver-objects): %$(objext): $ -+ -+ # Static libraries. -+ libgcc.a: $(libgcc-objects) -++libgcc_pic.a: $(libgcc-s-objects) -+ libgcov.a: $(libgcov-objects) -+ libunwind.a: $(libunwind-objects) -+ libgcc_eh.a: $(libgcc-eh-objects) -+ -+-libgcc.a libgcov.a libunwind.a libgcc_eh.a: -++libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a: -+ -rm -f $@ -+ -+ objects="$(objects)"; \ -+@@ -972,7 +973,7 @@ all: libunwind.a -+ endif -+ -+ ifeq ($(enable_shared),yes) -+-all: libgcc_eh.a libgcc_s$(SHLIB_EXT) -++all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT) -+ ifneq ($(LIBUNWIND),) -+ all: libunwind$(SHLIB_EXT) -+ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_EXT) -+@@ -1181,6 +1182,10 @@ install-shared: -+ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a -+ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a -+ -++ $(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/ -++ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a -++ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a -++ -+ $(subst @multilib_dir@,$(MULTIDIR),$(subst \ -+ @shlib_base_name@,libgcc_s,$(subst \ -+ @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL)))) -diff --git a/toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch b/toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch -new file mode 100644 -index 0000000..e3cb616 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/840-armv4_pass_fix-v4bx_to_ld.patch -@@ -0,0 +1,28 @@ -+commit 7edc8ca5456d9743dd0075eb3cc5b04f4f24c8cc -+Author: Imre Kaloz -+Date: Wed Feb 2 19:34:36 2011 +0000 -+ -+ add armv4 fixup patches -+ -+ SVN-Revision: 25322 -+ -+ -+--- a/gcc/config/arm/linux-eabi.h -++++ b/gcc/config/arm/linux-eabi.h -+@@ -91,10 +91,15 @@ -+ #define MUSL_DYNAMIC_LINKER \ -+ "/lib/ld-musl-arm" MUSL_DYNAMIC_LINKER_E "%{mfloat-abi=hard:hf}%{mfdpic:-fdpic}.so.1" -+ -++/* For armv4 we pass --fix-v4bx to linker to support EABI */ -++#undef TARGET_FIX_V4BX_SPEC -++#define TARGET_FIX_V4BX_SPEC " %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*"\ -++ "|march=armv4|mcpu=fa526|mcpu=fa626:--fix-v4bx}" -++ -+ /* At this point, bpabi.h will have clobbered LINK_SPEC. We want to -+ use the GNU/Linux version, not the generic BPABI version. */ -+ #undef LINK_SPEC -+-#define LINK_SPEC EABI_LINK_SPEC \ -++#define LINK_SPEC EABI_LINK_SPEC TARGET_FIX_V4BX_SPEC \ -+ LINUX_OR_ANDROID_LD (LINUX_TARGET_LINK_SPEC, \ -+ LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC) -+ -diff --git a/toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch b/toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch -new file mode 100644 -index 0000000..210c790 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/850-use_shared_libgcc.patch -@@ -0,0 +1,54 @@ -+commit dcfc40358b5a3cae7320c17f8d1cebd5ad5540cd -+Author: Felix Fietkau -+Date: Sun Feb 12 20:25:47 2012 +0000 -+ -+ gcc 4.6: port over the missing patch 850-use_shared_libgcc.patch to prevent libgcc crap from leaking into every single binary -+ -+ SVN-Revision: 30486 -+--- a/gcc/config/arm/linux-eabi.h -++++ b/gcc/config/arm/linux-eabi.h -+@@ -132,10 +132,6 @@ -+ "%{Ofast|ffast-math|funsafe-math-optimizations:%{!shared:crtfastmath.o%s}} " \ -+ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_ENDFILE_SPEC, ANDROID_ENDFILE_SPEC) -+ -+-/* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we -+- do not use -lfloat. */ -+-#undef LIBGCC_SPEC -+- -+ /* Clear the instruction cache from `beg' to `end'. This is -+ implemented in lib1funcs.S, so ensure an error if this definition -+ is used. */ -+--- a/gcc/config/linux.h -++++ b/gcc/config/linux.h -+@@ -58,6 +58,10 @@ see the files COPYING3 and COPYING.RUNTI -+ builtin_assert ("system=posix"); \ -+ } while (0) -+ -++#ifndef LIBGCC_SPEC -++#define LIBGCC_SPEC "%{static|static-libgcc:-lgcc}%{!static:%{!static-libgcc:-lgcc_s}}" -++#endif -++ -+ /* Determine which dynamic linker to use depending on whether GLIBC or -+ uClibc or Bionic or musl is the default C library and whether -+ -muclibc or -mglibc or -mbionic or -mmusl has been passed to change -+--- a/libgcc/mkmap-symver.awk -++++ b/libgcc/mkmap-symver.awk -+@@ -136,5 +136,5 @@ function output(lib) { -+ else if (inherit[lib]) -+ printf("} %s;\n", inherit[lib]); -+ else -+- printf ("\n local:\n\t*;\n};\n"); -++ printf ("\n\t*;\n};\n"); -+ } -+--- a/gcc/config/rs6000/linux.h -++++ b/gcc/config/rs6000/linux.h -+@@ -70,6 +70,9 @@ -+ #undef CPP_OS_DEFAULT_SPEC -+ #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" -+ -++#undef LIBGCC_SPEC -++#define LIBGCC_SPEC "%{!static:%{!static-libgcc:-lgcc_s}} -lgcc" -++ -+ #undef LINK_SHLIB_SPEC -+ #define LINK_SHLIB_SPEC "%{shared:-shared} %{!shared: %{static:-static}} \ -+ %{static-pie:-static -pie --no-dynamic-linker -z text}" -diff --git a/toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch b/toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch -new file mode 100644 -index 0000000..d710e40 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/851-libgcc_no_compat.patch -@@ -0,0 +1,22 @@ -+commit 64661de100da1ec1061ef3e5e400285dce115e6b -+Author: Felix Fietkau -+Date: Sun May 10 13:16:35 2015 +0000 -+ -+ gcc: add some size optimization patches -+ -+ Signed-off-by: Felix Fietkau -+ -+ SVN-Revision: 45664 -+ -+--- a/libgcc/config/t-libunwind -++++ b/libgcc/config/t-libunwind -+@@ -2,8 +2,7 @@ -+ -+ HOST_LIBGCC2_CFLAGS += -DUSE_GAS_SYMVER -+ -+-LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \ -+- $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c -++LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c -+ LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c -+ -+ # Override the default value from t-slibgcc-elf-ver and mention -lunwind -diff --git a/toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch b/toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch -new file mode 100644 -index 0000000..0dca688 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/870-ppc_no_crtsavres.patch -@@ -0,0 +1,11 @@ -+--- a/gcc/config/rs6000/rs6000-logue.cc -++++ b/gcc/config/rs6000/rs6000-logue.cc -+@@ -344,7 +344,7 @@ rs6000_savres_strategy (rs6000_stack_t * -+ /* Define cutoff for using out-of-line functions to save registers. */ -+ if (DEFAULT_ABI == ABI_V4 || TARGET_ELF) -+ { -+- if (!optimize_size) -++ if (1) -+ { -+ strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS; -+ strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS; -diff --git a/toolchain/gcc/patches-15.x/881-no_tm_section.patch b/toolchain/gcc/patches-15.x/881-no_tm_section.patch -new file mode 100644 -index 0000000..2029910 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/881-no_tm_section.patch -@@ -0,0 +1,11 @@ -+--- a/libgcc/crtstuff.c -++++ b/libgcc/crtstuff.c -+@@ -152,7 +152,7 @@ call_ ## FUNC (void) \ -+ #endif -+ -+ #if !defined(USE_TM_CLONE_REGISTRY) && defined(OBJECT_FORMAT_ELF) -+-# define USE_TM_CLONE_REGISTRY 1 -++# define USE_TM_CLONE_REGISTRY 0 -+ #elif !defined(USE_TM_CLONE_REGISTRY) -+ # define USE_TM_CLONE_REGISTRY 0 -+ #endif -diff --git a/toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch b/toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch -new file mode 100644 -index 0000000..b355545 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/900-bad-mips16-crt.patch -@@ -0,0 +1,9 @@ -+--- a/libgcc/config/mips/t-mips16 -++++ b/libgcc/config/mips/t-mips16 -+@@ -42,3 +42,6 @@ SYNC_CFLAGS = -mno-mips16 -+ -+ # Version these symbols if building libgcc.so. -+ SHLIB_MAPFILES += $(srcdir)/config/mips/libgcc-mips16.ver -++ -++CRTSTUFF_T_CFLAGS += -mno-mips16 -++CRTSTUFF_T_CFLAGS_S += -mno-mips16 -diff --git a/toolchain/gcc/patches-15.x/910-mbsd_multi.patch b/toolchain/gcc/patches-15.x/910-mbsd_multi.patch -new file mode 100644 -index 0000000..c5462e1 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/910-mbsd_multi.patch -@@ -0,0 +1,146 @@ -+commit 99368862e44740ff4fd33760893f04e14f9dbdf1 -+Author: Felix Fietkau -+Date: Tue Jul 31 00:52:27 2007 +0000 -+ -+ Port the mbsd_multi patch from freewrt, which adds -fhonour-copts. This will emit warnings in packages that don't use our target cflags properly -+ -+ SVN-Revision: 8256 -+ -+ This patch brings over a feature from MirBSD: -+ * -fhonour-copts -+ If this option is not given, it's warned (depending -+ on environment variables). This is to catch errors -+ of misbuilt packages which override CFLAGS themselves. -+ -+ This patch was authored by Thorsten Glaser -+ with copyright assignment to the FSF in effect. -+ -+--- a/gcc/c-family/c-opts.cc -++++ b/gcc/c-family/c-opts.cc -+@@ -109,6 +109,9 @@ static size_t include_cursor; -+ /* Whether any standard preincluded header has been preincluded. */ -+ static bool done_preinclude; -+ -++/* Check if a port honours COPTS. */ -++static int honour_copts = 0; -++ -+ static void handle_OPT_d (const char *); -+ static void set_std_cxx98 (int); -+ static void set_std_cxx11 (int); -+@@ -503,6 +506,12 @@ c_common_handle_option (size_t scode, co -+ flag_no_builtin = !value; -+ break; -+ -++ case OPT_fhonour_copts: -++ if (c_language == clk_c) { -++ honour_copts++; -++ } -++ break; -++ -+ case OPT_fconstant_string_class_: -+ constant_string_class_name = arg; -+ break; -+@@ -1359,6 +1368,47 @@ c_common_init (void) -+ return false; -+ } -+ -++ if (c_language == clk_c) { -++ char *ev = getenv ("GCC_HONOUR_COPTS"); -++ int evv; -++ if (ev == NULL) -++ evv = -1; -++ else if ((*ev == '0') || (*ev == '\0')) -++ evv = 0; -++ else if (*ev == '1') -++ evv = 1; -++ else if (*ev == '2') -++ evv = 2; -++ else if (*ev == 's') -++ evv = -1; -++ else { -++ warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1"); -++ evv = 1; /* maybe depend this on something like MIRBSD_NATIVE? */ -++ } -++ if (evv == 1) { -++ if (honour_copts == 0) { -++ error ("someone does not honour COPTS at all in lenient mode"); -++ return false; -++ } else if (honour_copts != 1) { -++ warning (0, "someone does not honour COPTS correctly, passed %d times", -++ honour_copts); -++ } -++ } else if (evv == 2) { -++ if (honour_copts == 0) { -++ error ("someone does not honour COPTS at all in strict mode"); -++ return false; -++ } else if (honour_copts != 1) { -++ error ("someone does not honour COPTS correctly, passed %d times", -++ honour_copts); -++ return false; -++ } -++ } else if (evv == 0) { -++ if (honour_copts != 1) -++ inform (UNKNOWN_LOCATION, "someone does not honour COPTS correctly, passed %d times", -++ honour_copts); -++ } -++ } -++ -+ return true; -+ } -+ -+--- a/gcc/c-family/c.opt -++++ b/gcc/c-family/c.opt -+@@ -2008,6 +2008,9 @@ C++ ObjC++ Optimization Alias(fexception -+ fhonor-std -+ C++ ObjC++ WarnRemoved -+ -++fhonour-copts -++C ObjC C++ ObjC++ RejectNegative -++ -+ fhosted -+ C ObjC -+ Assume normal C execution environment. -+--- a/gcc/common.opt -++++ b/gcc/common.opt -+@@ -1938,6 +1938,9 @@ Enum(hardcfr_check_noreturn_calls) Strin -+ EnumValue -+ Enum(hardcfr_check_noreturn_calls) String(always) Value(HCFRNR_ALWAYS) -+ -++fhonour-copts -++Common RejectNegative -++ -+ ; Nonzero means ignore `#ident' directives. 0 means handle them. -+ ; Generate position-independent code for executables if possible -+ ; On SVR4 targets, it also controls whether or not to emit a -+--- a/gcc/doc/invoke.texi -++++ b/gcc/doc/invoke.texi -+@@ -10897,6 +10897,17 @@ This option is only supported for C and -+ -+ This warning is upgraded to an error by @option{-pedantic-errors}. -+ -++@item -fhonour-copts -++@opindex fhonour-copts -++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not -++given at least once, and warn if it is given more than once. -++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not -++given exactly once. -++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option -++is not given exactly once. -++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}. -++This flag and environment variable only affect the C language. -++ -+ @opindex Wstack-protector -+ @opindex Wno-stack-protector -+ @item -Wstack-protector -+--- a/gcc/opts.cc -++++ b/gcc/opts.cc -+@@ -2867,6 +2867,9 @@ common_handle_option (struct gcc_options -+ add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg); -+ break; -+ -++ case OPT_fhonour_copts: -++ break; -++ -+ case OPT_Werror: -+ dc->set_warning_as_error_requested (value); -+ break; -diff --git a/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch -new file mode 100644 -index 0000000..01591d2 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/920-specs_nonfatal_getenv.patch -@@ -0,0 +1,22 @@ -+Author: Jo-Philipp Wich -+Date: Sat Apr 21 03:02:39 2012 +0000 -+ -+ gcc: add patch to make the getenv() spec function nonfatal if requested environment variable is unset -+ -+ SVN-Revision: 31390 -+ -+--- a/gcc/gcc.cc -++++ b/gcc/gcc.cc -+@@ -10357,8 +10357,10 @@ getenv_spec_function (int argc, const ch -+ } -+ -+ if (!value) -+- fatal_error (input_location, -+- "environment variable %qs not defined", varname); -++ { -++ warning (input_location, "environment variable %qs not defined", varname); -++ value = ""; -++ } -+ -+ /* We have to escape every character of the environment variable so -+ they are not interpreted as active spec characters. A -diff --git a/toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch b/toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch -new file mode 100644 -index 0000000..b1d7576 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/960-gotools-fix-compilation-when-making-cross-compiler.patch -@@ -0,0 +1,67 @@ -+From dda6b050cd74a352670787a294596a9c56c21327 Mon Sep 17 00:00:00 2001 -+From: Yousong Zhou -+Date: Fri, 4 May 2018 18:20:53 +0800 -+Subject: [PATCH] gotools: fix compilation when making cross compiler -+ -+libgo is "the runtime support library for the Go programming language. -+This library is intended for use with the Go frontend." -+ -+gccgo will link target files with libgo.so which depends on libgcc_s.so.1, but -+the linker will complain that it cannot find it. That's because shared libgcc -+is not present in the install directory yet. libgo.so was made without problem -+because gcc will emit -lgcc_s when compiled with -shared option. When gotools -+were being made, it was supplied with -static-libgcc thus no link option was -+provided. Check LIBGO in gcc/go/gcc-spec.c for how gccgo make a builtin spec -+for linking with libgo.so -+ -+- GccgoCrossCompilation, https://github.com/golang/go/wiki/GccgoCrossCompilation -+- Cross-building instructions, http://www.eglibc.org/archives/patches/msg00078.html -+ -+When 3-pass GCC compilation is used, shared libgcc runtime libraries will be -+available after gcc pass2 completed and will meet the gotools link requirement -+at gcc pass3 -+--- -+ gotools/Makefile.am | 4 +++- -+ gotools/Makefile.in | 4 +++- -+ 2 files changed, 6 insertions(+), 2 deletions(-) -+ -+--- a/gotools/Makefile.am -++++ b/gotools/Makefile.am -+@@ -26,6 +26,7 @@ PWD_COMMAND = $${PWDCMD-pwd} -+ STAMP = echo timestamp > -+ -+ libgodir = ../$(target_noncanonical)/libgo -++libgccdir = ../$(target_noncanonical)/libgcc -+ LIBGODEP = $(libgodir)/libgo.la -+ -+ LIBGOTOOL = $(libgodir)/libgotool.a -+@@ -41,7 +42,8 @@ GOCFLAGS = $(CFLAGS_FOR_TARGET) -+ GOCOMPILE = $(GOCOMPILER) $(GOCFLAGS) -+ -+ AM_GOCFLAGS = -I $(libgodir) -+-AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs -++AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs \ -++ -L $(libgccdir) -L $(libgccdir)/.libs -lgcc_s -+ GOLINK = $(GOCOMPILER) $(GOCFLAGS) $(AM_GOCFLAGS) $(LDFLAGS) $(AM_LDFLAGS) -o $@ -+ -+ libgosrcdir = $(srcdir)/../libgo/go -+--- a/gotools/Makefile.in -++++ b/gotools/Makefile.in -+@@ -337,6 +337,7 @@ mkinstalldirs = $(SHELL) $(toplevel_srcd -+ PWD_COMMAND = $${PWDCMD-pwd} -+ STAMP = echo timestamp > -+ libgodir = ../$(target_noncanonical)/libgo -++libgccdir = ../$(target_noncanonical)/libgcc -+ LIBGODEP = $(libgodir)/libgo.la -+ LIBGOTOOL = $(libgodir)/libgotool.a -+ @NATIVE_FALSE@GOCOMPILER = $(GOC) -+@@ -346,7 +347,8 @@ LIBGOTOOL = $(libgodir)/libgotool.a -+ GOCFLAGS = $(CFLAGS_FOR_TARGET) -+ GOCOMPILE = $(GOCOMPILER) $(GOCFLAGS) -+ AM_GOCFLAGS = -I $(libgodir) -+-AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs -++AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs \ -++ -L $(libgccdir) -L $(libgccdir)/.libs -lgcc_s -+ GOLINK = $(GOCOMPILER) $(GOCFLAGS) $(AM_GOCFLAGS) $(LDFLAGS) $(AM_LDFLAGS) -o $@ -+ libgosrcdir = $(srcdir)/../libgo/go -+ cmdsrcdir = $(libgosrcdir)/cmd -diff --git a/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch b/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch -new file mode 100644 -index 0000000..cf0fd74 ---- /dev/null -+++ b/toolchain/gcc/patches-15.x/970-macos_arm64-building-fix.patch -@@ -0,0 +1,45 @@ -+commit 9c6e71079b46ad5433165feaa2001450f2017b56 -+Author: Przemysław Buczkowski -+Date: Mon Aug 16 13:16:21 2021 +0100 -+ -+ GCC: Patch for Apple Silicon compatibility -+ -+ This patch fixes a linker error occuring when compiling -+ the cross-compiler on macOS and ARM64 architecture. -+ -+ Adapted from: -+ https://github.com/richfelker/musl-cross-make/issues/116#issuecomment-823612404 -+ -+ Change-Id: Ia3ee98a163bbb62689f42e2da83a5ef36beb0913 -+ Reviewed-on: https://review.haiku-os.org/c/buildtools/+/4329 -+ Reviewed-by: John Scipione -+ Reviewed-by: Adrien Destugues -+ -+--- a/gcc/config/aarch64/aarch64.h -++++ b/gcc/config/aarch64/aarch64.h -+@@ -1469,7 +1469,7 @@ extern enum aarch64_code_model aarch64_c -+ -+ /* Extra specs when building a native AArch64-hosted compiler. -+ Option rewriting rules based on host system. */ -+-#if defined(__aarch64__) -++#if defined(__aarch64__) && ! defined(__APPLE__) -+ extern const char *host_detect_local_cpu (int argc, const char **argv); -+ #define HAVE_LOCAL_CPU_DETECT -+ # define EXTRA_SPEC_FUNCTIONS \ -+--- a/gcc/config/host-darwin.cc -++++ b/gcc/config/host-darwin.cc -+@@ -23,6 +23,8 @@ -+ #include "options.h" -+ #include "diagnostic-core.h" -+ #include "config/host-darwin.h" -++#include "hosthooks.h" -++#include "hosthooks-def.h" -+ #include -+ -+ /* For Darwin (macOS only) platforms, without ASLR (PIE) enabled on the -+@@ -181,3 +183,5 @@ darwin_gt_pch_use_address (void *&addr, -+ -+ return 1; -+ } -++ -++const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; --- -2.43.5 - diff --git a/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch b/openwrt/patch/generic-25.12/0001-tools-add-upx-tools.patch similarity index 89% rename from openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch rename to openwrt/patch/generic-25.12/0001-tools-add-upx-tools.patch index 51692fcff..d86615cfe 100644 --- a/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch +++ b/openwrt/patch/generic-25.12/0001-tools-add-upx-tools.patch @@ -1,7 +1,7 @@ -From d9fe4db89fcc215510319db72e415a83c861a040 Mon Sep 17 00:00:00 2001 +From de1387e3780afbb3a79e361f3b97124eca6c0aa0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:39:25 +0800 -Subject: [PATCH 01/10] tools: add upx tools +Subject: [PATCH 01/13] tools: add upx tools Signed-off-by: sbwml --- @@ -11,10 +11,10 @@ Signed-off-by: sbwml create mode 100644 tools/upx/Makefile diff --git a/tools/Makefile b/tools/Makefile -index b16c5d9..702184a 100644 +index 79d3954..42b1265 100644 --- a/tools/Makefile +++ b/tools/Makefile -@@ -66,6 +66,7 @@ tools-y += pkgconf +@@ -67,6 +67,7 @@ tools-y += pkgconf tools-y += quilt tools-y += squashfs4 tools-y += sstrip diff --git a/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch b/openwrt/patch/generic-25.12/0002-rootfs-add-upx-compression-support.patch similarity index 83% rename from openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch rename to openwrt/patch/generic-25.12/0002-rootfs-add-upx-compression-support.patch index 0b399c14d..76ba78cd7 100644 --- a/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch +++ b/openwrt/patch/generic-25.12/0002-rootfs-add-upx-compression-support.patch @@ -1,7 +1,7 @@ -From a85660738779248ea2c2cd44a11b7f4602875671 Mon Sep 17 00:00:00 2001 +From 54de7991f8fcfe4399e476f385286e02517cca9e Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:46:49 +0800 -Subject: [PATCH 02/10] rootfs: add upx compression support +Subject: [PATCH 02/13] rootfs: add upx compression support * When the upx_list.txt file exists in the source code root directory, it will be compressed by upx. @@ -18,10 +18,10 @@ Signed-off-by: sbwml 1 file changed, 5 insertions(+) diff --git a/include/rootfs.mk b/include/rootfs.mk -index e6cadc5..574e3fe 100644 +index 02fa3b1..f778aef 100644 --- a/include/rootfs.mk +++ b/include/rootfs.mk -@@ -120,6 +120,11 @@ define prepare_rootfs +@@ -121,6 +121,11 @@ define prepare_rootfs $(1)/usr/lib/opkg/info/*.postinst* \ $(1)/usr/lib/opkg/lists/* \ $(1)/var/lock/*.lock diff --git a/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch b/openwrt/patch/generic-25.12/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch similarity index 74% rename from openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch rename to openwrt/patch/generic-25.12/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch index 0aeddb27b..1e77aa0df 100644 --- a/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch +++ b/openwrt/patch/generic-25.12/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch @@ -1,7 +1,7 @@ -From b557005f9d3164de1f23a0239647f25d07b0b389 Mon Sep 17 00:00:00 2001 +From c2e70e8b792bd3c99fe5584966ab69edcd6ead42 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:47:41 +0800 -Subject: [PATCH 03/10] rootfs: add r/w permissions for UCI configuration files +Subject: [PATCH 03/13] rootfs: add r/w permissions for UCI configuration files Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 1 insertion(+) diff --git a/include/rootfs.mk b/include/rootfs.mk -index 574e3fe..00203a4 100644 +index f778aef..d049ca5 100644 --- a/include/rootfs.mk +++ b/include/rootfs.mk -@@ -125,6 +125,7 @@ define prepare_rootfs +@@ -126,6 +126,7 @@ define prepare_rootfs $(STAGING_DIR_HOST)/bin/upx --lzma --best "$(1)$$file" || true; \ done < "$(TOPDIR)/upx_list.txt"; \ fi diff --git a/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch b/openwrt/patch/generic-25.12/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch similarity index 83% rename from openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch rename to openwrt/patch/generic-25.12/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch index 6f1a2db1a..2375db580 100644 --- a/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch +++ b/openwrt/patch/generic-25.12/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch @@ -1,7 +1,7 @@ -From 5c52ffb8e9e708c663359d5f8a8d609ca8cfd409 Mon Sep 17 00:00:00 2001 +From 24cf67d16f2a819eeaa937e888ef974993c2455a Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:48:29 +0800 -Subject: [PATCH 04/10] rootfs: Add support for local kmod installation sources +Subject: [PATCH 04/13] rootfs: Add support for local kmod installation sources * CONFIG_TARGET_ROOTFS_LOCAL_PACKAGES=y @@ -12,10 +12,10 @@ Signed-off-by: sbwml 2 files changed, 14 insertions(+) diff --git a/config/Config-images.in b/config/Config-images.in -index 47f3dfc..ed9ecb2 100644 +index fcc5fa5..8094136 100644 --- a/config/Config-images.in +++ b/config/Config-images.in -@@ -322,4 +322,12 @@ menu "Target Images" +@@ -356,4 +356,12 @@ menu "Target Images" across reboots. When enabled, /var/run will still be linked to /tmp/run. @@ -29,10 +29,10 @@ index 47f3dfc..ed9ecb2 100644 + endmenu diff --git a/include/rootfs.mk b/include/rootfs.mk -index 00203a4..0bea0c1 100644 +index d049ca5..cb19964 100644 --- a/include/rootfs.mk +++ b/include/rootfs.mk -@@ -126,6 +126,12 @@ define prepare_rootfs +@@ -127,6 +127,12 @@ define prepare_rootfs done < "$(TOPDIR)/upx_list.txt"; \ fi chmod 600 $(1)/etc/config/* diff --git a/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch b/openwrt/patch/generic-25.12/0005-kernel-Add-support-for-llvm-clang-compiler.patch similarity index 90% rename from openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch rename to openwrt/patch/generic-25.12/0005-kernel-Add-support-for-llvm-clang-compiler.patch index 3e7fafb95..32ae04a83 100644 --- a/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch +++ b/openwrt/patch/generic-25.12/0005-kernel-Add-support-for-llvm-clang-compiler.patch @@ -1,7 +1,7 @@ -From b196c42657703b93c93210bf6743f2aa745a88bc Mon Sep 17 00:00:00 2001 +From 5019245030b26f3602095de80ab7fc43051e37a2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:51:22 +0800 -Subject: [PATCH 05/10] kernel: Add support for llvm/clang compiler +Subject: [PATCH 05/13] kernel: Add support for llvm/clang compiler Signed-off-by: sbwml --- @@ -11,10 +11,10 @@ Signed-off-by: sbwml 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/config/Config-devel.in b/config/Config-devel.in -index cbac91c..9079303 100644 +index 3fe78f3..46287bf 100644 --- a/config/Config-devel.in +++ b/config/Config-devel.in -@@ -95,6 +95,13 @@ menuconfig DEVEL +@@ -149,6 +149,13 @@ menuconfig DEVEL default "-falign-functions=32" if TARGET_bcm53xx default "" @@ -60,7 +60,7 @@ index 6ef7663..1648a6f 100644 -nostdinc $(if $(DUMP),, -isystem $(shell $(TARGET_CC) -print-file-name=include)) diff --git a/include/package.mk b/include/package.mk -index 7fbecf9..3e988ed 100644 +index 5392bdf..5bcc4f3 100644 --- a/include/package.mk +++ b/include/package.mk @@ -23,6 +23,10 @@ else diff --git a/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch b/openwrt/patch/generic-25.12/0006-build-kernel-add-out-of-tree-kernel-config.patch similarity index 95% rename from openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch rename to openwrt/patch/generic-25.12/0006-build-kernel-add-out-of-tree-kernel-config.patch index e809782a3..2f2af1951 100644 --- a/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch +++ b/openwrt/patch/generic-25.12/0006-build-kernel-add-out-of-tree-kernel-config.patch @@ -1,7 +1,7 @@ -From 2ad612d3af7e88120052d1772fdacd6cce109f58 Mon Sep 17 00:00:00 2001 +From 687ed9e452ea3ce1508af0c661eba9019dc5d16d Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:56:57 +0800 -Subject: [PATCH 06/10] build: kernel: add out-of-tree kernel config +Subject: [PATCH 06/13] build: kernel: add out-of-tree kernel config Signed-off-by: sbwml --- @@ -10,10 +10,10 @@ Signed-off-by: sbwml 2 files changed, 79 insertions(+) diff --git a/config/Config-devel.in b/config/Config-devel.in -index 9079303..2cbefc2 100644 +index 46287bf..a73832e 100644 --- a/config/Config-devel.in +++ b/config/Config-devel.in -@@ -102,6 +102,13 @@ menuconfig DEVEL +@@ -156,6 +156,13 @@ menuconfig DEVEL Enter C compiler name or full pathname i.e.: clang If not set, uses '$(TARGET_CC)' @@ -28,10 +28,10 @@ index 9079303..2cbefc2 100644 string "Use external kernel tree" if DEVEL default "" diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index f94ed33..6ec2e75 100644 +index bdfdaaa..f1202bc 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk -@@ -108,6 +108,78 @@ define Kernel/SetNoInitramfs +@@ -107,6 +107,78 @@ define Kernel/SetNoInitramfs echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config.set diff --git a/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch b/openwrt/patch/generic-25.12/0007-include-kernel-add-miss-config-for-linux-6.11.patch similarity index 78% rename from openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch rename to openwrt/patch/generic-25.12/0007-include-kernel-add-miss-config-for-linux-6.11.patch index 655ad22d2..12eb422dd 100644 --- a/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch +++ b/openwrt/patch/generic-25.12/0007-include-kernel-add-miss-config-for-linux-6.11.patch @@ -1,7 +1,7 @@ -From 6243d903b853abbc81a3258356155f207e2c0853 Mon Sep 17 00:00:00 2001 +From 8a78c2447e9842da14227edbddd5989bc399a04a Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:29 +0800 -Subject: [PATCH 07/10] include: kernel: add miss config for linux-6.11 +Subject: [PATCH 07/13] include: kernel: add miss config for linux-6.11 Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 1 insertion(+) diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk -index 6ec2e75..ea97998 100644 +index f1202bc..20b3a12 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk -@@ -108,6 +108,7 @@ define Kernel/SetNoInitramfs +@@ -107,6 +107,7 @@ define Kernel/SetNoInitramfs echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config.set diff --git a/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch b/openwrt/patch/generic-25.12/0008-meson-add-platform-variable-to-cross-compilation-fil.patch similarity index 82% rename from openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch rename to openwrt/patch/generic-25.12/0008-meson-add-platform-variable-to-cross-compilation-fil.patch index c0dcd162a..d6285e97a 100644 --- a/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch +++ b/openwrt/patch/generic-25.12/0008-meson-add-platform-variable-to-cross-compilation-fil.patch @@ -1,7 +1,7 @@ -From dc0aa15d94e848f1f96e70a9e8068ad798aaba22 Mon Sep 17 00:00:00 2001 +From 643e0796f188993c5caea1655c4836aae8307336 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 4 Oct 2024 10:58:54 +0800 -Subject: [PATCH 08/10] meson: add platform variable to cross-compilation file +Subject: [PATCH 08/13] meson: add platform variable to cross-compilation file Signed-off-by: sbwml --- @@ -10,10 +10,10 @@ Signed-off-by: sbwml 2 files changed, 2 insertions(+) diff --git a/include/meson.mk b/include/meson.mk -index ff452d8..8ac801b 100644 +index 62dc7bd..91cd7e6 100644 --- a/include/meson.mk +++ b/include/meson.mk -@@ -90,6 +90,7 @@ define Meson/CreateCrossFile +@@ -96,6 +96,7 @@ define Meson/CreateCrossFile -e "s|@LDFLAGS@|$(foreach FLAG,$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS),'$(FLAG)',)|" \ -e "s|@ARCH@|$(MESON_ARCH)|" \ -e "s|@CPU@|$(MESON_CPU)|" \ diff --git a/openwrt/patch/generic-25.12/0009-tools-squashfs4-enable-lz4-zstd-compression-support.patch b/openwrt/patch/generic-25.12/0009-tools-squashfs4-enable-lz4-zstd-compression-support.patch new file mode 100644 index 000000000..136dbb86a --- /dev/null +++ b/openwrt/patch/generic-25.12/0009-tools-squashfs4-enable-lz4-zstd-compression-support.patch @@ -0,0 +1,29 @@ +From 2959e6624a39b223527d654828022fe1d79ea6fc Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 21 Dec 2025 15:14:08 +0800 +Subject: [PATCH 09/13] tools: squashfs4: enable lz4 & zstd compression support + +Signed-off-by: sbwml +--- + tools/squashfs4/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/squashfs4/Makefile b/tools/squashfs4/Makefile +index 6b88735..31c884a 100644 +--- a/tools/squashfs4/Makefile ++++ b/tools/squashfs4/Makefile +@@ -24,9 +24,9 @@ include $(INCLUDE_DIR)/host-build.mk + define Host/Compile + +$(HOST_MAKE_VARS) \ + $(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR)/squashfs-tools \ +- LZ4_SUPPORT=0 \ ++ LZ4_SUPPORT=1 \ + LZO_SUPPORT=0 \ +- ZSTD_SUPPORT=0 \ ++ ZSTD_SUPPORT=1 \ + GZIP_SUPPORT=1 \ + XZ_SUPPORT=1 \ + LZMA_XZ_SUPPORT=1 \ +-- +2.43.5 + diff --git a/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch b/openwrt/patch/generic-25.12/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch similarity index 88% rename from openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch rename to openwrt/patch/generic-25.12/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch index a3819d478..5d730bab3 100644 --- a/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch +++ b/openwrt/patch/generic-25.12/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch @@ -1,7 +1,7 @@ -From 53ff6a6a2bdeb5173d5ea0b3795b36737af8abb3 Mon Sep 17 00:00:00 2001 +From 5ebcd78dec9b1c9cd5ca4abaad34abe6a794058c Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 12 Oct 2024 08:36:46 +0800 -Subject: [PATCH 10/10] kernel: add PREEMPT_RT support for aarch64/x86_64 +Subject: [PATCH 10/13] kernel: add PREEMPT_RT support for aarch64/x86_64 Signed-off-by: sbwml --- @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 13 insertions(+) diff --git a/config/Config-kernel.in b/config/Config-kernel.in -index eb0f000..76092d4 100644 +index 8692063..6c75038 100644 --- a/config/Config-kernel.in +++ b/config/Config-kernel.in @@ -20,6 +20,19 @@ config KERNEL_BUILD_DOMAIN diff --git a/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch b/openwrt/patch/generic-25.12/0011-config-include-image-add-support-for-squashfs-zstd-c.patch similarity index 61% rename from openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch rename to openwrt/patch/generic-25.12/0011-config-include-image-add-support-for-squashfs-zstd-c.patch index 5e7b874f3..4cc620bc2 100644 --- a/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch +++ b/openwrt/patch/generic-25.12/0011-config-include-image-add-support-for-squashfs-zstd-c.patch @@ -1,22 +1,22 @@ -From 6b33c9bae79c972a711da6b719c2e924ba76b16a Mon Sep 17 00:00:00 2001 +From 0649947c4c8d0b21bd40124c3d2bd004c0118549 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 29 May 2025 17:12:37 +0800 -Subject: [PATCH 12/12] config/include: image: add support for squashfs zstd +Subject: [PATCH 11/13] config/include: image: add support for squashfs zstd compression algorithm Signed-off-by: sbwml --- config/Config-images.in | 7 +++++++ - include/image.mk | 3 +++ - 2 files changed, 10 insertions(+) + include/image.mk | 4 ++++ + 2 files changed, 11 insertions(+) diff --git a/config/Config-images.in b/config/Config-images.in -index ed9ecb2..8b91b7f 100644 +index 8094136..3721292 100644 --- a/config/Config-images.in +++ b/config/Config-images.in -@@ -160,6 +160,13 @@ menu "Target Images" - Select squashfs block size, must be one of: - 4, 8, 16, 32, 64, 128, 256, 512, 1024 +@@ -194,6 +194,13 @@ menu "Target Images" + Specify the number of parallel small file reader threads + (for files less than the squashfs block size). + config TARGET_ROOTFS_SQUASHFS_ZSTD + bool "SquashFS Zstd" @@ -29,19 +29,20 @@ index ed9ecb2..8b91b7f 100644 bool "ubifs" default y if USES_UBIFS diff --git a/include/image.mk b/include/image.mk -index 9a4dff2..b121622 100644 +index 38005b2..078d2f7 100644 --- a/include/image.mk +++ b/include/image.mk -@@ -94,6 +94,9 @@ ifeq ($(CONFIG_SQUASHFS_XZ),y) - endif +@@ -100,6 +100,10 @@ ifeq ($(CONFIG_SQUASHFS_XZ),y) SQUASHFSCOMP := xz $(LZMA_XZ_OPTIONS) $(BCJ_FILTER) endif + +ifeq ($(CONFIG_TARGET_ROOTFS_SQUASHFS_ZSTD),y) + SQUASHFSCOMP := zstd -Xcompression-level 22 +endif - ++ JFFS2_BLOCKSIZE ?= 64k 128k + EROFS_PCLUSTERSIZE = $(shell echo $$(($(CONFIG_TARGET_EROFS_PCLUSTER_SIZE)*1024))) -- 2.43.5 diff --git a/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch b/openwrt/patch/generic-25.12/0012-include-kernel-Always-collect-module-symvers.patch similarity index 90% rename from openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch rename to openwrt/patch/generic-25.12/0012-include-kernel-Always-collect-module-symvers.patch index 60cf3035e..d14365c62 100644 --- a/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch +++ b/openwrt/patch/generic-25.12/0012-include-kernel-Always-collect-module-symvers.patch @@ -1,7 +1,7 @@ -From f499ed288826b284cdb4a4e5563cbcc45a31ef71 Mon Sep 17 00:00:00 2001 +From 13032f8109b35d761d61d0631b73b305299078f4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 26 Oct 2025 16:12:19 +0800 -Subject: [PATCH] include: kernel: Always collect module symvers +Subject: [PATCH 12/13] include: kernel: Always collect module symvers Signed-off-by: sbwml --- diff --git a/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch b/openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch similarity index 82% rename from openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch rename to openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch index bf3243b90..de8fe5f01 100644 --- a/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch +++ b/openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch @@ -1,13 +1,13 @@ -From e952be9f0d42ecb6dc18ab0b29611e7c6a3fe800 Mon Sep 17 00:00:00 2001 +From 431c5f546692b996a40500aea48eea9c1412af36 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 31 Oct 2025 12:32:08 +0800 -Subject: [PATCH] include: netfilter: update kernel config options for legacy - iptables and ebtables +Subject: [PATCH 13/13] include: netfilter: update kernel config options for + legacy iptables and ebtables Signed-off-by: sbwml --- - include/netfilter.mk | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) + include/netfilter.mk | 2 ++ + 1 file changed, 2 insertions(+) diff --git a/include/netfilter.mk b/include/netfilter.mk index 255e478..afe9d4d 100644 diff --git a/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch b/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch deleted file mode 100644 index c63673d7f..000000000 --- a/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch +++ /dev/null @@ -1,158 +0,0 @@ -From ca7f11ebc4d4a99ccfd44be8555d505b26996c12 Mon Sep 17 00:00:00 2001 -From: Arjun Roy -Date: Mon, 25 Jul 2022 12:49:35 -0400 -Subject: [PATCH 2/2] ss: output TCP BBRv3 diag information - -Add logic for printing diag information for TCP BBRv3 congestion -control. This commit leaves in place the support for printing the -earlier TCP BBRv1 congestion control information. - -Both BBRv1 and BBRv3 are using the same enum value. The BBRv3 struct -starts with the same data as BBRv1, so it is is backward-compatible -with BBRv1, to allow lder ss binaries to print basic information for -BBRv3. We use the size of the returned data and the version field to -check the version of the data. - -Signed-off-by: Arjun Roy -Signed-off-by: Neal Cardwell -Signed-off-by: David Morley ---- - include/uapi/linux/inet_diag.h | 23 ++++++++++++ - misc/ss.c | 66 +++++++++++++++++++++++++++++++++- - 2 files changed, 88 insertions(+), 1 deletion(-) - ---- a/include/uapi/linux/inet_diag.h -+++ b/include/uapi/linux/inet_diag.h -@@ -229,6 +229,29 @@ struct tcp_bbr_info { - __u32 bbr_min_rtt; /* min-filtered RTT in uSec */ - __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */ - __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */ -+ __u32 bbr_bw_hi_lsb; /* lower 32 bits of bw_hi */ -+ __u32 bbr_bw_hi_msb; /* upper 32 bits of bw_hi */ -+ __u32 bbr_bw_lo_lsb; /* lower 32 bits of bw_lo */ -+ __u32 bbr_bw_lo_msb; /* upper 32 bits of bw_lo */ -+ __u8 bbr_mode; /* current bbr_mode in state machine */ -+ __u8 bbr_phase; /* current state machine phase */ -+ __u8 unused1; /* alignment padding; not used yet */ -+ __u8 bbr_version; /* BBR algorithm version */ -+ __u32 bbr_inflight_lo; /* lower short-term data volume bound */ -+ __u32 bbr_inflight_hi; /* higher long-term data volume bound */ -+ __u32 bbr_extra_acked; /* max excess packets ACKed in epoch */ -+}; -+ -+/* TCP BBR congestion control bbr_phase as reported in netlink/ss stats. */ -+enum tcp_bbr_phase { -+ BBR_PHASE_INVALID = 0, -+ BBR_PHASE_STARTUP = 1, -+ BBR_PHASE_DRAIN = 2, -+ BBR_PHASE_PROBE_RTT = 3, -+ BBR_PHASE_PROBE_BW_UP = 4, -+ BBR_PHASE_PROBE_BW_DOWN = 5, -+ BBR_PHASE_PROBE_BW_CRUISE = 6, -+ BBR_PHASE_PROBE_BW_REFILL = 7, - }; - - union tcp_cc_info { ---- a/misc/ss.c -+++ b/misc/ss.c -@@ -895,6 +895,7 @@ struct tcpstat { - bool app_limited; - struct dctcpstat *dctcp; - struct tcp_bbr_info *bbr_info; -+ unsigned int bbr_info_len; - }; - - /* SCTP assocs share the same inode number with their parent endpoint. So if we -@@ -2597,6 +2598,29 @@ static void sctp_stats_print(struct sctp - out(" fraginl:%d", s->sctpi_s_frag_interleave); - } - -+static const char* bbr_phase_to_str(enum tcp_bbr_phase phase) -+{ -+ switch (phase) { -+ case BBR_PHASE_STARTUP: -+ return "STARTUP"; -+ case BBR_PHASE_DRAIN: -+ return "DRAIN"; -+ case BBR_PHASE_PROBE_RTT: -+ return "PROBE_RTT"; -+ case BBR_PHASE_PROBE_BW_UP: -+ return "PROBE_BW_UP"; -+ case BBR_PHASE_PROBE_BW_DOWN: -+ return "PROBE_BW_DOWN"; -+ case BBR_PHASE_PROBE_BW_CRUISE: -+ return "PROBE_BW_CRUISE"; -+ case BBR_PHASE_PROBE_BW_REFILL: -+ return "PROBE_BW_REFILL"; -+ case BBR_PHASE_INVALID: -+ default: -+ return "INVALID"; -+ } -+} -+ - static void tcp_stats_print(struct tcpstat *s) - { - char b1[64]; -@@ -2672,7 +2696,14 @@ static void tcp_stats_print(struct tcpst - } - - if (s->bbr_info) { -- __u64 bw; -+ /* All versions of the BBR algorithm use the INET_DIAG_BBRINFO -+ * enum value. Later versions of the tcp_bbr_info struct are -+ * backward-compatible with earlier versions, to allow older ss -+ * binaries to print basic information for newer versions of -+ * the algorithm. We use the size of the returned tcp_bbr_info -+ * struct to decide how much to print. -+ */ -+ __u64 bw, bw_hi, bw_lo; - - bw = s->bbr_info->bbr_bw_hi; - bw <<= 32; -@@ -2687,6 +2718,38 @@ static void tcp_stats_print(struct tcpst - if (s->bbr_info->bbr_cwnd_gain) - out(",cwnd_gain:%g", - (double)s->bbr_info->bbr_cwnd_gain / 256.0); -+ -+ if (s->bbr_info_len >= -+ (offsetof(struct tcp_bbr_info, bbr_extra_acked) + -+ sizeof(__u32))) { -+ -+ bw_hi = s->bbr_info->bbr_bw_hi_msb; -+ bw_hi <<= 32; -+ bw_hi |= s->bbr_info->bbr_bw_hi_lsb; -+ -+ bw_lo = s->bbr_info->bbr_bw_lo_msb; -+ bw_lo <<= 32; -+ bw_lo |= s->bbr_info->bbr_bw_lo_lsb; -+ -+ out(",version:%u", s->bbr_info->bbr_version); -+ if (bw_hi != ~0UL) -+ out(",bw_hi:%sbps", sprint_bw(b1, bw_hi * 8.0)); -+ if (bw_lo != ~0UL) -+ out(",bw_lo:%sbps", sprint_bw(b1, bw_lo * 8.0)); -+ if (s->bbr_info->bbr_inflight_hi != ~0U) -+ out(",inflight_hi:%u", -+ s->bbr_info->bbr_inflight_hi); -+ if (s->bbr_info->bbr_inflight_lo != ~0U) -+ out(",inflight_lo:%u", -+ s->bbr_info->bbr_inflight_lo); -+ out(",extra_acked:%u", s->bbr_info->bbr_extra_acked); -+ out(",mode:%d", (int)s->bbr_info->bbr_mode); -+ out(",phase:%s", -+ bbr_phase_to_str( -+ (enum tcp_bbr_phase) -+ s->bbr_info->bbr_phase)); -+ } -+ - out(")"); - } - -@@ -3174,6 +3237,7 @@ static void tcp_show_info(const struct n - s.bbr_info = calloc(1, sizeof(*s.bbr_info)); - if (s.bbr_info && bbr_info) - memcpy(s.bbr_info, bbr_info, len); -+ s.bbr_info_len = len; - } - - if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) { diff --git a/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch b/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch deleted file mode 100644 index 80b9b7132..000000000 --- a/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 537b1b761e1d0036923adba7a80d3655cfff095d Mon Sep 17 00:00:00 2001 -From: David Morley -Date: Fri, 21 Jul 2023 09:20:46 +0000 -Subject: [PATCH 1/2] ip: introduce the ecn_low per-route feature - -Add a a new "ecn_low" feature that administrators can add to a -particular ip route. The ecn_low feature indicates that the given -destination network is a low-latency ECN environment, meaning both -that ECN CE marks are applied by the network using a low-latency -marking threshold and also that TCP endpoints provide precise -per-data-segment ECN feedback in ACKs (where the ACK ECE flag echoes -the received CE status of all newly-acknowledged data segments). This -ecn_low feature indication can be used by congestion control -algorithms to decide how to interpret ECN signals over the given -destination network. - -Signed-off-by: David Morley -Signed-off-by: Neal Cardwell ---- - include/uapi/linux/rtnetlink.h | 4 +++- - ip/iproute.c | 8 +++++++- - man/man8/ip-route.8.in | 19 ++++++++++++++----- - 3 files changed, 24 insertions(+), 7 deletions(-) - ---- a/include/uapi/linux/rtnetlink.h -+++ b/include/uapi/linux/rtnetlink.h -@@ -508,12 +508,14 @@ enum { - #define RTAX_FEATURE_TIMESTAMP (1 << 2) /* unused */ - #define RTAX_FEATURE_ALLFRAG (1 << 3) /* unused */ - #define RTAX_FEATURE_TCP_USEC_TS (1 << 4) -+#define RTAX_FEATURE_ECN_LOW (1 << 5) - - #define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | \ - RTAX_FEATURE_SACK | \ - RTAX_FEATURE_TIMESTAMP | \ - RTAX_FEATURE_ALLFRAG | \ -- RTAX_FEATURE_TCP_USEC_TS) -+ RTAX_FEATURE_TCP_USEC_TS | \ -+ RTAX_FEATURE_ECN_LOW) - - struct rta_session { - __u8 proto; ---- a/ip/iproute.c -+++ b/ip/iproute.c -@@ -97,7 +97,7 @@ static void usage(void) - "PREF := [ low | medium | high ]\n" - "TIME := NUMBER[s|ms]\n" - "BOOL := [1|0]\n" -- "FEATURES := ecn\n" -+ "FEATURES := [ ecn | ecn_low ]\n" - "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 | xfrm ]\n" - "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR | XFRMINFO ]\n" - "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n" -@@ -373,6 +373,10 @@ static void print_rtax_features(FILE *fp - print_null(PRINT_ANY, "ecn", "ecn ", NULL); - features &= ~RTAX_FEATURE_ECN; - } -+ if (features & RTAX_FEATURE_ECN_LOW) { -+ print_null(PRINT_ANY, "ecn_low", "ecn_low ", NULL); -+ features &= ~RTAX_FEATURE_ECN_LOW; -+ } - - if (features & RTAX_FEATURE_TCP_USEC_TS) { - print_null(PRINT_ANY, "tcp_usec_ts", "tcp_usec_ts ", NULL); -@@ -1381,6 +1385,8 @@ static int iproute_modify(int cmd, unsig - features |= RTAX_FEATURE_ECN; - else if (strcmp(*argv, "tcp_usec_ts") == 0) - features |= RTAX_FEATURE_TCP_USEC_TS; -+ else if (strcmp(*argv, "ecn_low") == 0) -+ features |= RTAX_FEATURE_ECN_LOW; - else - invarg("\"features\" value not valid\n", *argv); - break; ---- a/man/man8/ip-route.8.in -+++ b/man/man8/ip-route.8.in -@@ -184,7 +184,7 @@ throw " | " unreachable " | " prohibit " - - .ti -8 - .IR FEATURES " := [ " --.BR ecn " | ]" -+.BR ecn " | " ecn_low " ] " - - .ti -8 - .IR PREF " := [ " -@@ -556,16 +556,25 @@ The default value is zero, meaning to us - - .TP - .BI features " FEATURES " (Linux 3.18+ only) --Enable or disable per-route features. Only available feature at this --time is --.B ecn --to enable explicit congestion notification when initiating connections to the -+Enable or disable per-route features. Available features include: -+ -+.BI ecn -+- to enable explicit congestion notification when initiating connections to the - given destination network. - When responding to a connection request from the given network, ecn will - also be used even if the - .B net.ipv4.tcp_ecn - sysctl is set to 0. - -+.BI ecn_low -+- to indicate that the given destination network is a low-latency ECN -+environment, meaning both that ECN CE marks are applied by the network using a -+low-latency marking threshold and also that TCP endpoints provide precise -+per-data-segment ECN feedback in ACKs (where the ACK ECE flag echoes the -+received CE status of all newly-acknowledged data segments). This ecn_low -+feature indication can be used by congestion control algorithms to decide how -+to interpret ECN signals over the given destination network (Linux 6.7+ only). -+ - .TP - .BI quickack " BOOL " "(Linux 3.11+ only)" - Enable or disable quick ack for connections to this destination. diff --git a/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch b/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch deleted file mode 100644 index 91b9fe69c..000000000 --- a/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 107339d7f48c95ae8a7461150e143fc53b08fea9 Mon Sep 17 00:00:00 2001 -From: Neal Cardwell -Date: Sun, 23 Jul 2023 23:33:21 -0400 -Subject: [PATCH] ss: display "ecn_low" if tcp_info tcpi_options - TCPI_OPT_ECN_LOW bit is set - -Display "ecn_low" if the TCPI_OPT_ECN_LOW bit is set in the -tcpi_options field in tcp_info. - -Signed-off-by: Neal Cardwell ---- - include/uapi/linux/tcp.h | 1 + - misc/ss.c | 4 ++++ - 2 files changed, 5 insertions(+) - ---- a/include/uapi/linux/tcp.h -+++ b/include/uapi/linux/tcp.h -@@ -178,6 +178,7 @@ enum tcp_fastopen_client_fail { - #define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */ - #define TCPI_OPT_SYN_DATA 32 /* SYN-ACK acked data in SYN sent or rcvd */ - #define TCPI_OPT_USEC_TS 64 /* usec timestamps */ -+#define TCPI_OPT_ECN_LOW 64 /* Low-latency ECN configured at init */ - - /* - * Sender's congestion state indicating normal or abnormal situations ---- a/misc/ss.c -+++ b/misc/ss.c -@@ -890,6 +890,7 @@ struct tcpstat { - bool has_sack_opt; - bool has_ecn_opt; - bool has_ecnseen_opt; -+ bool has_ecn_low_opt; - bool has_fastopen_opt; - bool has_wscale_opt; - bool app_limited; -@@ -2635,6 +2636,8 @@ static void tcp_stats_print(struct tcpst - out(" ecn"); - if (s->has_ecnseen_opt) - out(" ecnseen"); -+ if (s->has_ecn_low_opt) -+ out(" ecn_low"); - if (s->has_fastopen_opt) - out(" fastopen"); - if (s->cong_alg[0]) -@@ -3161,6 +3164,7 @@ static void tcp_show_info(const struct n - s.has_sack_opt = TCPI_HAS_OPT(info, TCPI_OPT_SACK); - s.has_ecn_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN); - s.has_ecnseen_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN); -+ s.has_ecn_low_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_LOW); - s.has_fastopen_opt = TCPI_HAS_OPT(info, TCPI_OPT_SYN_DATA); - } - diff --git a/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch b/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch index 9dc11737b..bb58960d6 100644 --- a/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch +++ b/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch @@ -1,100 +1,149 @@ -diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c -index 3313149..1442e1f 100644 ---- a/target/linux/generic/files/drivers/net/phy/ar8327.c -+++ b/target/linux/generic/files/drivers/net/phy/ar8327.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1171,6 +1172,7 @@ ar8327_sw_hw_apply(struct switch_dev *dev) - return 0; - } - -+static - int - ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev, - const struct switch_attr *attr, -@@ -1189,6 +1191,7 @@ ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev, - return 0; - } - -+static - int - ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev, - const struct switch_attr *attr, -@@ -1207,6 +1210,7 @@ ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev, - return 0; - } - -+static - int - ar8327_sw_get_igmp_snooping(struct switch_dev *dev, - const struct switch_attr *attr, -@@ -1224,6 +1228,7 @@ ar8327_sw_get_igmp_snooping(struct switch_dev *dev, - return 0; - } +diff --git a/target/linux/generic/files/drivers/net/phy/adm6996.c b/target/linux/generic/files/drivers/net/phy/adm6996.c +index d917427..0f70634 100644 +--- a/target/linux/generic/files/drivers/net/phy/adm6996.c ++++ b/target/linux/generic/files/drivers/net/phy/adm6996.c +@@ -1209,7 +1209,7 @@ static void adm6996_gpio_remove(struct platform_device *pdev) + + static struct platform_driver adm6996_gpio_driver = { + .probe = adm6996_gpio_probe, +- .remove_new = adm6996_gpio_remove, ++ .remove = adm6996_gpio_remove, + .driver = { + .name = "adm6996_gpio", + }, +@@ -1219,14 +1219,14 @@ static int __init adm6996_init(void) + { + int err; -+static - int - ar8327_sw_set_igmp_snooping(struct switch_dev *dev, - const struct switch_attr *attr, -@@ -1240,6 +1245,7 @@ ar8327_sw_set_igmp_snooping(struct switch_dev *dev, - return 0; - } +- phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup); +- err = phy_driver_register(&adm6996_phy_driver, THIS_MODULE); ++ phy_register_fixup_for_id("MATCH ANY PHY", adm6996_fixup); ++ err = phy_drivers_register(&adm6996_phy_driver, 1, THIS_MODULE); + if (err) + return err; -+static - int - ar8327_sw_get_igmp_v3(struct switch_dev *dev, - const struct switch_attr *attr, -@@ -1256,6 +1262,7 @@ ar8327_sw_get_igmp_v3(struct switch_dev *dev, - return 0; - } + err = platform_driver_register(&adm6996_gpio_driver); + if (err) +- phy_driver_unregister(&adm6996_phy_driver); ++ phy_drivers_unregister(&adm6996_phy_driver, 1); -+static - int - ar8327_sw_set_igmp_v3(struct switch_dev *dev, - const struct switch_attr *attr, -diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c -index d5f9bfc..ac37ef9 100644 ---- a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c -+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c -@@ -227,7 +227,7 @@ static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, - } + return err; } - --void b53_set_forwarding(struct b53_device *dev, int enable) -+static void b53_set_forwarding(struct b53_device *dev, int enable) +@@ -1234,7 +1234,7 @@ static int __init adm6996_init(void) + static void __exit adm6996_exit(void) { - u8 mgmt; + platform_driver_unregister(&adm6996_gpio_driver); +- phy_driver_unregister(&adm6996_phy_driver); ++ phy_drivers_unregister(&adm6996_phy_driver, 1); + } + module_init(adm6996_init); diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c -index c85df1f..fdcebc7 100644 +index fdcebc7..ad3f308 100644 --- a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c -@@ -400,7 +400,7 @@ static struct phy_driver b53_phy_driver_id3 = { - .read_status = b53_phy_read_status, - }; - --int __init b53_phy_driver_register(void) -+static int __init b53_phy_driver_register(void) +@@ -404,29 +404,29 @@ static int __init b53_phy_driver_register(void) { int ret; -@@ -422,7 +422,7 @@ err1: +- ret = phy_driver_register(&b53_phy_driver_id1, THIS_MODULE); ++ ret = phy_drivers_register(&b53_phy_driver_id1, 1, THIS_MODULE); + if (ret) + return ret; + +- ret = phy_driver_register(&b53_phy_driver_id2, THIS_MODULE); ++ ret = phy_drivers_register(&b53_phy_driver_id2, 1, THIS_MODULE); + if (ret) + goto err1; + +- ret = phy_driver_register(&b53_phy_driver_id3, THIS_MODULE); ++ ret = phy_drivers_register(&b53_phy_driver_id3, 1, THIS_MODULE); + if (!ret) + return 0; + +- phy_driver_unregister(&b53_phy_driver_id2); ++ phy_drivers_unregister(&b53_phy_driver_id2, 1); + err1: +- phy_driver_unregister(&b53_phy_driver_id1); ++ phy_drivers_unregister(&b53_phy_driver_id1, 1); return ret; } --void __exit b53_phy_driver_unregister(void) -+static void __exit b53_phy_driver_unregister(void) + static void __exit b53_phy_driver_unregister(void) + { +- phy_driver_unregister(&b53_phy_driver_id3); +- phy_driver_unregister(&b53_phy_driver_id2); +- phy_driver_unregister(&b53_phy_driver_id1); ++ phy_drivers_unregister(&b53_phy_driver_id3, 1); ++ phy_drivers_unregister(&b53_phy_driver_id2, 1); ++ phy_drivers_unregister(&b53_phy_driver_id1, 1); + } + + module_init(b53_phy_driver_register); +diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c b/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c +index 62dfe1c..04625c5 100644 +--- a/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c ++++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c +@@ -227,7 +227,7 @@ static void b53_mmap_remove(struct platform_device *pdev) + + static struct platform_driver b53_mmap_driver = { + .probe = b53_mmap_probe, +- .remove_new = b53_mmap_remove, ++ .remove = b53_mmap_remove, + .driver = { + .name = "b53-switch", + }, +diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c b/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c +index 5a41507..3059d39 100644 +--- a/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c ++++ b/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c +@@ -49,7 +49,7 @@ static int b53_phy_fixup(struct phy_device *dev) + + static int __init b53_phy_fixup_register(void) + { +- return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup); ++ return phy_register_fixup_for_id("MATCH ANY PHY", b53_phy_fixup); + } + + subsys_initcall(b53_phy_fixup_register); +diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c +index f8cb993..869f920 100644 +--- a/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c ++++ b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c +@@ -364,7 +364,7 @@ static void b53_srab_remove(struct platform_device *pdev) + + static struct platform_driver b53_srab_driver = { + .probe = b53_srab_probe, +- .remove_new = b53_srab_remove, ++ .remove = b53_srab_remove, + .driver = { + .name = "b53-srab-switch", + }, +diff --git a/target/linux/generic/files/drivers/net/phy/psb6970.c b/target/linux/generic/files/drivers/net/phy/psb6970.c +index e8b1b06..97af784 100644 +--- a/target/linux/generic/files/drivers/net/phy/psb6970.c ++++ b/target/linux/generic/files/drivers/net/phy/psb6970.c +@@ -425,15 +425,15 @@ static struct phy_driver psb6970_driver = { + + static int __init psb6970_init(void) { - phy_driver_unregister(&b53_phy_driver_id3); - phy_driver_unregister(&b53_phy_driver_id2); +- phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup); +- return phy_driver_register(&psb6970_driver, THIS_MODULE); ++ phy_register_fixup_for_id("MATCH ANY PHY", psb6970_fixup); ++ return phy_drivers_register(&psb6970_driver, 1, THIS_MODULE); + } + + module_init(psb6970_init); + + static void __exit psb6970_exit(void) + { +- phy_driver_unregister(&psb6970_driver); ++ phy_drivers_unregister(&psb6970_driver, 1); + } + + module_exit(psb6970_exit); diff --git a/target/linux/generic/files/drivers/net/phy/rtl8306.c b/target/linux/generic/files/drivers/net/phy/rtl8306.c -index 31bc758..d7a5faa 100644 +index 9bd1735..a4b2664 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8306.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8306.c @@ -1047,14 +1047,14 @@ static struct phy_driver rtl8306_driver = { @@ -103,7 +152,7 @@ index 31bc758..d7a5faa 100644 { - phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup); - return phy_driver_register(&rtl8306_driver, THIS_MODULE); -+ phy_register_fixup_for_id("*", rtl8306_fixup); ++ phy_register_fixup_for_id("MATCH ANY PHY", rtl8306_fixup); + return phy_drivers_register(&rtl8306_driver, 1, THIS_MODULE); } @@ -115,111 +164,55 @@ index 31bc758..d7a5faa 100644 } module_init(rtl_init); -diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c -index a26fd20..c3d50a0 100644 ---- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c -+++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c -@@ -254,6 +254,7 @@ static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) - #define MDC_MDIO_WRITE_OP 0x0003 - #define MDC_REALTEK_PHY_ADDR 0x0 - -+static - int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) - { - u32 phy_id = smi->phy_id; -@@ -1577,6 +1578,7 @@ static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8 - } - #endif - -+static - int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi) - { - struct rtl8366_platform_data *pdata = pdev->dev.platform_data; diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c -index 0878ca9..06f92fb 100644 +index 0f4bbb1..3d4daec 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c -@@ -1478,7 +1478,7 @@ static int rtl8366rb_probe(struct platform_device *pdev) - return err; - } - --static int rtl8366rb_remove(struct platform_device *pdev) -+static void rtl8366rb_remove(struct platform_device *pdev) - { - struct rtl8366_smi *smi = platform_get_drvdata(pdev); - -@@ -1488,8 +1488,6 @@ static int rtl8366rb_remove(struct platform_device *pdev) - rtl8366_smi_cleanup(smi); - kfree(smi); - } -- -- return 0; - } +@@ -1498,7 +1498,7 @@ static struct platform_driver rtl8366rb_driver = { + .of_match_table = rtl8366rb_match, + }, + .probe = rtl8366rb_probe, +- .remove_new = rtl8366rb_remove, ++ .remove = rtl8366rb_remove, + }; - #ifdef CONFIG_OF + static int __init rtl8366rb_module_init(void) diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366s.c b/target/linux/generic/files/drivers/net/phy/rtl8366s.c -index d4045fc..513ed2c 100644 +index 0b37a4e..298faed 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366s.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366s.c -@@ -1266,7 +1266,7 @@ static int rtl8366s_probe(struct platform_device *pdev) - return err; - } - --static int rtl8366s_remove(struct platform_device *pdev) -+static void rtl8366s_remove(struct platform_device *pdev) - { - struct rtl8366_smi *smi = platform_get_drvdata(pdev); - -@@ -1276,8 +1276,6 @@ static int rtl8366s_remove(struct platform_device *pdev) - rtl8366_smi_cleanup(smi); - kfree(smi); - } -- -- return 0; - } +@@ -1275,7 +1275,7 @@ static struct platform_driver rtl8366s_driver = { + .of_match_table = rtl8366s_match, + }, + .probe = rtl8366s_probe, +- .remove_new = rtl8366s_remove, ++ .remove = rtl8366s_remove, + }; - #ifdef CONFIG_OF + static int __init rtl8366s_module_init(void) diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367.c b/target/linux/generic/files/drivers/net/phy/rtl8367.c -index 950e9d2..7c10ce2 100644 +index 2c11190..96f866a 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367.c -@@ -1801,7 +1801,7 @@ static int rtl8367_probe(struct platform_device *pdev) - return err; - } - --static int rtl8367_remove(struct platform_device *pdev) -+static void rtl8367_remove(struct platform_device *pdev) - { - struct rtl8366_smi *smi = platform_get_drvdata(pdev); - -@@ -1811,8 +1811,6 @@ static int rtl8367_remove(struct platform_device *pdev) - rtl8366_smi_cleanup(smi); - kfree(smi); - } -- -- return 0; - } +@@ -1812,7 +1812,7 @@ static struct platform_driver rtl8367_driver = { + .of_match_table = rtl8367_match, + }, + .probe = rtl8367_probe, +- .remove_new = rtl8367_remove, ++ .remove = rtl8367_remove, + .shutdown = rtl8367_shutdown, + }; - static void rtl8367_shutdown(struct platform_device *pdev) diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c -index 5f885aa..dc55fc6 100644 +index ae30936..c1a2868 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367b.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c -@@ -1600,7 +1600,7 @@ static int rtl8367b_probe(struct platform_device *pdev) - return err; - } - --static int rtl8367b_remove(struct platform_device *pdev) -+static void rtl8367b_remove(struct platform_device *pdev) - { - struct rtl8366_smi *smi = platform_get_drvdata(pdev); - -@@ -1610,8 +1610,6 @@ static int rtl8367b_remove(struct platform_device *pdev) - rtl8366_smi_cleanup(smi); - kfree(smi); - } -- -- return 0; - } +@@ -1610,7 +1610,7 @@ static struct platform_driver rtl8367b_driver = { + .of_match_table = rtl8367b_match, + }, + .probe = rtl8367b_probe, +- .remove_new = rtl8367b_remove, ++ .remove = rtl8367b_remove, + .shutdown = rtl8367b_shutdown, + }; - static void rtl8367b_shutdown(struct platform_device *pdev) diff --git a/openwrt/patch/key.tar.gz b/openwrt/patch/key.tar.gz deleted file mode 100644 index 141a9ce5e4e5bc899dfcb7e95203e0f98b18a598..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1424 zcmV;B1#kKviwFSao9SZ!1MOGYaw0br?MY=BcV6?5M-9f?P)*Yf-GC>!3fm0e4UBEP zjA!hoTY%iFdjUh7mn>DO{6fAUf02iLSgyb}HnVuD5;HSNpDL=Qt1DgUO6N%ExW_dD zVrb06Apww6Df$)C(w*-BqMTraq#!5L$+VnEfITgXB7+hSIHwx~p0BtFO(N9Ch`{n) zNCDQ6YMUmu{6(~3tBQdJhXU!i$JX|1D?8mh#j09b;~V)>yr3`x}w57rCbTDvW5W%gp}&Enx{Es_9(-IB8aLe-<1VR6*e>N^VES^)VH^qnU$@Ll3H9VCarFgbeHQ#7s-Ts5Q`Q3#zD8+ zt?1Q4;fyEMZ0#sk6tflea2?kR_2n2&1#&|X>(Y6#Yr}Q_h++QvkzxL1z8Id*Ul`^a z<}oe$JqHgL@H4}F%S?3?gJ@0HHU~!akFS0m+VO=$TH|{-+Y-{1?Tf6!L#Ec=S2*&-vd9_Q+YfzS7HUv5e_0XWjaC zML0V$4)tRB{2-R`RW~nsySx4dkvi4ZW~sNIbm3iZ9rQbjmeE|NYR4`zD_*~B=VRNe z`Hhup{%gSh(|7Ryv$yddcs|2?-6U2EyN*jNssQ85_;7juIG~%h#t}z<$QYF4X-T@~ z`}kK#riC&7g8)pL|E_Jn^YwFI`zMO&Cw$iaSkgOK)=|m$g-?lxUc3g~7mk8_V1A8tiuq$@M3w5qWsrvYx=)iB_{1Z9oQuvw zJ|Wi|h*M|0!K@e9DX*=FlI#U0w3~Vxb_5Mg*ACNYSJ5$Y6k>VEw~{j~HJ-9llq1|l zztSA`jq`Llu5HAjA>Qi4VANyaz>Qi*F(MFS6?>{n9G}?MBL5tcK=ZVSqPHh_e9Z1Z zX25!rC2A_=hZ&*X*VzI4oe?9~$0)*TwuM=UV4GnR=pN8^c5r|aAN|8@LKx^j zz3Cq?#y$FX)c;A~P5RI7R;sz7;IrlG`c;v?ekzPz4B-6EYk}P<7v~qy zJc|IXiMS@J4#nNODa7Ffjw+xhH)T_?NE3Vhpm!8zgW^bBnibH}TYOqBb`aMopt)D` zo1leimyIfphA~5d>+6}b7fjpd|YsBwY@O+dX!s{2LS`h z9>nb+&Kxa_12w0Kx%qnq>Un3i!@2ee%vBwATe_VDc7bJwm#AC;$NCZq|VS diff --git a/openwrt/patch/key2.tar.gz b/openwrt/patch/key2.tar.gz index 81cd3e99da40337f32e2b7791e458961593c8401..ee01fccb8303e17923a0fb94194869277f8281b6 100644 GIT binary patch literal 773 zcmV+g1N!_QiwFQN!AxlY1MQY+Z`wc*hWWg|Vnb0#8W|rPX(|!P7-KBLVFEdtwrH`9 z;}{?H1)=SK@7hfzLz<#~AW7AIWXX7EJTp7%cSMP{Y*(WK({OUTg25bDtI3@`t}@ws z0?U;vIkw8OwQ8-(F?gNjm>QRZ%+4yx5CtLfAA8Lg2mGjA&lj+T#tp;0FeaMm)3M*k^U_7do5X-jQF7> zjwb7_H2muMrW3*f_q_-of*&U7s1?i?)|@wTp3Bm~Av^#O&_k+) z3_U0zZJK%@&w{q)XiNApeNLb#-*s_ny!o|NOTP~&+=a&$G@rW*Dsn;}e_pz_W=o`& zzCq(1#VFL1I3-WF*Sy>)^rCRBzKs2CDXH_6*7TTmqWK(hr~7Pby-B1Vo~dNdCGY;BLrDxASBq>9XPmjdjY9aSE$~|=@s_|z@+2yS9v=z?PcxkdzYed! zW{!&mK-KV4dTQXMwedet+WZQ4kRuuLwMylw`OlOq<&F7Y=9ptL|DOXYp&?3g4~haD z4CM=cB*Kn(of<&5tqQy%it?a;)V*WMs?rW@;jCwjW&ygbjrpF&p$j>VxpzJB#F4_K z*>ZVT5`-_(dAD)`_=VVZ$4XN%cyV}j)YNP-ZnPVnnZoKLO=i$E7POXgB|1}I@U7-$ zBR0--X3@XD)O6G9g5{;s(2mAEz3(D^)ifo*Uv9V4}nn5m#X*y$O5D^*U1*5q%ZJia6 z5ad#>#uQ3>DB?ZU305{_9mebUD)m4Bwt zOto5|S(>i1b(W!$b(*2-)dHk;mQjw-50D38!Joy};tzh??Effl_Q=rp$eCf2njOIz z@^1mqmagLkaLA22jbdp$7?Membi>xCs^O8hjvu5O-j`B`A^H}oR> z1o!u$wlo4r0g!BOln&fjJp|l{?@Wgr-{nN%JXu7s35j;OScYZtGe79JC2>0DMxrpD zuDg=(tLqtd087mGGJJ@0m_{a6uvl7i-Uxp#i3f-90Kf##O7k>qRa;i>e8+|^QcR?4 zeg&zs%mcY5v`kxF!jIW^3PE^|lY~w#vbJh!_dbyn`UQQUeVX&58&i=NN=6Oo0T1496VgZ@ceLAz=WR3XQGQ~68z$Yza zYD9KtBE56Py?>}sdPZ`t8d`1=aqf5)3gDx%z;C(0TMkZxr>7F=aZ?C*nyWnc)w~j& zYZncGq9#jO*T73l#`Z? zXBrg`?k`o%aC=~RDL2)lNnaZ{h+DM`5mBqr$%SvSSF6YfWl3)|K$fh~Z~gWTFJ0nS zO``vBwlI_(%73f=nL4wne~M Date: Fri, 13 Sep 2024 19:36:44 +0800 -Subject: [PATCH 1/5] luci-mod-system: add modal overlay dialog to reboot +Subject: [PATCH 1/7] luci-mod-system: add modal overlay dialog to reboot Signed-off-by: sbwml --- @@ -41,5 +41,5 @@ index 92e1dd4..c106f78 100644 return body; -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch index 2698cb0fa..5a86aaf07 100644 --- a/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch +++ b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch @@ -1,7 +1,7 @@ -From fb9d1a301136922a624e1eb2927ad60260ee11f8 Mon Sep 17 00:00:00 2001 +From 673317998a908c133f7f677fa985b854d182e96a Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 19:43:19 +0800 -Subject: [PATCH 2/5] luci-mod-status: displays actual process memory usage +Subject: [PATCH 2/7] luci-mod-status: displays actual process memory usage Signed-off-by: sbwml --- @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js -index 0a885c0..d3302ff 100644 +index 0a885c0..56ac7c4 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js @@ -32,8 +32,8 @@ return baseclass.extend({ @@ -24,5 +24,5 @@ index 0a885c0..d3302ff 100644 if (mem.buffered) -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch b/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch index 915aa8512..3e2213395 100644 --- a/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch +++ b/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch @@ -1,7 +1,7 @@ -From 2543713322fa4f7b404a673429ce36f4319c4749 Mon Sep 17 00:00:00 2001 +From a2ce3356bd451a51e241361e56f0b9ff7349273a Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 24 Mar 2024 00:12:45 +0800 -Subject: [PATCH 3/5] luci-mod-status: storage index applicable only to valid +Subject: [PATCH 3/7] luci-mod-status: storage index applicable only to valid devices Signed-off-by: sbwml @@ -39,5 +39,5 @@ index 60661f6..aac6711 100644 var name = entry.device + ' (' + entry.mount +')', -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch index 5d37f54b2..caeea8674 100644 --- a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch +++ b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch @@ -1,7 +1,7 @@ -From 44cb42a004b8334d784814c5f616c8d8ceda6b22 Mon Sep 17 00:00:00 2001 +From b8114ae5032c4f73994074326c0db004795bb0aa Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 19:44:52 +0800 -Subject: [PATCH 4/5] luci-mod-status: firewall: disable legacy firewall rule +Subject: [PATCH 4/7] luci-mod-status: firewall: disable legacy firewall rule warning Signed-off-by: sbwml @@ -11,10 +11,10 @@ Signed-off-by: sbwml 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -index 0013a3a..bc630b0 100644 +index 40f7f71..38a0d24 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -@@ -675,26 +675,12 @@ return view.extend({ +@@ -773,26 +773,12 @@ return view.extend({ return node; }, @@ -42,10 +42,10 @@ index 0013a3a..bc630b0 100644 return E('em', _('No nftables ruleset loaded.')); diff --git a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json -index 79101e9..0b7272d 100644 +index 23e8bdb..5ba794e 100644 --- a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json +++ b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json -@@ -39,23 +39,39 @@ +@@ -60,23 +60,39 @@ } }, diff --git a/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch b/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch index fec459d9c..ff29c5261 100644 --- a/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch +++ b/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch @@ -1,7 +1,7 @@ -From 8596f6d48c24c063fd75f007b8e24cd011ac93fb Mon Sep 17 00:00:00 2001 +From 3d6420303179fbb13ed565aa816908a632303309 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 19:47:13 +0800 -Subject: [PATCH 5/5] luci-mod-system: add refresh interval setting +Subject: [PATCH 5/7] luci-mod-system: add refresh interval setting Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 8 insertions(+) diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js -index 767bc8c..c8969ac 100644 +index e0835d1..59155f4 100644 --- a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js +++ b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js -@@ -244,6 +244,14 @@ return view.extend({ +@@ -252,6 +252,14 @@ return view.extend({ if (k[i].charAt(0) != '.') o.value(uci.get('luci', 'themes', k[i]), k[i]); @@ -28,5 +28,5 @@ index 767bc8c..c8969ac 100644 * NTP */ -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch b/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch index cd6be2cb9..3d668bcc5 100644 --- a/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch +++ b/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch @@ -1,7 +1,7 @@ -From b5423aca7403dc8b5662bc3e13bf22115fb6b2eb Mon Sep 17 00:00:00 2001 +From 32885208f76463b46706ef88d080cce81529b903 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 Nov 2024 19:13:53 +0800 -Subject: [PATCH] luci-mod-system: mounts: add docker directory mount point +Subject: [PATCH 6/7] luci-mod-system: mounts: add docker directory mount point Signed-off-by: sbwml --- diff --git a/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch b/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch index 430f9b98f..e27929df6 100644 --- a/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch +++ b/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch @@ -1,7 +1,7 @@ -From 433eec85db3ec6ca6185eb077ff694ba9b9db2d8 Mon Sep 17 00:00:00 2001 +From fe0acd787f369d075816ceafb5d95d1cfa40fd25 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 5 May 2025 22:24:52 +0800 -Subject: [PATCH] luci-mod-system: add ucitrack luci-mod-system-zram.json +Subject: [PATCH 7/7] luci-mod-system: add ucitrack luci-mod-system-zram.json Signed-off-by: sbwml --- @@ -20,5 +20,5 @@ index 0000000..56da09e + "init": "zram" +} -- -2.36.0 +2.43.5 diff --git a/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch b/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch deleted file mode 100644 index ef9cbe8b3..000000000 --- a/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 6cef85935b825ee477553594d36c9627df95a8c6 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 28 May 2025 14:49:44 +0800 -Subject: [PATCH 1/2] Revert "speed: Pass IV to EVP_CipherInit_ex for -evp runs - with non-AEAD ciphers" - -This reverts commit 4836c042d500da503b7f50db2aa65e0bfea1c451. ---- - apps/speed.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/apps/speed.c -+++ b/apps/speed.c -@@ -2378,7 +2378,7 @@ skip_hmac: - - if (!ae_mode) { - if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, -- loopargs[k].key, iv, -1)) { -+ loopargs[k].key, NULL, -1)) { - BIO_printf(bio_err, "\nFailed to set the key\n"); - ERR_print_errors(bio_err); - exit(1); diff --git a/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch b/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch deleted file mode 100644 index 699bd0667..000000000 --- a/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch +++ /dev/null @@ -1,488 +0,0 @@ -From 28dd8b02baa130d081ae279446f81487f1662907 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Wed, 28 May 2025 14:49:59 +0800 -Subject: [PATCH 2/2] Revert "apps/speed.c: Fix the benchmarking for AEAD - ciphers" - -This reverts commit 336b86f082c7d1041c1c35817024c94c77279437. ---- - apps/speed.c | 358 +++++++++++---------------------------------------- - 1 file changed, 72 insertions(+), 286 deletions(-) - ---- a/apps/speed.c -+++ b/apps/speed.c -@@ -456,14 +456,6 @@ static double sm2_results[SM2_NUM][2]; - #define COND(unused_cond) (run && count < INT_MAX) - #define COUNT(d) (count) - --#define TAG_LEN 16 -- --static unsigned int mode_op; /* AE Mode of operation */ --static unsigned int aead = 0; /* AEAD flag */ --static unsigned char aead_iv[12]; /* For AEAD modes */ --static unsigned char aad[EVP_AEAD_TLS1_AAD_LEN] = { 0xcc }; --static int aead_ivlen = sizeof(aead_iv); -- - typedef struct loopargs_st { - ASYNC_JOB *inprogress_job; - ASYNC_WAIT_CTX *wait_ctx; -@@ -472,7 +464,6 @@ typedef struct loopargs_st { - unsigned char *buf_malloc; - unsigned char *buf2_malloc; - unsigned char *key; -- unsigned char tag[TAG_LEN]; - size_t buflen; - size_t sigsize; - EVP_PKEY_CTX *rsa_sign_ctx[RSA_NUM]; -@@ -736,8 +727,12 @@ static int EVP_Update_loop(void *args) - unsigned char *buf = tempargs->buf; - EVP_CIPHER_CTX *ctx = tempargs->ctx; - int outl, count, rc; -+ unsigned char faketag[16] = { 0xcc }; - - if (decrypt) { -+ if (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) { -+ (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(faketag), faketag); -+ } - for (count = 0; COND(c[D_EVP][testnum]); count++) { - rc = EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); - if (rc != 1) { -@@ -762,159 +757,74 @@ static int EVP_Update_loop(void *args) - } - - /* -- * To make AEAD benchmarking more relevant perform TLS-like operations, -- * 13-byte AAD followed by payload. But don't use TLS-formatted AAD, as -- * payload length is not actually limited by 16KB... - * CCM does not support streaming. For the purpose of performance measurement, - * each message is encrypted using the same (key,iv)-pair. Do not use this - * code in your application. - */ --static int EVP_Update_loop_aead_enc(void *args) -+static int EVP_Update_loop_ccm(void *args) - { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; -- unsigned char *key = tempargs->key; - EVP_CIPHER_CTX *ctx = tempargs->ctx; -- int outl, count, realcount = 0; -+ int outl, count; -+ unsigned char tag[12]; - -- for (count = 0; COND(c[D_EVP][testnum]); count++) { -- /* Set length of iv (Doesn't apply to SIV mode) */ -- if (mode_op != EVP_CIPH_SIV_MODE) { -- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, -- aead_ivlen, NULL)) { -- BIO_printf(bio_err, "\nFailed to set iv length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- /* Set tag_len (Not for GCM/SIV at encryption stage) */ -- if (mode_op != EVP_CIPH_GCM_MODE -- && mode_op != EVP_CIPH_SIV_MODE) { -- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, -- TAG_LEN, NULL)) { -- BIO_printf(bio_err, "\nFailed to set tag length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, aead_iv, -1)) { -- BIO_printf(bio_err, "\nFailed to set key and iv\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- /* Set total length of input. Only required for CCM */ -- if (mode_op == EVP_CIPH_CCM_MODE) { -- if (!EVP_EncryptUpdate(ctx, NULL, &outl, -- NULL, lengths[testnum])) { -- BIO_printf(bio_err, "\nCouldn't set input text length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- if (aead) { -- if (!EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) { -- BIO_printf(bio_err, "\nCouldn't insert AAD when encrypting\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -+ if (decrypt) { -+ for (count = 0; COND(c[D_EVP][testnum]); count++) { -+ (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(tag), -+ tag); -+ /* reset iv */ -+ (void)EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); -+ /* counter is reset on every update */ -+ (void)EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); - } -- if (!EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum])) { -- BIO_printf(bio_err, "\nFailed to encrypt the data\n"); -- ERR_print_errors(bio_err); -- exit(1); -+ } else { -+ for (count = 0; COND(c[D_EVP][testnum]); count++) { -+ /* restore iv length field */ -+ (void)EVP_EncryptUpdate(ctx, NULL, &outl, NULL, lengths[testnum]); -+ /* counter is reset on every update */ -+ (void)EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); - } -- if (EVP_EncryptFinal_ex(ctx, buf, &outl)) -- realcount++; - } -- return realcount; -+ if (decrypt) -+ (void)EVP_DecryptFinal_ex(ctx, buf, &outl); -+ else -+ (void)EVP_EncryptFinal_ex(ctx, buf, &outl); -+ return count; - } - - /* - * To make AEAD benchmarking more relevant perform TLS-like operations, - * 13-byte AAD followed by payload. But don't use TLS-formatted AAD, as - * payload length is not actually limited by 16KB... -- * CCM does not support streaming. For the purpose of performance measurement, -- * each message is decrypted using the same (key,iv)-pair. Do not use this -- * code in your application. -- * For decryption, we will use buf2 to preserve the input text in buf. - */ --static int EVP_Update_loop_aead_dec(void *args) -+static int EVP_Update_loop_aead(void *args) - { - loopargs_t *tempargs = *(loopargs_t **) args; - unsigned char *buf = tempargs->buf; -- unsigned char *outbuf = tempargs->buf2; -- unsigned char *key = tempargs->key; -- unsigned char tag[TAG_LEN]; - EVP_CIPHER_CTX *ctx = tempargs->ctx; -- int outl, count, realcount = 0; -- -- for (count = 0; COND(c[D_EVP][testnum]); count++) { -- /* Set the length of iv (Doesn't apply to SIV mode) */ -- if (mode_op != EVP_CIPH_SIV_MODE) { -- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, -- aead_ivlen, NULL)) { -- BIO_printf(bio_err, "\nFailed to set iv length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -+ int outl, count; -+ unsigned char aad[13] = { 0xcc }; -+ unsigned char faketag[16] = { 0xcc }; - -- /* Set the tag length (Doesn't apply to SIV mode) */ -- if (mode_op != EVP_CIPH_SIV_MODE -- && mode_op != EVP_CIPH_GCM_MODE) { -- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, -- TAG_LEN, NULL)) { -- BIO_printf(bio_err, "\nFailed to set tag length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, aead_iv, -1)) { -- BIO_printf(bio_err, "\nFailed to set key and iv\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- /* Set iv before decryption (Doesn't apply to SIV mode) */ -- if (mode_op != EVP_CIPH_SIV_MODE) { -- if (!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, aead_iv)) { -- BIO_printf(bio_err, "\nFailed to set iv\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- memcpy(tag, tempargs->tag, TAG_LEN); -- -- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, -- TAG_LEN, tag)) { -- BIO_printf(bio_err, "\nFailed to set tag\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- /* Set the total length of cipher text. Only required for CCM */ -- if (mode_op == EVP_CIPH_CCM_MODE) { -- if (!EVP_DecryptUpdate(ctx, NULL, &outl, -- NULL, lengths[testnum])) { -- BIO_printf(bio_err, "\nCouldn't set cipher text length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- if (aead) { -- if (!EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) { -- BIO_printf(bio_err, "\nCouldn't insert AAD when decrypting\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -+ if (decrypt) { -+ for (count = 0; COND(c[D_EVP][testnum]); count++) { -+ (void)EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv); -+ (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, -+ sizeof(faketag), faketag); -+ (void)EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); -+ (void)EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); -+ (void)EVP_DecryptFinal_ex(ctx, buf + outl, &outl); - } -- if (!EVP_DecryptUpdate(ctx, outbuf, &outl, buf, lengths[testnum])) { -- BIO_printf(bio_err, "\nFailed to decrypt the data\n"); -- ERR_print_errors(bio_err); -- exit(1); -+ } else { -+ for (count = 0; COND(c[D_EVP][testnum]); count++) { -+ (void)EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv); -+ (void)EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)); -+ (void)EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]); -+ (void)EVP_EncryptFinal_ex(ctx, buf + outl, &outl); - } -- if (EVP_DecryptFinal_ex(ctx, outbuf, &outl)) -- realcount++; - } -- return realcount; -+ return count; - } - - static long rsa_c[RSA_NUM][2]; /* # RSA iteration test */ -@@ -1460,11 +1370,11 @@ int speed_main(int argc, char **argv) - OPTION_CHOICE o; - int async_init = 0, multiblock = 0, pr_header = 0; - uint8_t doit[ALGOR_NUM] = { 0 }; -- int ret = 1, misalign = 0, lengths_single = 0; -+ int ret = 1, misalign = 0, lengths_single = 0, aead = 0; - long count = 0; - unsigned int size_num = SIZE_NUM; - unsigned int i, k, loopargs_len = 0, async_jobs = 0; -- int keylen = 0; -+ int keylen; - int buflen; - BIGNUM *bn = NULL; - EVP_PKEY_CTX *genctx = NULL; -@@ -2302,20 +2212,12 @@ skip_hmac: - } - } - -- /*- -- * There are three scenarios for D_EVP: -- * 1- Using authenticated encryption (AE) e.g. CCM, GCM, OCB etc. -- * 2- Using AE + associated data (AD) i.e. AEAD using CCM, GCM, OCB etc. -- * 3- Not using AE or AD e.g. ECB, CBC, CFB etc. -- */ - if (doit[D_EVP]) { - if (evp_cipher != NULL) { -- int (*loopfunc) (void *); -- int outlen = 0; -- unsigned int ae_mode = 0; -+ int (*loopfunc) (void *) = EVP_Update_loop; - -- if (multiblock && (EVP_CIPHER_get_flags(evp_cipher) -- & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) { -+ if (multiblock && (EVP_CIPHER_get_flags(evp_cipher) & -+ EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) { - multiblock_speed(evp_cipher, lengths_single, &seconds); - ret = 0; - goto end; -@@ -2323,26 +2225,16 @@ skip_hmac: - - names[D_EVP] = EVP_CIPHER_get0_name(evp_cipher); - -- mode_op = EVP_CIPHER_get_mode(evp_cipher); -- -- if (aead) { -+ if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_CCM_MODE) { -+ loopfunc = EVP_Update_loop_ccm; -+ } else if (aead && (EVP_CIPHER_get_flags(evp_cipher) & -+ EVP_CIPH_FLAG_AEAD_CIPHER)) { -+ loopfunc = EVP_Update_loop_aead; - if (lengths == lengths_list) { - lengths = aead_lengths_list; - size_num = OSSL_NELEM(aead_lengths_list); - } - } -- if (mode_op == EVP_CIPH_GCM_MODE -- || mode_op == EVP_CIPH_CCM_MODE -- || mode_op == EVP_CIPH_OCB_MODE -- || mode_op == EVP_CIPH_SIV_MODE) { -- ae_mode = 1; -- if (decrypt) -- loopfunc = EVP_Update_loop_aead_dec; -- else -- loopfunc = EVP_Update_loop_aead_enc; -- } else { -- loopfunc = EVP_Update_loop; -- } - - for (testnum = 0; testnum < size_num; testnum++) { - print_message(names[D_EVP], c[D_EVP][testnum], lengths[testnum], -@@ -2354,144 +2246,37 @@ skip_hmac: - BIO_printf(bio_err, "\nEVP_CIPHER_CTX_new failure\n"); - exit(1); - } -- -- /* -- * For AE modes, we must first encrypt the data to get -- * a valid tag that enables us to decrypt. If we don't -- * encrypt first, we won't have a valid tag that enables -- * authenticity and hence decryption will fail. -- */ -- if (!EVP_CipherInit_ex(loopargs[k].ctx, -- evp_cipher, NULL, NULL, NULL, -- ae_mode ? 1 : !decrypt)) { -- BIO_printf(bio_err, "\nCouldn't init the context\n"); -+ if (!EVP_CipherInit_ex(loopargs[k].ctx, evp_cipher, NULL, -+ NULL, iv, decrypt ? 0 : 1)) { -+ BIO_printf(bio_err, "\nEVP_CipherInit_ex failure\n"); - ERR_print_errors(bio_err); - exit(1); - } - -- /* Padding isn't needed */ - EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0); - - keylen = EVP_CIPHER_CTX_get_key_length(loopargs[k].ctx); - loopargs[k].key = app_malloc(keylen, "evp_cipher key"); - EVP_CIPHER_CTX_rand_key(loopargs[k].ctx, loopargs[k].key); -- -- if (!ae_mode) { -- if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, -- loopargs[k].key, NULL, -1)) { -- BIO_printf(bio_err, "\nFailed to set the key\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } else if (mode_op == EVP_CIPH_SIV_MODE) { -- EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, -- EVP_CTRL_SET_SPEED, 1, NULL); -- } -- if (ae_mode && decrypt) { -- /* Set length of iv (Doesn't apply to SIV mode) */ -- if (mode_op != EVP_CIPH_SIV_MODE) { -- if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, -- EVP_CTRL_AEAD_SET_IVLEN, -- aead_ivlen, NULL)) { -- BIO_printf(bio_err, "\nFailed to set iv length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- /* Set tag_len (Not for SIV at encryption stage) */ -- if (mode_op != EVP_CIPH_GCM_MODE -- && mode_op != EVP_CIPH_SIV_MODE) { -- if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, -- EVP_CTRL_AEAD_SET_TAG, -- TAG_LEN, NULL)) { -- BIO_printf(bio_err, -- "\nFailed to set tag length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, -- loopargs[k].key, aead_iv, -1)) { -- BIO_printf(bio_err, "\nFailed to set the key\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- /* Set total length of input. Only required for CCM */ -- if (mode_op == EVP_CIPH_CCM_MODE) { -- if (!EVP_EncryptUpdate(loopargs[k].ctx, NULL, -- &outlen, NULL, -- lengths[testnum])) { -- BIO_printf(bio_err, -- "\nCouldn't set input text length\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- if (aead) { -- if (!EVP_EncryptUpdate(loopargs[k].ctx, NULL, -- &outlen, aad, sizeof(aad))) { -- BIO_printf(bio_err, -- "\nCouldn't insert AAD when encrypting\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- } -- if (!EVP_EncryptUpdate(loopargs[k].ctx, loopargs[k].buf, -- &outlen, loopargs[k].buf, -- lengths[testnum])) { -- BIO_printf(bio_err, -- "\nFailed to to encrypt the data\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- -- if (!EVP_EncryptFinal_ex(loopargs[k].ctx, -- loopargs[k].buf, &outlen)) { -- BIO_printf(bio_err, -- "\nFailed finalize the encryption\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- -- if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, -- EVP_CTRL_AEAD_GET_TAG, -- TAG_LEN, &loopargs[k].tag)) { -- BIO_printf(bio_err, "\nFailed to get the tag\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- -- EVP_CIPHER_CTX_free(loopargs[k].ctx); -- loopargs[k].ctx = EVP_CIPHER_CTX_new(); -- if (loopargs[k].ctx == NULL) { -- BIO_printf(bio_err, -- "\nEVP_CIPHER_CTX_new failure\n"); -- exit(1); -- } -- if (!EVP_CipherInit_ex(loopargs[k].ctx, evp_cipher, -- NULL, NULL, NULL, 0)) { -- BIO_printf(bio_err, -- "\nFailed initializing the context\n"); -- ERR_print_errors(bio_err); -- exit(1); -- } -- -- EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0); -- -- /* SIV only allows for one Update operation */ -- if (mode_op == EVP_CIPH_SIV_MODE) -- EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, -- EVP_CTRL_SET_SPEED, 1, NULL); -+ if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL, -+ loopargs[k].key, NULL, -1)) { -+ BIO_printf(bio_err, "\nEVP_CipherInit_ex failure\n"); -+ ERR_print_errors(bio_err); -+ exit(1); - } -+ OPENSSL_clear_free(loopargs[k].key, keylen); -+ -+ /* SIV mode only allows for a single Update operation */ -+ if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_SIV_MODE) -+ (void)EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, -+ EVP_CTRL_SET_SPEED, 1, NULL); - } - - Time_F(START); - count = run_benchmark(async_jobs, loopfunc, loopargs); - d = Time_F(STOP); -- for (k = 0; k < loopargs_len; k++) { -- OPENSSL_clear_free(loopargs[k].key, keylen); -+ for (k = 0; k < loopargs_len; k++) - EVP_CIPHER_CTX_free(loopargs[k].ctx); -- } - print_result(D_EVP, testnum, count, d); - } - } else if (evp_md_name != NULL) { -@@ -3889,6 +3674,7 @@ static void multiblock_speed(const EVP_C - print_message(alg_name, 0, mblengths[j], seconds->sym); - Time_F(START); - for (count = 0; run && count < INT_MAX; count++) { -+ unsigned char aad[EVP_AEAD_TLS1_AAD_LEN]; - EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; - size_t len = mblengths[j]; - int packlen; diff --git a/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch b/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch deleted file mode 100644 index f66140741..000000000 --- a/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch +++ /dev/null @@ -1,1746 +0,0 @@ -From 1838d91ae3f953de3c44d5076e0373dc7197993f Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 12 Apr 2019 11:13:25 -0400 -Subject: [PATCH 01/43] QUIC: Add support for BoringSSL QUIC APIs - -This adds a compatible API for BoringSSL's QUIC support, based -on the current |draft-ietf-quic-tls|. - -Based on BoringSSL commit 3c034b2cf386b3131f75520705491871a2e0cafe -Based on BoringSSL commit c8e0f90f83b9ec38ea833deb86b5a41360b62b6a -Based on BoringSSL commit 3cbb0299a28a8bd0136257251a78b91a96c5eec8 -Based on BoringSSL commit cc9d935256539af2d3b7f831abf57c0d685ffd81 -Based on BoringSSL commit e6eef1ca16a022e476bbaedffef044597cfc8f4b -Based on BoringSSL commit 6f733791148cf8a076bf0e95498235aadbe5926d -Based on BoringSSL commit 384d0eaf1930af1ebc47eda751f0c78dfcba1c03 -Based on BoringSSL commit a0373182eb5cc7b81d49f434596b473c7801c942 -Based on BoringSSL commit b1b76aee3cb43ce11889403c5334283d951ebd37 ---- - Configure | 2 + - INSTALL.md | 4 + - crypto/err/openssl.txt | 2 + - doc/man3/SSL_CIPHER_get_name.pod | 13 ++ - doc/man3/SSL_CTX_set_quic_method.pod | 232 +++++++++++++++++++++++++ - include/openssl/evp.h | 5 + - include/openssl/ssl.h.in | 45 +++++ - include/openssl/sslerr.h | 2 + - include/openssl/tls1.h | 3 + - include/openssl/types.h | 2 + - ssl/build.info | 2 + - ssl/s3_msg.c | 10 ++ - ssl/ssl_ciph.c | 32 ++++ - ssl/ssl_err.c | 3 + - ssl/ssl_lib.c | 41 ++++- - ssl/ssl_local.h | 37 ++++ - ssl/ssl_quic.c | 248 +++++++++++++++++++++++++++ - ssl/statem/extensions.c | 29 ++++ - ssl/statem/extensions_clnt.c | 48 ++++++ - ssl/statem/extensions_srvr.c | 51 ++++++ - ssl/statem/statem.c | 20 ++- - ssl/statem/statem_lib.c | 19 +- - ssl/statem/statem_local.h | 19 ++ - ssl/statem/statem_quic.c | 106 ++++++++++++ - ssl/tls13_enc.c | 59 +++++++ - test/helpers/ssltestlib.c | 5 + - test/sslapitest.c | 131 ++++++++++++++ - test/tls13secretstest.c | 7 + - util/libssl.num | 11 ++ - util/other.syms | 2 + - 30 files changed, 1185 insertions(+), 6 deletions(-) - create mode 100644 doc/man3/SSL_CTX_set_quic_method.pod - create mode 100644 ssl/ssl_quic.c - create mode 100644 ssl/statem/statem_quic.c - ---- a/Configure -+++ b/Configure -@@ -468,6 +468,7 @@ my @disablables = ( - "poly1305", - "posix-io", - "psk", -+ "quic", - "rc2", - "rc4", - "rc5", -@@ -636,6 +637,7 @@ my @disable_cascades = ( - "legacy" => [ "md2" ], - - "cmp" => [ "crmf" ], -+ "tls1_3" => [ "quic" ], - - "fips" => [ "fips-securitychecks", "acvp-tests" ], - ---- a/INSTALL.md -+++ b/INSTALL.md -@@ -829,6 +829,10 @@ Don't use POSIX IO capabilities. - - Don't build support for Pre-Shared Key based ciphersuites. - -+### no-quic -+ -+Don't build support for QUIC API from BoringSSL. -+ - ### no-rdrand - - Don't use hardware RDRAND capabilities. ---- a/crypto/err/openssl.txt -+++ b/crypto/err/openssl.txt -@@ -1253,6 +1253,7 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_ - SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec - SSL_R_BAD_CIPHER:186:bad cipher - SSL_R_BAD_DATA:390:bad data -+SSL_R_BAD_DATA_LENGTH:802:bad data length - SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback - SSL_R_BAD_DECOMPRESSION:107:bad decompression - SSL_R_BAD_DH_VALUE:102:bad dh value -@@ -1540,6 +1541,7 @@ SSL_R_VERSION_TOO_LOW:396:version too lo - SSL_R_WRONG_CERTIFICATE_TYPE:383:wrong certificate type - SSL_R_WRONG_CIPHER_RETURNED:261:wrong cipher returned - SSL_R_WRONG_CURVE:378:wrong curve -+SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED:800:wrong encryption level received - SSL_R_WRONG_SIGNATURE_LENGTH:264:wrong signature length - SSL_R_WRONG_SIGNATURE_SIZE:265:wrong signature size - SSL_R_WRONG_SIGNATURE_TYPE:370:wrong signature type ---- a/doc/man3/SSL_CIPHER_get_name.pod -+++ b/doc/man3/SSL_CIPHER_get_name.pod -@@ -13,6 +13,7 @@ SSL_CIPHER_get_digest_nid, - SSL_CIPHER_get_handshake_digest, - SSL_CIPHER_get_kx_nid, - SSL_CIPHER_get_auth_nid, -+SSL_CIPHER_get_prf_nid, - SSL_CIPHER_is_aead, - SSL_CIPHER_find, - SSL_CIPHER_get_id, -@@ -34,6 +35,7 @@ SSL_CIPHER_get_protocol_id - const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c); - int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c); - int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c); -+ int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); - int SSL_CIPHER_is_aead(const SSL_CIPHER *c); - const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); - uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c); -@@ -91,6 +93,15 @@ TLS 1.3 cipher suites) B i - NID_auth_ecdsa - NID_auth_psk - -+SSL_CIPHER_get_prf_nid() retuns the pseudo-random function NID for B. If B is -+a pre-TLS-1.2 cipher, it returns B but note these ciphers use -+SHA-256 in TLS 1.2. Other return values may be treated uniformly in all -+applicable versions. Examples (not comprehensive): -+ -+ NID_md5_sha1 -+ NID_sha256 -+ NID_sha384 -+ - SSL_CIPHER_is_aead() returns 1 if the cipher B is AEAD (e.g. GCM or - ChaCha20/Poly1305), and 0 if it is not AEAD. - -@@ -201,6 +212,8 @@ required to enable this function. - - The OPENSSL_cipher_name() function was added in OpenSSL 1.1.1. - -+The SSL_CIPHER_get_prf_nid() function was added in OpenSSL 3.0.0. -+ - =head1 COPYRIGHT - - Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved. ---- /dev/null -+++ b/doc/man3/SSL_CTX_set_quic_method.pod -@@ -0,0 +1,232 @@ -+=pod -+ -+=head1 NAME -+ -+SSL_QUIC_METHOD, -+OSSL_ENCRYPTION_LEVEL, -+SSL_CTX_set_quic_method, -+SSL_set_quic_method, -+SSL_set_quic_transport_params, -+SSL_get_peer_quic_transport_params, -+SSL_quic_max_handshake_flight_len, -+SSL_quic_read_level, -+SSL_quic_write_level, -+SSL_provide_quic_data, -+SSL_process_quic_post_handshake, -+SSL_is_quic -+- QUIC support -+ -+=head1 SYNOPSIS -+ -+ #include -+ -+ typedef struct ssl_quic_method_st SSL_QUIC_METHOD; -+ typedef enum ssl_encryption_level_t OSSL_ENCRYPTION_LEVEL; -+ -+ int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method); -+ int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method); -+ int SSL_set_quic_transport_params(SSL *ssl, -+ const uint8_t *params, -+ size_t params_len); -+ void SSL_get_peer_quic_transport_params(const SSL *ssl, -+ const uint8_t **out_params, -+ size_t *out_params_len); -+ size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level); -+ OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl); -+ OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl); -+ int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *data, size_t len); -+ int SSL_process_quic_post_handshake(SSL *ssl); -+ int SSL_is_quic(SSL *ssl); -+ -+=head1 DESCRIPTION -+ -+SSL_CTX_set_quic_method() and SSL_set_quic_method() configures the QUIC methods. -+This should only be configured with a minimum version of TLS 1.3. B -+must remain valid for the lifetime of B or B. Calling this disables -+the SSL_OP_ENABLE_MIDDLEBOX_COMPAT option, which is not required for QUIC. -+ -+SSL_set_quic_transport_params() configures B to send B (of length -+B) in the quic_transport_parameters extension in either the -+ClientHello or EncryptedExtensions handshake message. This extension will -+only be sent if the TLS version is at least 1.3, and for a server, only if -+the client sent the extension. The buffer pointed to by B only need be -+valid for the duration of the call to this function. -+ -+SSL_get_peer_quic_transport_params() provides the caller with the value of the -+quic_transport_parameters extension sent by the peer. A pointer to the buffer -+containing the TransportParameters will be put in B<*out_params>, and its -+length in B<*out_params_len>. This buffer will be valid for the lifetime of the -+B. If no params were received from the peer, B<*out_params_len> will be 0. -+ -+SSL_quic_max_handshake_flight_len() returns returns the maximum number of bytes -+that may be received at the given encryption level. This function should be -+used to limit buffering in the QUIC implementation. -+ -+See https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4. -+ -+SSL_quic_read_level() returns the current read encryption level. -+ -+SSL_quic_write_level() returns the current write encryption level. -+ -+SSL_provide_quic_data() provides data from QUIC at a particular encryption -+level B. It is an error to call this function outside of the handshake -+or with an encryption level other than the current read level. It returns one -+on success and zero on error. -+ -+SSL_process_quic_post_handshake() processes any data that QUIC has provided -+after the handshake has completed. This includes NewSessionTicket messages -+sent by the server. -+ -+SSL_is_quic() indicates whether a connection uses QUIC. -+ -+=head1 NOTES -+ -+These APIs are implementations of BoringSSL's QUIC APIs. -+ -+QUIC acts as an underlying transport for the TLS 1.3 handshake. The following -+functions allow a QUIC implementation to serve as the underlying transport as -+described in draft-ietf-quic-tls. -+ -+When configured for QUIC, SSL_do_handshake() will drive the handshake as -+before, but it will not use the configured B. It will call functions on -+B to configure secrets and send data. If data is needed from -+the peer, it will return B. When received, the caller -+should call SSL_provide_quic_data() and then SSL_do_handshake() to continue -+the handshake. After the handshake is complete, the caller should call -+SSL_provide_quic_data() for any post-handshake data, followed by -+SSL_process_quic_post_handshake() to process it. It is an error to call -+SSL_read()/SSL_read_ex() and SSL_write()/SSL_write_ex() in QUIC. -+ -+Note that secrets for an encryption level may be available to QUIC before the -+level is active in TLS. Callers should use SSL_quic_read_level() to determine -+the active read level for SSL_provide_quic_data(). SSL_do_handshake() will -+pass the active write level to add_handshake_data() when writing data. Callers -+can use SSL_quic_write_level() to query the active write level when -+generating their own errors. -+ -+See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more -+details. -+ -+To avoid DoS attacks, the QUIC implementation must limit the amount of data -+being queued up. The implementation can call -+SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each -+encryption level. -+ -+draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters -+used by QUIC for each endpoint to unilaterally declare its supported -+transport parameters. draft-ietf-quic-transport (section 7.4) defines the -+contents of that extension (a TransportParameters struct) and describes how -+to handle it and its semantic meaning. -+ -+OpenSSL handles this extension as an opaque byte string. The caller is -+responsible for serializing and parsing it. -+ -+=head2 OSSL_ENCRYPTION_LEVEL -+ -+B (B) represents the -+encryption levels: -+ -+=over 4 -+ -+=item ssl_encryption_initial -+ -+The initial encryption level that is used for client and server hellos. -+ -+=item ssl_encryption_early_data -+ -+The encryption level for early data. This is a write-level for the client -+and a read-level for the server. -+ -+=item ssl_encryption_handshake -+ -+The encryption level for the remainder of the handshake. -+ -+=item ssl_encryption_application -+ -+The encryption level for the application data. -+ -+=back -+ -+=head2 SSL_QUIC_METHOD -+ -+The B (B) describes the -+QUIC methods. -+ -+ struct ssl_quic_method_st { -+ int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *read_secret, -+ const uint8_t *write_secret, size_t secret_len); -+ int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *data, size_t len); -+ int (*flush_flight)(SSL *ssl); -+ int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert); -+ }; -+ typedef struct ssl_quic_method_st SSL_QUIC_METHOD; -+ -+set_encryption_secrets() configures the read and write secrets for the given -+encryption level. This function will always be called before an encryption -+level other than B is used. Note, however, that -+secrets for a level may be configured before TLS is ready to send or accept -+data at that level. -+ -+When reading packets at a given level, the QUIC implementation must send -+ACKs at the same level, so this function provides read and write secrets -+together. The exception is B, where secrets are -+only available in the client to server direction. The other secret will be -+NULL. The server acknowledges such data at B, -+which will be configured in the same SSL_do_handshake() call. -+ -+This function should use SSL_get_current_cipher() to determine the TLS -+cipher suite. -+ -+add_handshake_data() adds handshake data to the current flight at the given -+encryption level. It returns one on success and zero on error. -+ -+OpenSSL will pack data from a single encryption level together, but a -+single handshake flight may include multiple encryption levels. Callers -+should defer writing data to the network until flush_flight() to better -+pack QUIC packets into transport datagrams. -+ -+flush_flight() is called when the current flight is complete and should be -+written to the transport. Note a flight may contain data at several -+encryption levels. -+ -+send_alert() sends a fatal alert at the specified encryption level. -+ -+All QUIC methods return 1 on success and 0 on error. -+ -+=head1 RETURN VALUES -+ -+SSL_CTX_set_quic_method(), -+SSL_set_quic_method(), -+SSL_set_quic_transport_params(), and -+SSL_process_quic_post_handshake() -+return 1 on success, and 0 on error. -+ -+SSL_quic_read_level() and SSL_quic_write_level() return the current -+encryption level as B (B). -+ -+SSL_quic_max_handshake_flight_len() returns the maximum length of a flight -+for a given encryption level. -+ -+SSL_is_quic() returns 1 if QUIC is being used, 0 if not. -+ -+=head1 SEE ALSO -+ -+L, L, L -+ -+=head1 HISTORY -+ -+These functions were added in OpenSSL 3.0.0. -+ -+=head1 COPYRIGHT -+ -+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. -+ -+Licensed under the Apache License 2.0 (the "License"). You may not use -+this file except in compliance with the License. You can obtain a copy -+in the file LICENSE in the source distribution or at -+L. -+ -+=cut ---- a/include/openssl/evp.h -+++ b/include/openssl/evp.h -@@ -1741,6 +1741,11 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CT - * Method handles all operations: don't assume any digest related defaults. - */ - # define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 -+ -+/* Used by Chromium/QUIC */ -+# define X25519_PRIVATE_KEY_LEN 32 -+# define X25519_PUBLIC_VALUE_LEN 32 -+ - # ifndef OPENSSL_NO_DEPRECATED_3_0 - OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); - OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); ---- a/include/openssl/ssl.h.in -+++ b/include/openssl/ssl.h.in -@@ -2521,6 +2521,51 @@ void SSL_set_allow_early_data_cb(SSL *s, - const char *OSSL_default_cipher_list(void); - const char *OSSL_default_ciphersuites(void); - -+# ifndef OPENSSL_NO_QUIC -+/* -+ * QUIC integration - The QUIC interface matches BoringSSL -+ * -+ * ssl_encryption_level_t represents a specific QUIC encryption level used to -+ * transmit handshake messages. BoringSSL has this as an 'enum'. -+ */ -+typedef enum ssl_encryption_level_t { -+ ssl_encryption_initial = 0, -+ ssl_encryption_early_data, -+ ssl_encryption_handshake, -+ ssl_encryption_application -+} OSSL_ENCRYPTION_LEVEL; -+ -+struct ssl_quic_method_st { -+ int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *read_secret, -+ const uint8_t *write_secret, size_t secret_len); -+ int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *data, size_t len); -+ int (*flush_flight)(SSL *ssl); -+ int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert); -+}; -+ -+__owur int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method); -+__owur int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method); -+__owur int SSL_set_quic_transport_params(SSL *ssl, -+ const uint8_t *params, -+ size_t params_len); -+void SSL_get_peer_quic_transport_params(const SSL *ssl, -+ const uint8_t **out_params, -+ size_t *out_params_len); -+__owur size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level); -+__owur OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl); -+__owur OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl); -+__owur int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *data, size_t len); -+__owur int SSL_process_quic_post_handshake(SSL *ssl); -+ -+__owur int SSL_is_quic(SSL *ssl); -+ -+# endif -+ -+int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); -+ - # ifdef __cplusplus - } - # endif ---- a/include/openssl/sslerr.h -+++ b/include/openssl/sslerr.h -@@ -28,6 +28,7 @@ - # define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 - # define SSL_R_BAD_CIPHER 186 - # define SSL_R_BAD_DATA 390 -+# define SSL_R_BAD_DATA_LENGTH 802 - # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 - # define SSL_R_BAD_DECOMPRESSION 107 - # define SSL_R_BAD_DH_VALUE 102 -@@ -335,6 +336,7 @@ - # define SSL_R_WRONG_CERTIFICATE_TYPE 383 - # define SSL_R_WRONG_CIPHER_RETURNED 261 - # define SSL_R_WRONG_CURVE 378 -+# define SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED 800 - # define SSL_R_WRONG_SIGNATURE_LENGTH 264 - # define SSL_R_WRONG_SIGNATURE_SIZE 265 - # define SSL_R_WRONG_SIGNATURE_TYPE 370 ---- a/include/openssl/tls1.h -+++ b/include/openssl/tls1.h -@@ -151,6 +151,9 @@ extern "C" { - /* Temporary extension type */ - # define TLSEXT_TYPE_renegotiate 0xff01 - -+/* ExtensionType value from draft-ietf-quic-tls-13 */ -+# define TLSEXT_TYPE_quic_transport_parameters 0xffa5 -+ - # ifndef OPENSSL_NO_NEXTPROTONEG - /* This is not an IANA defined extension number */ - # define TLSEXT_TYPE_next_proto_neg 13172 ---- a/include/openssl/types.h -+++ b/include/openssl/types.h -@@ -229,6 +229,8 @@ typedef struct ossl_decoder_ctx_st OSSL_ - - typedef struct ossl_self_test_st OSSL_SELF_TEST; - -+typedef struct ssl_quic_method_st SSL_QUIC_METHOD; -+ - #ifdef __cplusplus - } - #endif ---- a/ssl/build.info -+++ b/ssl/build.info -@@ -38,6 +38,8 @@ IF[{- !$disabled{'deprecated-3.0'} -}] - SOURCE[../libssl]=ssl_rsa_legacy.c - ENDIF - -+SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c -+ - DEFINE[../libssl]=$AESDEF - - SOURCE[../providers/libcommon.a]=record/tls_pad.c ---- a/ssl/s3_msg.c -+++ b/ssl/s3_msg.c -@@ -81,6 +81,16 @@ int ssl3_dispatch_alert(SSL *s) - - s->s3.alert_dispatch = 0; - alertlen = 2; -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ if (!s->quic_method->send_alert(s, s->quic_write_level, -+ s->s3.send_alert[1])) { -+ SSLerr(SSL_F_SSL3_DISPATCH_ALERT, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ i = 1; -+ } else -+#endif - i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3.send_alert[0], &alertlen, 1, 0, - &written); - if (i <= 0) { ---- a/ssl/ssl_ciph.c -+++ b/ssl/ssl_ciph.c -@@ -2240,3 +2240,35 @@ const char *OSSL_default_ciphersuites(vo - "TLS_CHACHA20_POLY1305_SHA256:" - "TLS_AES_128_GCM_SHA256"; - } -+ -+int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c) -+{ -+ switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) { -+ default: -+ break; -+ case TLS1_PRF_SHA1_MD5: /* TLS1_PRF */ -+ return NID_md5_sha1; -+ case TLS1_PRF_SHA256: -+ return NID_sha256; -+ case TLS1_PRF_SHA384: -+ return NID_sha384; -+ case TLS1_PRF_GOST94: -+ return NID_id_GostR3411_94_prf; -+ case TLS1_PRF_GOST12_256: -+ return NID_id_GostR3411_2012_256; -+ case TLS1_PRF_GOST12_512: -+ return NID_id_GostR3411_2012_512; -+ } -+ /* TLSv1.3 ciphers don't specify separate PRF */ -+ switch (c->algorithm2 & SSL_HANDSHAKE_MAC_MASK) { -+ default: -+ break; -+ case SSL_HANDSHAKE_MAC_MD5_SHA1: /* SSL_HANDSHAKE_MAC_DEFAULT */ -+ return NID_md5_sha1; -+ case SSL_HANDSHAKE_MAC_SHA256: -+ return NID_sha256; -+ case SSL_HANDSHAKE_MAC_SHA384: -+ return NID_sha384; -+ } -+ return NID_undef; -+} ---- a/ssl/ssl_err.c -+++ b/ssl/ssl_err.c -@@ -27,6 +27,7 @@ static const ERR_STRING_DATA SSL_str_rea - "bad change cipher spec"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"}, -+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_LENGTH), "bad data length"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), - "bad data returned by callback"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"}, -@@ -548,6 +549,8 @@ static const ERR_STRING_DATA SSL_str_rea - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED), - "wrong cipher returned"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"}, -+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED), -+ "wrong encryption level received"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH), - "wrong signature length"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE), ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -856,6 +856,10 @@ SSL *SSL_new(SSL_CTX *ctx) - - s->job = NULL; - -+#ifndef OPENSSL_NO_QUIC -+ s->quic_method = ctx->quic_method; -+#endif -+ - #ifndef OPENSSL_NO_CT - if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback, - ctx->ct_validation_callback_arg)) -@@ -1253,6 +1257,18 @@ void SSL_free(SSL *s) - OPENSSL_free(s->pha_context); - EVP_MD_CTX_free(s->pha_dgst); - -+#ifndef OPENSSL_NO_QUIC -+ OPENSSL_free(s->ext.quic_transport_params); -+ OPENSSL_free(s->ext.peer_quic_transport_params); -+ while (s->quic_input_data_head != NULL) { -+ QUIC_DATA *qd; -+ -+ qd = s->quic_input_data_head; -+ s->quic_input_data_head = qd->next; -+ OPENSSL_free(qd); -+ } -+#endif -+ - sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free); - sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free); - -@@ -1852,6 +1868,12 @@ static int ssl_io_intern(void *vargs) - - int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) - { -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ return -1; -+ } -+#endif - if (s->handshake_func == NULL) { - ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); - return -1; -@@ -1983,6 +2005,12 @@ int SSL_get_early_data_status(const SSL - - static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes) - { -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ return -1; -+ } -+#endif - if (s->handshake_func == NULL) { - ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); - return -1; -@@ -2043,6 +2071,12 @@ int SSL_peek_ex(SSL *s, void *buf, size_ - - int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written) - { -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ return -1; -+ } -+#endif - if (s->handshake_func == NULL) { - ERR_raise(ERR_LIB_SSL, SSL_R_UNINITIALIZED); - return -1; -@@ -3875,6 +3909,11 @@ int SSL_get_error(const SSL *s, int i) - } - - if (SSL_want_read(s)) { -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ return SSL_ERROR_WANT_READ; -+ } -+#endif - bio = SSL_get_rbio(s); - if (BIO_should_read(bio)) - return SSL_ERROR_WANT_READ; -@@ -4242,7 +4281,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const - - const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) - { -- if ((s->session != NULL) && (s->session->cipher != NULL)) -+ if (s->session != NULL) - return s->session->cipher; - return NULL; - } ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -337,6 +337,13 @@ - /* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */ - # define SSL3_CK_CIPHERSUITE_FLAG 0x03000000 - -+/* Check if an SSL structure is using QUIC (which uses TLSv1.3) */ -+# ifndef OPENSSL_NO_QUIC -+# define SSL_IS_QUIC(s) (s->quic_method != NULL) -+# else -+# define SSL_IS_QUIC(s) 0 -+# endif -+ - /* Check if an SSL structure is using DTLS */ - # define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) - -@@ -766,6 +773,7 @@ typedef enum tlsext_index_en { - TLSEXT_IDX_cryptopro_bug, - TLSEXT_IDX_early_data, - TLSEXT_IDX_certificate_authorities, -+ TLSEXT_IDX_quic_transport_params, - TLSEXT_IDX_padding, - TLSEXT_IDX_psk, - /* Dummy index - must always be the last entry */ -@@ -1205,10 +1213,24 @@ struct ssl_ctx_st { - uint32_t disabled_mac_mask; - uint32_t disabled_mkey_mask; - uint32_t disabled_auth_mask; -+ -+#ifndef OPENSSL_NO_QUIC -+ const SSL_QUIC_METHOD *quic_method; -+#endif - }; - - typedef struct cert_pkey_st CERT_PKEY; - -+#ifndef OPENSSL_NO_QUIC -+struct quic_data_st { -+ struct quic_data_st *next; -+ OSSL_ENCRYPTION_LEVEL level; -+ size_t length; -+}; -+typedef struct quic_data_st QUIC_DATA; -+int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); -+#endif -+ - struct ssl_st { - /* - * protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, -@@ -1680,8 +1702,23 @@ struct ssl_st { - * selected. - */ - int tick_identity; -+ -+#ifndef OPENSSL_NO_QUIC -+ uint8_t *quic_transport_params; -+ size_t quic_transport_params_len; -+ uint8_t *peer_quic_transport_params; -+ size_t peer_quic_transport_params_len; -+#endif - } ext; - -+#ifndef OPENSSL_NO_QUIC -+ OSSL_ENCRYPTION_LEVEL quic_read_level; -+ OSSL_ENCRYPTION_LEVEL quic_write_level; -+ QUIC_DATA *quic_input_data_head; -+ QUIC_DATA *quic_input_data_tail; -+ const SSL_QUIC_METHOD *quic_method; -+ size_t quic_len; -+#endif - /* - * Parsed form of the ClientHello, kept around across client_hello_cb - * calls. ---- /dev/null -+++ b/ssl/ssl_quic.c -@@ -0,0 +1,248 @@ -+/* -+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. -+ * -+ * Licensed under the Apache License 2.0 (the "License"). You may not use -+ * this file except in compliance with the License. You can obtain a copy -+ * in the file LICENSE in the source distribution or at -+ * https://www.openssl.org/source/license.html -+ */ -+ -+#include "ssl_local.h" -+#include "internal/cryptlib.h" -+#include "internal/refcount.h" -+ -+#ifdef OPENSSL_NO_QUIC -+NON_EMPTY_TRANSLATION_UNIT -+#else -+ -+int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, -+ size_t params_len) -+{ -+ uint8_t *tmp; -+ -+ if (params == NULL || params_len == 0) { -+ tmp = NULL; -+ params_len = 0; -+ } else { -+ tmp = OPENSSL_memdup(params, params_len); -+ if (tmp == NULL) -+ return 0; -+ } -+ -+ OPENSSL_free(ssl->ext.quic_transport_params); -+ ssl->ext.quic_transport_params = tmp; -+ ssl->ext.quic_transport_params_len = params_len; -+ return 1; -+} -+ -+void SSL_get_peer_quic_transport_params(const SSL *ssl, -+ const uint8_t **out_params, -+ size_t *out_params_len) -+{ -+ *out_params = ssl->ext.peer_quic_transport_params; -+ *out_params_len = ssl->ext.peer_quic_transport_params_len; -+} -+ -+size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level) -+{ -+ /* -+ * Limits flights to 16K by default when there are no large -+ * (certificate-carrying) messages. -+ */ -+ static const size_t DEFAULT_FLIGHT_LIMIT = 16384; -+ -+ switch (level) { -+ case ssl_encryption_initial: -+ return DEFAULT_FLIGHT_LIMIT; -+ case ssl_encryption_early_data: -+ /* QUIC does not send EndOfEarlyData. */ -+ return 0; -+ case ssl_encryption_handshake: -+ if (ssl->server) { -+ /* -+ * Servers may receive Certificate message if configured to request -+ * client certificates. -+ */ -+ if ((ssl->verify_mode & SSL_VERIFY_PEER) -+ && ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT) -+ return ssl->max_cert_list; -+ } else { -+ /* -+ * Clients may receive both Certificate message and a CertificateRequest -+ * message. -+ */ -+ if (2*ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT) -+ return 2 * ssl->max_cert_list; -+ } -+ return DEFAULT_FLIGHT_LIMIT; -+ case ssl_encryption_application: -+ return DEFAULT_FLIGHT_LIMIT; -+ } -+ -+ return 0; -+} -+ -+OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl) -+{ -+ return ssl->quic_read_level; -+} -+ -+OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl) -+{ -+ return ssl->quic_write_level; -+} -+ -+int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *data, size_t len) -+{ -+ size_t l; -+ -+ if (!SSL_IS_QUIC(ssl)) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ return 0; -+ } -+ -+ /* Level can be different than the current read, but not less */ -+ if (level < ssl->quic_read_level -+ || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); -+ return 0; -+ } -+ -+ /* Split the QUIC messages up, if necessary */ -+ while (len > 0) { -+ QUIC_DATA *qd; -+ const uint8_t *p = data + 1; -+ -+ n2l3(p, l); -+ l += SSL3_HM_HEADER_LENGTH; -+ -+ if (l > len) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_DATA_LENGTH); -+ return 0; -+ } -+ -+ qd = OPENSSL_malloc(sizeof(QUIC_DATA) + l); -+ if (qd == NULL) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ -+ qd->next = NULL; -+ qd->length = l; -+ qd->level = level; -+ memcpy((void*)(qd + 1), data, l); -+ if (ssl->quic_input_data_tail != NULL) -+ ssl->quic_input_data_tail->next = qd; -+ else -+ ssl->quic_input_data_head = qd; -+ ssl->quic_input_data_tail = qd; -+ -+ data += l; -+ len -= l; -+ } -+ -+ return 1; -+} -+ -+int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) -+{ -+ switch (ctx->method->version) { -+ case DTLS1_VERSION: -+ case DTLS1_2_VERSION: -+ case DTLS_ANY_VERSION: -+ case DTLS1_BAD_VER: -+ return 0; -+ default: -+ break; -+ } -+ ctx->quic_method = quic_method; -+ ctx->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; -+ return 1; -+} -+ -+int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) -+{ -+ switch (ssl->method->version) { -+ case DTLS1_VERSION: -+ case DTLS1_2_VERSION: -+ case DTLS_ANY_VERSION: -+ case DTLS1_BAD_VER: -+ return 0; -+ default: -+ break; -+ } -+ ssl->quic_method = quic_method; -+ ssl->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; -+ return 1; -+} -+ -+int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) -+{ -+ uint8_t *read_secret = NULL; -+ uint8_t *write_secret = NULL; -+ static const unsigned char zeros[EVP_MAX_MD_SIZE]; -+ -+ if (!SSL_IS_QUIC(ssl)) -+ return 1; -+ -+ /* secrets from the POV of the client */ -+ switch (level) { -+ case ssl_encryption_early_data: -+ write_secret = ssl->early_secret; -+ break; -+ case ssl_encryption_handshake: -+ read_secret = ssl->client_finished_secret; -+ write_secret = ssl->server_finished_secret; -+ break; -+ case ssl_encryption_application: -+ read_secret = ssl->client_app_traffic_secret; -+ write_secret = ssl->server_app_traffic_secret; -+ break; -+ default: -+ return 1; -+ } -+ /* In some cases, we want to set the secret only when BOTH are non-zero */ -+ if (read_secret != NULL && write_secret != NULL -+ && !memcmp(read_secret, zeros, ssl->quic_len) -+ && !memcmp(write_secret, zeros, ssl->quic_len)) -+ return 1; -+ -+ if (ssl->server) { -+ if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret, -+ write_secret, ssl->quic_len)) { -+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ } else { -+ if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret, -+ read_secret, ssl->quic_len)) { -+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ } -+ -+ return 1; -+} -+ -+int SSL_process_quic_post_handshake(SSL *ssl) -+{ -+ if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) { -+ SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ return 0; -+ } -+ -+ ossl_statem_set_in_init(ssl, 1); -+ -+ if (ssl->handshake_func(ssl) <= 0) -+ return 0; -+ -+ return 1; -+} -+ -+int SSL_is_quic(SSL* ssl) -+{ -+ return SSL_IS_QUIC(ssl); -+} -+ -+#endif ---- a/ssl/statem/extensions.c -+++ b/ssl/statem/extensions.c -@@ -59,6 +59,10 @@ static int final_early_data(SSL *s, unsi - static int final_maxfragmentlen(SSL *s, unsigned int context, int sent); - static int init_post_handshake_auth(SSL *s, unsigned int context); - static int final_psk(SSL *s, unsigned int context, int sent); -+#ifndef OPENSSL_NO_QUIC -+static int init_quic_transport_params(SSL *s, unsigned int context); -+static int final_quic_transport_params(SSL *s, unsigned int context, int sent); -+#endif - - /* Structure to define a built-in extension */ - typedef struct extensions_definition_st { -@@ -370,6 +374,19 @@ static const EXTENSION_DEFINITION ext_de - tls_construct_certificate_authorities, - tls_construct_certificate_authorities, NULL, - }, -+#ifndef OPENSSL_NO_QUIC -+ { -+ TLSEXT_TYPE_quic_transport_parameters, -+ SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO -+ | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, -+ init_quic_transport_params, -+ tls_parse_ctos_quic_transport_params, tls_parse_stoc_quic_transport_params, -+ tls_construct_stoc_quic_transport_params, tls_construct_ctos_quic_transport_params, -+ final_quic_transport_params, -+ }, -+#else -+ INVALID_EXTENSION, -+#endif - { - /* Must be immediately before pre_shared_key */ - TLSEXT_TYPE_padding, -@@ -1722,3 +1739,15 @@ static int final_psk(SSL *s, unsigned in - - return 1; - } -+ -+#ifndef OPENSSL_NO_QUIC -+static int init_quic_transport_params(SSL *s, unsigned int context) -+{ -+ return 1; -+} -+ -+static int final_quic_transport_params(SSL *s, unsigned int context, int sent) -+{ -+ return 1; -+} -+#endif ---- a/ssl/statem/extensions_clnt.c -+++ b/ssl/statem/extensions_clnt.c -@@ -1196,7 +1196,29 @@ EXT_RETURN tls_construct_ctos_post_hands - #endif - } - -+#ifndef OPENSSL_NO_QUIC -+/* SAME AS tls_construct_stoc_quic_transport_params() */ -+EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx) -+{ -+ if (s->ext.quic_transport_params == NULL -+ || s->ext.quic_transport_params_len == 0) { -+ return EXT_RETURN_NOT_SENT; -+ } -+ -+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) -+ || !WPACKET_start_sub_packet_u16(pkt) -+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -+ s->ext.quic_transport_params_len) -+ || !WPACKET_close(pkt)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return EXT_RETURN_FAIL; -+ } - -+ return EXT_RETURN_SENT; -+} -+#endif - /* - * Parse the server's renegotiation binding and abort if it's not right - */ -@@ -2006,3 +2028,29 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p - - return 1; - } -+#ifndef OPENSSL_NO_QUIC -+/* SAME AS tls_parse_ctos_quic_transport_params() */ -+int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, -+ X509 *x, size_t chainidx) -+{ -+ PACKET trans_param; -+ -+ if (!PACKET_as_length_prefixed_2(pkt, &trans_param) -+ || PACKET_remaining(&trans_param) == 0) { -+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); -+ return 0; -+ } -+ -+ OPENSSL_free(s->ext.peer_quic_transport_params); -+ s->ext.peer_quic_transport_params = NULL; -+ s->ext.peer_quic_transport_params_len = 0; -+ -+ if (!PACKET_memdup(&trans_param, -+ &s->ext.peer_quic_transport_params, -+ &s->ext.peer_quic_transport_params_len)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ return 1; -+} -+#endif ---- a/ssl/statem/extensions_srvr.c -+++ b/ssl/statem/extensions_srvr.c -@@ -1249,6 +1249,33 @@ int tls_parse_ctos_post_handshake_auth(S - return 1; - } - -+#ifndef OPENSSL_NO_QUIC -+/* SAME AS tls_parse_stoc_quic_transport_params() */ -+int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, -+ X509 *x, size_t chainidx) -+{ -+ PACKET trans_param; -+ -+ if (!PACKET_as_length_prefixed_2(pkt, &trans_param) -+ || PACKET_remaining(&trans_param) == 0) { -+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); -+ return 0; -+ } -+ -+ OPENSSL_free(s->ext.peer_quic_transport_params); -+ s->ext.peer_quic_transport_params = NULL; -+ s->ext.peer_quic_transport_params_len = 0; -+ -+ if (!PACKET_memdup(&trans_param, -+ &s->ext.peer_quic_transport_params, -+ &s->ext.peer_quic_transport_params_len)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ return 1; -+} -+#endif -+ - /* - * Add the server's renegotiation binding - */ -@@ -1932,3 +1959,27 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s - - return EXT_RETURN_SENT; - } -+ -+#ifndef OPENSSL_NO_QUIC -+/* SAME AS tls_construct_ctos_quic_transport_params() */ -+EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx) -+{ -+ if (s->ext.quic_transport_params == NULL -+ || s->ext.quic_transport_params_len == 0) { -+ return EXT_RETURN_NOT_SENT; -+ } -+ -+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) -+ || !WPACKET_start_sub_packet_u16(pkt) -+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -+ s->ext.quic_transport_params_len) -+ || !WPACKET_close(pkt)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return EXT_RETURN_FAIL; -+ } -+ -+ return EXT_RETURN_SENT; -+} -+#endif ---- a/ssl/statem/statem.c -+++ b/ssl/statem/statem.c -@@ -583,6 +583,10 @@ static SUB_STATE_RETURN read_state_machi - * In DTLS we get the whole message in one go - header and body - */ - ret = dtls_get_message(s, &mt); -+#ifndef OPENSSL_NO_QUIC -+ } else if (SSL_IS_QUIC(s)) { -+ ret = quic_get_message(s, &mt, &len); -+#endif - } else { - ret = tls_get_message_header(s, &mt); - } -@@ -612,8 +616,8 @@ static SUB_STATE_RETURN read_state_machi - return SUB_STATE_ERROR; - } - -- /* dtls_get_message already did this */ -- if (!SSL_IS_DTLS(s) -+ /* dtls_get_message/quic_get_message already did this */ -+ if (!SSL_IS_DTLS(s) && !SSL_IS_QUIC(s) - && s->s3.tmp.message_size > 0 - && !grow_init_buf(s, s->s3.tmp.message_size - + SSL3_HM_HEADER_LENGTH)) { -@@ -631,7 +635,8 @@ static SUB_STATE_RETURN read_state_machi - * opportunity to do any further processing. - */ - ret = dtls_get_message_body(s, &len); -- } else { -+ } else if (!SSL_IS_QUIC(s)) { -+ /* We already got this above for QUIC */ - ret = tls_get_message_body(s, &len); - } - if (ret == 0) { -@@ -921,6 +926,15 @@ static SUB_STATE_RETURN write_state_mach - int statem_flush(SSL *s) - { - s->rwstate = SSL_WRITING; -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ if (!s->quic_method->flush_flight(s)) { -+ /* NOTE: BIO_flush() does not generate an error */ -+ SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ } else -+#endif - if (BIO_flush(s->wbio) <= 0) { - return 0; - } ---- a/ssl/statem/statem_lib.c -+++ b/ssl/statem/statem_lib.c -@@ -44,9 +44,23 @@ int ssl3_do_write(SSL *s, int type) - { - int ret; - size_t written = 0; -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s) && type == SSL3_RT_HANDSHAKE) { -+ ret = s->quic_method->add_handshake_data(s, s->quic_write_level, -+ (const uint8_t*)&s->init_buf->data[s->init_off], -+ s->init_num); -+ if (!ret) { -+ ret = -1; -+ /* QUIC can't sent anything out sice the above failed */ -+ SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); -+ } else { -+ written = s->init_num; -+ } -+ } else -+#endif -+ ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off], -+ s->init_num, &written); - -- ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off], -- s->init_num, &written); - if (ret <= 0) - return -1; - if (type == SSL3_RT_HANDSHAKE) -@@ -1173,6 +1187,7 @@ int tls_get_message_header(SSL *s, int * - - do { - while (s->init_num < SSL3_HM_HEADER_LENGTH) { -+ /* QUIC: either create a special ssl_read_bytes... or if/else this */ - i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, - &p[s->init_num], - SSL3_HM_HEADER_LENGTH - s->init_num, ---- a/ssl/statem/statem_local.h -+++ b/ssl/statem/statem_local.h -@@ -104,6 +104,7 @@ __owur int tls_get_message_header(SSL *s - __owur int tls_get_message_body(SSL *s, size_t *len); - __owur int dtls_get_message(SSL *s, int *mt); - __owur int dtls_get_message_body(SSL *s, size_t *len); -+__owur int quic_get_message(SSL *s, int *mt, size_t *len); - - /* Message construction and processing functions */ - __owur int tls_process_initial_server_flight(SSL *s); -@@ -251,6 +252,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *p - size_t chainidx); - int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); -+#ifndef OPENSSL_NO_QUIC -+int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, -+ X509 *x, size_t chainidx); -+#endif - - EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, - unsigned int context, X509 *x, -@@ -311,6 +316,11 @@ EXT_RETURN tls_construct_stoc_cryptopro_ - size_t chainidx); - EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); -+#ifndef OPENSSL_NO_QUIC -+EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx); -+#endif - - /* Client Extension processing */ - EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context, -@@ -380,6 +390,11 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s - X509 *x, size_t chainidx); - EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); -+#ifndef OPENSSL_NO_QUIC -+EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx); -+#endif - - int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); -@@ -423,6 +438,10 @@ int tls_parse_stoc_cookie(SSL *s, PACKET - size_t chainidx); - int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx); -+#ifndef OPENSSL_NO_QUIC -+int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, -+ X509 *x, size_t chainidx); -+#endif - - int tls_handle_alpn(SSL *s); - ---- /dev/null -+++ b/ssl/statem/statem_quic.c -@@ -0,0 +1,106 @@ -+/* -+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. -+ * -+ * Licensed under the Apache License 2.0 (the "License"). You may not use -+ * this file except in compliance with the License. You can obtain a copy -+ * in the file LICENSE in the source distribution or at -+ * https://www.openssl.org/source/license.html -+ */ -+ -+#include "../ssl_local.h" -+#include "statem_local.h" -+#include "internal/cryptlib.h" -+ -+#ifdef OPENSSL_NO_QUIC -+NON_EMPTY_TRANSLATION_UNIT -+#else -+ -+int quic_get_message(SSL *s, int *mt, size_t *len) -+{ -+ size_t l; -+ QUIC_DATA *qd; -+ uint8_t *p; -+ -+ if (s->quic_input_data_head == NULL) { -+ s->rwstate = SSL_READING; -+ *len = 0; -+ return 0; -+ } -+ -+ /* This is where we check for the proper level, not when data is given */ -+ if (s->quic_input_data_head->level != s->quic_read_level) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); -+ *len = 0; -+ return 0; -+ } -+ -+ if (!BUF_MEM_grow_clean(s->init_buf, (int)s->quic_input_data_head->length)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); -+ *len = 0; -+ return 0; -+ } -+ -+ /* Copy buffered data */ -+ qd = s->quic_input_data_head; -+ memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); -+ s->init_buf->length = qd->length; -+ s->quic_input_data_head = qd->next; -+ if (s->quic_input_data_head == NULL) -+ s->quic_input_data_tail = NULL; -+ OPENSSL_free(qd); -+ -+ s->s3.tmp.message_type = *mt = *(s->init_buf->data); -+ p = (uint8_t*)s->init_buf->data + 1; -+ n2l3(p, l); -+ s->init_num = s->s3.tmp.message_size = *len = l; -+ s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH; -+ -+ /* No CCS in QUIC/TLSv1.3? */ -+ if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { -+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_CCS_RECEIVED_EARLY); -+ *len = 0; -+ return 0; -+ } -+ -+ /* -+ * If receiving Finished, record MAC of prior handshake messages for -+ * Finished verification. -+ */ -+ if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { -+ /* SSLfatal() already called */ -+ *len = 0; -+ return 0; -+ } -+ -+ /* -+ * We defer feeding in the HRR until later. We'll do it as part of -+ * processing the message -+ * The TLsv1.3 handshake transcript stops at the ClientFinished -+ * message. -+ */ -+#define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2) -+ /* KeyUpdate and NewSessionTicket do not need to be added */ -+ if (!SSL_IS_TLS13(s) || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET -+ && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) { -+ if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO -+ || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE -+ || memcmp(hrrrandom, -+ s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET, -+ SSL3_RANDOM_SIZE) != 0) { -+ if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, -+ s->init_num + SSL3_HM_HEADER_LENGTH)) { -+ /* SSLfatal() already called */ -+ *len = 0; -+ return 0; -+ } -+ } -+ } -+ if (s->msg_callback) -+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, -+ (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s, -+ s->msg_callback_arg); -+ -+ return 1; -+} -+ -+#endif ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -440,6 +440,9 @@ int tls13_change_cipher_state(SSL *s, in - ktls_crypto_info_t crypto_info; - BIO *bio; - #endif -+#ifndef OPENSSL_NO_QUIC -+ OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; -+#endif - - if (which & SSL3_CC_READ) { - if (s->enc_read_ctx != NULL) { -@@ -485,6 +488,9 @@ int tls13_change_cipher_state(SSL *s, in - label = client_early_traffic; - labellen = sizeof(client_early_traffic) - 1; - log_label = CLIENT_EARLY_LABEL; -+#ifndef OPENSSL_NO_QUIC -+ level = ssl_encryption_early_data; -+#endif - - handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata); - if (handlen <= 0) { -@@ -544,6 +550,9 @@ int tls13_change_cipher_state(SSL *s, in - goto err; - } - hashlen = hashlenui; -+#ifndef OPENSSL_NO_QUIC -+ s->quic_len = hashlen; -+#endif - EVP_MD_CTX_free(mdctx); - - if (!tls13_hkdf_expand(s, md, insecret, -@@ -561,6 +570,14 @@ int tls13_change_cipher_state(SSL *s, in - /* SSLfatal() already called */ - goto err; - } -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ if (s->server) -+ s->quic_read_level = ssl_encryption_early_data; -+ else -+ s->quic_write_level = ssl_encryption_early_data; -+ } -+#endif - } else if (which & SSL3_CC_HANDSHAKE) { - insecret = s->handshake_secret; - finsecret = s->client_finished_secret; -@@ -568,6 +585,15 @@ int tls13_change_cipher_state(SSL *s, in - label = client_handshake_traffic; - labellen = sizeof(client_handshake_traffic) - 1; - log_label = CLIENT_HANDSHAKE_LABEL; -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ level = ssl_encryption_handshake; -+ if (s->server) -+ s->quic_read_level = ssl_encryption_handshake; -+ else -+ s->quic_write_level = ssl_encryption_handshake; -+ } -+#endif - /* - * The handshake hash used for the server read/client write handshake - * traffic secret is the same as the hash for the server -@@ -590,6 +616,15 @@ int tls13_change_cipher_state(SSL *s, in - * previously saved value. - */ - hash = s->server_finished_hash; -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ level = ssl_encryption_application; /* ??? */ -+ if (s->server) -+ s->quic_read_level = ssl_encryption_application; -+ else -+ s->quic_write_level = ssl_encryption_application; -+ } -+#endif - } - } else { - /* Early data never applies to client-read/server-write */ -@@ -600,11 +635,29 @@ int tls13_change_cipher_state(SSL *s, in - label = server_handshake_traffic; - labellen = sizeof(server_handshake_traffic) - 1; - log_label = SERVER_HANDSHAKE_LABEL; -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ level = ssl_encryption_handshake; -+ if (s->server) -+ s->quic_write_level = ssl_encryption_handshake; -+ else -+ s->quic_read_level = ssl_encryption_handshake; -+ } -+#endif - } else { - insecret = s->master_secret; - label = server_application_traffic; - labellen = sizeof(server_application_traffic) - 1; - log_label = SERVER_APPLICATION_LABEL; -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ level = ssl_encryption_application; -+ if (s->server) -+ s->quic_write_level = ssl_encryption_application; -+ else -+ s->quic_read_level = ssl_encryption_application; -+ } -+#endif - } - } - -@@ -732,6 +785,12 @@ int tls13_change_cipher_state(SSL *s, in - skip_ktls: - # endif - #endif -+ -+#ifndef OPENSSL_NO_QUIC -+ if (!quic_set_encryption_secrets(s, level)) -+ goto err; -+#endif -+ - ret = 1; - err: - if ((which & SSL3_CC_EARLY) != 0) { ---- a/test/helpers/ssltestlib.c -+++ b/test/helpers/ssltestlib.c -@@ -1166,6 +1166,11 @@ int create_ssl_connection(SSL *serverssl - if (!create_bare_ssl_connection(serverssl, clientssl, want, 1)) - return 0; - -+#ifndef OPENSSL_NO_QUIC -+ /* QUIC does not support SSL_read_ex */ -+ if (SSL_is_quic(clientssl)) -+ return 1; -+#endif - /* - * We attempt to read some data on the client side which we expect to fail. - * This will ensure we have received the NewSessionTicket in TLSv1.3 where ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10765,6 +10765,135 @@ static int test_multi_resume(int idx) - return testresult; - } - -+#ifndef OPENSSL_NO_QUIC -+static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *read_secret, -+ const uint8_t *write_secret, size_t secret_len) -+{ -+ test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n", -+ ssl->server ? "server" : "client", level, secret_len); -+ return 1; -+} -+ -+static int test_quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+ const uint8_t *data, size_t len) -+{ -+ SSL *peer = (SSL*)SSL_get_app_data(ssl); -+ -+ test_printf_stderr("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", -+ ssl->server ? "server" : "client", level, (int)*data, len); -+ if (!TEST_ptr(peer)) -+ return 0; -+ -+ if (!TEST_true(SSL_provide_quic_data(peer, level, data, len))) { -+ ERR_print_errors_fp(stderr); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static int test_quic_flush_flight(SSL *ssl) -+{ -+ test_printf_stderr("quic_flush_flight() %s\n", ssl->server ? "server" : "client"); -+ return 1; -+} -+ -+static int test_quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) -+{ -+ test_printf_stderr("quic_send_alert() %s, lvl=%d, alert=%d\n", -+ ssl->server ? "server" : "client", level, alert); -+ return 1; -+} -+ -+static SSL_QUIC_METHOD quic_method = { -+ test_quic_set_encryption_secrets, -+ test_quic_add_handshake_data, -+ test_quic_flush_flight, -+ test_quic_send_alert, -+}; -+ -+static int test_quic_api(void) -+{ -+ SSL_CTX *cctx = NULL, *sctx = NULL; -+ SSL *clientssl = NULL, *serverssl = NULL; -+ int testresult = 0; -+ -+ static const char *server_str = "SERVER"; -+ static const char *client_str = "CLIENT"; -+ const uint8_t *peer_str; -+ size_t peer_str_len; -+ -+ /* Clean up logging space */ -+ memset(client_log_buffer, 0, sizeof(client_log_buffer)); -+ memset(server_log_buffer, 0, sizeof(server_log_buffer)); -+ client_log_buffer_index = 0; -+ server_log_buffer_index = 0; -+ error_writing_log = 0; -+ -+ -+ if (!TEST_ptr(sctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method())) -+ || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) -+ || !TEST_ptr(sctx->quic_method) -+ || !TEST_ptr(serverssl = SSL_new(sctx)) -+ || !TEST_true(SSL_IS_QUIC(serverssl)) -+ || !TEST_true(SSL_set_quic_method(serverssl, NULL)) -+ || !TEST_false(SSL_IS_QUIC(serverssl)) -+ || !TEST_true(SSL_set_quic_method(serverssl, &quic_method)) -+ || !TEST_true(SSL_IS_QUIC(serverssl))) -+ goto end; -+ -+ SSL_CTX_free(sctx); -+ sctx = NULL; -+ SSL_free(serverssl); -+ serverssl = NULL; -+ -+ if (!TEST_true(create_ssl_ctx_pair(libctx, -+ TLS_server_method(), -+ TLS_client_method(), -+ TLS1_3_VERSION, 0, -+ &sctx, &cctx, cert, privkey)) -+ || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) -+ || !TEST_true(SSL_CTX_set_quic_method(cctx, &quic_method)) -+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, -+ &clientssl, NULL, NULL)) -+ || !TEST_true(SSL_set_quic_transport_params(serverssl, -+ (unsigned char*)server_str, -+ sizeof(server_str))) -+ || !TEST_true(SSL_set_quic_transport_params(clientssl, -+ (unsigned char*)client_str, -+ sizeof(client_str))) -+ || !TEST_true(SSL_set_app_data(serverssl, clientssl)) -+ || !TEST_true(SSL_set_app_data(clientssl, serverssl)) -+ || !TEST_true(create_ssl_connection(serverssl, clientssl, -+ SSL_ERROR_NONE)) -+ || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) -+ || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) -+ || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) -+ || !(TEST_int_eq(SSL_quic_read_level(serverssl), ssl_encryption_application)) -+ || !(TEST_int_eq(SSL_quic_write_level(clientssl), ssl_encryption_application)) -+ || !(TEST_int_eq(SSL_quic_write_level(serverssl), ssl_encryption_application))) -+ goto end; -+ -+ SSL_get_peer_quic_transport_params(serverssl, &peer_str, &peer_str_len); -+ if (!TEST_mem_eq(peer_str, peer_str_len, client_str, sizeof(client_str))) -+ goto end; -+ SSL_get_peer_quic_transport_params(clientssl, &peer_str, &peer_str_len); -+ if (!TEST_mem_eq(peer_str, peer_str_len, server_str, sizeof(server_str))) -+ goto end; -+ -+ /* Deal with two NewSessionTickets */ -+ if (!TEST_true(SSL_process_quic_post_handshake(clientssl)) -+ || !TEST_true(SSL_process_quic_post_handshake(clientssl))) -+ goto end; -+ -+ testresult = 1; -+ -+ end: -+ return testresult; -+} -+#endif /* OPENSSL_NO_QUIC */ -+ - static struct next_proto_st { - int serverlen; - unsigned char server[40]; -@@ -11482,6 +11611,9 @@ int setup_tests(void) - #endif - ADD_ALL_TESTS(test_alpn, 4); - ADD_ALL_TESTS(test_no_renegotiation, 2); -+#ifndef OPENSSL_NO_QUIC -+ ADD_TEST(test_quic_api); -+#endif - return 1; - - err: ---- a/test/tls13secretstest.c -+++ b/test/tls13secretstest.c -@@ -224,6 +224,13 @@ void ssl_evp_md_free(const EVP_MD *md) - { - } - -+#ifndef OPENSSL_NO_QUIC -+int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) -+{ -+ return 1; -+} -+#endif -+ - /* End of mocked out code */ - - static int test_secret(SSL *s, unsigned char *prk, ---- a/util/libssl.num -+++ b/util/libssl.num -@@ -520,3 +520,14 @@ SSL_load_client_CA_file_ex - SSL_set0_tmp_dh_pkey 521 3_0_0 EXIST::FUNCTION: - SSL_CTX_set0_tmp_dh_pkey 522 3_0_0 EXIST::FUNCTION: - SSL_group_to_name 523 3_0_0 EXIST::FUNCTION: -+SSL_quic_read_level 20000 3_0_0 EXIST::FUNCTION:QUIC -+SSL_set_quic_transport_params 20001 3_0_0 EXIST::FUNCTION:QUIC -+SSL_CIPHER_get_prf_nid 20002 3_0_0 EXIST::FUNCTION: -+SSL_is_quic 20003 3_0_0 EXIST::FUNCTION:QUIC -+SSL_get_peer_quic_transport_params 20004 3_0_0 EXIST::FUNCTION:QUIC -+SSL_quic_write_level 20005 3_0_0 EXIST::FUNCTION:QUIC -+SSL_CTX_set_quic_method 20006 3_0_0 EXIST::FUNCTION:QUIC -+SSL_set_quic_method 20007 3_0_0 EXIST::FUNCTION:QUIC -+SSL_quic_max_handshake_flight_len 20008 3_0_0 EXIST::FUNCTION:QUIC -+SSL_process_quic_post_handshake 20009 3_0_0 EXIST::FUNCTION:QUIC -+SSL_provide_quic_data 20010 3_0_0 EXIST::FUNCTION:QUIC ---- a/util/other.syms -+++ b/util/other.syms -@@ -143,6 +143,8 @@ custom_ext_free_cb - custom_ext_parse_cb datatype - pem_password_cb datatype - ssl_ct_validation_cb datatype -+OSSL_ENCRYPTION_LEVEL datatype -+SSL_QUIC_METHOD datatype - # - ASN1_BIT_STRING_digest define - BIO_append_filename define diff --git a/openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch b/openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch deleted file mode 100644 index 595c8b720..000000000 --- a/openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch +++ /dev/null @@ -1,90 +0,0 @@ -From faa77f36f0e0be37bf9733a14d79a8e9f5863c45 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 14 Jun 2019 12:04:14 -0400 -Subject: [PATCH 02/43] QUIC: New method to get QUIC secret length - ---- - ssl/ssl_local.h | 1 - - ssl/ssl_quic.c | 30 ++++++++++++++++++++++++++---- - ssl/tls13_enc.c | 3 --- - 3 files changed, 26 insertions(+), 8 deletions(-) - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1717,7 +1717,6 @@ struct ssl_st { - QUIC_DATA *quic_input_data_head; - QUIC_DATA *quic_input_data_tail; - const SSL_QUIC_METHOD *quic_method; -- size_t quic_len; - #endif - /* - * Parsed form of the ClientHello, kept around across client_hello_cb ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -181,6 +181,8 @@ int quic_set_encryption_secrets(SSL *ssl - { - uint8_t *read_secret = NULL; - uint8_t *write_secret = NULL; -+ size_t len; -+ const EVP_MD *md; - static const unsigned char zeros[EVP_MAX_MD_SIZE]; - - if (!SSL_IS_QUIC(ssl)) -@@ -202,21 +204,41 @@ int quic_set_encryption_secrets(SSL *ssl - default: - return 1; - } -+ -+ md = ssl_handshake_md(ssl); -+ if (md == NULL) { -+ /* May not have selected cipher, yet */ -+ const SSL_CIPHER *c = NULL; -+ -+ if (ssl->session != NULL) -+ c = SSL_SESSION_get0_cipher(ssl->session); -+ else if (ssl->psksession != NULL) -+ c = SSL_SESSION_get0_cipher(ssl->psksession); -+ -+ if (c != NULL) -+ md = SSL_CIPHER_get_handshake_digest(c); -+ } -+ -+ if ((len = EVP_MD_size(md)) <= 0) { -+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ - /* In some cases, we want to set the secret only when BOTH are non-zero */ - if (read_secret != NULL && write_secret != NULL -- && !memcmp(read_secret, zeros, ssl->quic_len) -- && !memcmp(write_secret, zeros, ssl->quic_len)) -+ && !memcmp(read_secret, zeros, len) -+ && !memcmp(write_secret, zeros, len)) - return 1; - - if (ssl->server) { - if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret, -- write_secret, ssl->quic_len)) { -+ write_secret, len)) { - SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return 0; - } - } else { - if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret, -- read_secret, ssl->quic_len)) { -+ read_secret, len)) { - SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return 0; - } ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -550,9 +550,6 @@ int tls13_change_cipher_state(SSL *s, in - goto err; - } - hashlen = hashlenui; --#ifndef OPENSSL_NO_QUIC -- s->quic_len = hashlen; --#endif - EVP_MD_CTX_free(mdctx); - - if (!tls13_hkdf_expand(s, md, insecret, diff --git a/openwrt/patch/openssl/quic/0003-QUIC-Make-temp-secret-names-less-confusing.patch b/openwrt/patch/openssl/quic/0003-QUIC-Make-temp-secret-names-less-confusing.patch deleted file mode 100644 index 652578bac..000000000 --- a/openwrt/patch/openssl/quic/0003-QUIC-Make-temp-secret-names-less-confusing.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0e937646383bf2dddf8cc6eb63ad0a56bdd7a9ad Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 15 Aug 2019 11:13:15 -0400 -Subject: [PATCH 03/43] QUIC: Make temp secret names less confusing - ---- - ssl/ssl_quic.c | 28 ++++++++++++++-------------- - 1 file changed, 14 insertions(+), 14 deletions(-) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -179,8 +179,8 @@ int SSL_set_quic_method(SSL *ssl, const - - int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level) - { -- uint8_t *read_secret = NULL; -- uint8_t *write_secret = NULL; -+ uint8_t *c2s_secret = NULL; -+ uint8_t *s2c_secret = NULL; - size_t len; - const EVP_MD *md; - static const unsigned char zeros[EVP_MAX_MD_SIZE]; -@@ -191,15 +191,15 @@ int quic_set_encryption_secrets(SSL *ssl - /* secrets from the POV of the client */ - switch (level) { - case ssl_encryption_early_data: -- write_secret = ssl->early_secret; -+ s2c_secret = ssl->early_secret; - break; - case ssl_encryption_handshake: -- read_secret = ssl->client_finished_secret; -- write_secret = ssl->server_finished_secret; -+ c2s_secret = ssl->client_finished_secret; -+ s2c_secret = ssl->server_finished_secret; - break; - case ssl_encryption_application: -- read_secret = ssl->client_app_traffic_secret; -- write_secret = ssl->server_app_traffic_secret; -+ c2s_secret = ssl->client_app_traffic_secret; -+ s2c_secret = ssl->server_app_traffic_secret; - break; - default: - return 1; -@@ -225,20 +225,20 @@ int quic_set_encryption_secrets(SSL *ssl - } - - /* In some cases, we want to set the secret only when BOTH are non-zero */ -- if (read_secret != NULL && write_secret != NULL -- && !memcmp(read_secret, zeros, len) -- && !memcmp(write_secret, zeros, len)) -+ if (c2s_secret != NULL && s2c_secret != NULL -+ && !memcmp(c2s_secret, zeros, len) -+ && !memcmp(s2c_secret, zeros, len)) - return 1; - - if (ssl->server) { -- if (!ssl->quic_method->set_encryption_secrets(ssl, level, read_secret, -- write_secret, len)) { -+ if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret, -+ s2c_secret, len)) { - SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return 0; - } - } else { -- if (!ssl->quic_method->set_encryption_secrets(ssl, level, write_secret, -- read_secret, len)) { -+ if (!ssl->quic_method->set_encryption_secrets(ssl, level, s2c_secret, -+ c2s_secret, len)) { - SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return 0; - } diff --git a/openwrt/patch/openssl/quic/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch b/openwrt/patch/openssl/quic/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch deleted file mode 100644 index d718b6f3b..000000000 --- a/openwrt/patch/openssl/quic/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 53f22b3eaa410edb8f1b26ce2a61b76d2485090d Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 15 Aug 2019 11:35:10 -0400 -Subject: [PATCH 04/43] QUIC: Move QUIC transport params to encrypted - extensions - ---- - ssl/statem/extensions.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/ssl/statem/extensions.c -+++ b/ssl/statem/extensions.c -@@ -377,7 +377,7 @@ static const EXTENSION_DEFINITION ext_de - #ifndef OPENSSL_NO_QUIC - { - TLSEXT_TYPE_quic_transport_parameters, -- SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_SERVER_HELLO -+ SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS - | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, - init_quic_transport_params, - tls_parse_ctos_quic_transport_params, tls_parse_stoc_quic_transport_params, diff --git a/openwrt/patch/openssl/quic/0005-QUIC-Use-proper-secrets-for-handshake.patch b/openwrt/patch/openssl/quic/0005-QUIC-Use-proper-secrets-for-handshake.patch deleted file mode 100644 index 6a5b08fa1..000000000 --- a/openwrt/patch/openssl/quic/0005-QUIC-Use-proper-secrets-for-handshake.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 73ef78a611eb40a0a74c60aa9fe9850ae69d08b6 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 15 Aug 2019 12:37:03 -0400 -Subject: [PATCH 05/43] QUIC: Use proper secrets for handshake - ---- - ssl/ssl_local.h | 2 ++ - ssl/ssl_quic.c | 4 ++-- - ssl/tls13_enc.c | 6 ++++++ - 3 files changed, 10 insertions(+), 2 deletions(-) - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1490,6 +1490,8 @@ struct ssl_st { - unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE]; - unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE]; -+ unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE]; -+ unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char exporter_master_secret[EVP_MAX_MD_SIZE]; - unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE]; - EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -194,8 +194,8 @@ int quic_set_encryption_secrets(SSL *ssl - s2c_secret = ssl->early_secret; - break; - case ssl_encryption_handshake: -- c2s_secret = ssl->client_finished_secret; -- s2c_secret = ssl->server_finished_secret; -+ c2s_secret = ssl->client_hand_traffic_secret; -+ s2c_secret = ssl->server_hand_traffic_secret; - break; - case ssl_encryption_application: - c2s_secret = ssl->client_app_traffic_secret; ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -723,6 +723,12 @@ int tls13_change_cipher_state(SSL *s, in - } - } else if (label == client_application_traffic) - memcpy(s->client_app_traffic_secret, secret, hashlen); -+#ifndef OPENSSL_NO_QUIC -+ else if (label == client_handshake_traffic) -+ memcpy(s->client_hand_traffic_secret, secret, hashlen); -+ else if (label == server_handshake_traffic) -+ memcpy(s->server_hand_traffic_secret, secret, hashlen); -+#endif - - if (!ssl_log_secret(s, log_label, secret, hashlen)) { - /* SSLfatal() already called */ diff --git a/openwrt/patch/openssl/quic/0006-QUIC-Handle-partial-handshake-messages.patch b/openwrt/patch/openssl/quic/0006-QUIC-Handle-partial-handshake-messages.patch deleted file mode 100644 index 9a6186590..000000000 --- a/openwrt/patch/openssl/quic/0006-QUIC-Handle-partial-handshake-messages.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 0c9c5b370c5d5d7d0adf8defacd68aa0455f2cbf Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 15 Aug 2019 13:26:32 -0400 -Subject: [PATCH 06/43] QUIC: Handle partial handshake messages - ---- - ssl/ssl_local.h | 1 + - ssl/ssl_quic.c | 28 ++++++++++++++++++++++------ - 2 files changed, 23 insertions(+), 6 deletions(-) - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1225,6 +1225,7 @@ typedef struct cert_pkey_st CERT_PKEY; - struct quic_data_st { - struct quic_data_st *next; - OSSL_ENCRYPTION_LEVEL level; -+ size_t offset; - size_t length; - }; - typedef struct quic_data_st QUIC_DATA; ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -114,15 +114,26 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - QUIC_DATA *qd; - const uint8_t *p = data + 1; - -+ /* Check for an incomplete block */ -+ qd = ssl->quic_input_data_tail; -+ if (qd != NULL) { -+ l = qd->length - qd->offset; -+ if (l != 0) { -+ /* we still need to copy `l` bytes into the last data block */ -+ if (l > len) -+ l = len; -+ memcpy((char*)(qd+1) + qd->offset, data, l); -+ qd->offset += l; -+ len -= l; -+ data += l; -+ continue; -+ } -+ } -+ - n2l3(p, l); - l += SSL3_HM_HEADER_LENGTH; - -- if (l > len) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_DATA_LENGTH); -- return 0; -- } -- -- qd = OPENSSL_malloc(sizeof(QUIC_DATA) + l); -+ qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l); - if (qd == NULL) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); - return 0; -@@ -131,6 +142,11 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - qd->next = NULL; - qd->length = l; - qd->level = level; -+ /* partial data received? */ -+ if (l > len) -+ l = len; -+ qd->offset = l; -+ - memcpy((void*)(qd + 1), data, l); - if (ssl->quic_input_data_tail != NULL) - ssl->quic_input_data_tail->next = qd; diff --git a/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch b/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch deleted file mode 100644 index 6200042f1..000000000 --- a/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch +++ /dev/null @@ -1,82 +0,0 @@ -From bfde078b732672f8668793722b6ba1209f78c6b3 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Mon, 26 Aug 2019 13:29:17 -0400 -Subject: [PATCH 07/43] QUIC: Fix quic_transport constructors/parsers - ---- - ssl/statem/extensions_clnt.c | 16 +++------------- - ssl/statem/extensions_srvr.c | 16 +++------------- - 2 files changed, 6 insertions(+), 26 deletions(-) - ---- a/ssl/statem/extensions_clnt.c -+++ b/ssl/statem/extensions_clnt.c -@@ -1208,10 +1208,8 @@ EXT_RETURN tls_construct_ctos_quic_trans - } - - if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) -- || !WPACKET_start_sub_packet_u16(pkt) -- || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -- s->ext.quic_transport_params_len) -- || !WPACKET_close(pkt)) { -+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -+ s->ext.quic_transport_params_len)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return EXT_RETURN_FAIL; - } -@@ -2033,19 +2031,11 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p - int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx) - { -- PACKET trans_param; -- -- if (!PACKET_as_length_prefixed_2(pkt, &trans_param) -- || PACKET_remaining(&trans_param) == 0) { -- SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); -- return 0; -- } -- - OPENSSL_free(s->ext.peer_quic_transport_params); - s->ext.peer_quic_transport_params = NULL; - s->ext.peer_quic_transport_params_len = 0; - -- if (!PACKET_memdup(&trans_param, -+ if (!PACKET_memdup(pkt, - &s->ext.peer_quic_transport_params, - &s->ext.peer_quic_transport_params_len)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); ---- a/ssl/statem/extensions_srvr.c -+++ b/ssl/statem/extensions_srvr.c -@@ -1254,19 +1254,11 @@ int tls_parse_ctos_post_handshake_auth(S - int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx) - { -- PACKET trans_param; -- -- if (!PACKET_as_length_prefixed_2(pkt, &trans_param) -- || PACKET_remaining(&trans_param) == 0) { -- SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_EXTENSION); -- return 0; -- } -- - OPENSSL_free(s->ext.peer_quic_transport_params); - s->ext.peer_quic_transport_params = NULL; - s->ext.peer_quic_transport_params_len = 0; - -- if (!PACKET_memdup(&trans_param, -+ if (!PACKET_memdup(pkt, - &s->ext.peer_quic_transport_params, - &s->ext.peer_quic_transport_params_len)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -@@ -1972,10 +1964,8 @@ EXT_RETURN tls_construct_stoc_quic_trans - } - - if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters) -- || !WPACKET_start_sub_packet_u16(pkt) -- || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -- s->ext.quic_transport_params_len) -- || !WPACKET_close(pkt)) { -+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -+ s->ext.quic_transport_params_len)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return EXT_RETURN_FAIL; - } diff --git a/openwrt/patch/openssl/quic/0008-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch b/openwrt/patch/openssl/quic/0008-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch deleted file mode 100644 index 4d3fabf58..000000000 --- a/openwrt/patch/openssl/quic/0008-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 2e492e056b68540c5ff222bd53ee4ebe2f4a0181 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 29 Aug 2019 11:53:41 -0400 -Subject: [PATCH 08/43] QUIC: Reset init state in - SSL_process_quic_post_handshake() - ---- - ssl/ssl_quic.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -265,16 +265,19 @@ int quic_set_encryption_secrets(SSL *ssl - - int SSL_process_quic_post_handshake(SSL *ssl) - { -+ int ret; -+ - if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) { - SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - - ossl_statem_set_in_init(ssl, 1); -+ ret = ssl->handshake_func(ssl); -+ ossl_statem_set_in_init(ssl, 0); - -- if (ssl->handshake_func(ssl) <= 0) -+ if (ret <= 0) - return 0; -- - return 1; - } - diff --git a/openwrt/patch/openssl/quic/0009-QUIC-Don-t-process-an-incomplete-message.patch b/openwrt/patch/openssl/quic/0009-QUIC-Don-t-process-an-incomplete-message.patch deleted file mode 100644 index 37bec9656..000000000 --- a/openwrt/patch/openssl/quic/0009-QUIC-Don-t-process-an-incomplete-message.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 059e2a654d4226a8419407cfeb8a8e15d48733c6 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 29 Aug 2019 12:03:48 -0400 -Subject: [PATCH 09/43] QUIC: Don't process an incomplete message - ---- - ssl/statem/statem_quic.c | 9 ++++----- - 1 file changed, 4 insertions(+), 5 deletions(-) - ---- a/ssl/statem/statem_quic.c -+++ b/ssl/statem/statem_quic.c -@@ -18,30 +18,29 @@ NON_EMPTY_TRANSLATION_UNIT - int quic_get_message(SSL *s, int *mt, size_t *len) - { - size_t l; -- QUIC_DATA *qd; -+ QUIC_DATA *qd = s->quic_input_data_head; - uint8_t *p; - -- if (s->quic_input_data_head == NULL) { -+ if (qd == NULL || (qd->length - qd->offset) != 0) { - s->rwstate = SSL_READING; - *len = 0; - return 0; - } - - /* This is where we check for the proper level, not when data is given */ -- if (s->quic_input_data_head->level != s->quic_read_level) { -+ if (qd->level != s->quic_read_level) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); - *len = 0; - return 0; - } - -- if (!BUF_MEM_grow_clean(s->init_buf, (int)s->quic_input_data_head->length)) { -+ if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); - *len = 0; - return 0; - } - - /* Copy buffered data */ -- qd = s->quic_input_data_head; - memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); - s->init_buf->length = qd->length; - s->quic_input_data_head = qd->next; diff --git a/openwrt/patch/openssl/quic/0010-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch b/openwrt/patch/openssl/quic/0010-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch deleted file mode 100644 index dc7d53c97..000000000 --- a/openwrt/patch/openssl/quic/0010-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 8ff2c79869c1ab3aa3f9c565197111809a482599 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 29 Aug 2019 20:21:58 -0400 -Subject: [PATCH 10/43] QUIC: Quick fix: s2c to c2s for early secret - ---- - ssl/ssl_quic.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -207,7 +207,7 @@ int quic_set_encryption_secrets(SSL *ssl - /* secrets from the POV of the client */ - switch (level) { - case ssl_encryption_early_data: -- s2c_secret = ssl->early_secret; -+ c2s_secret = ssl->early_secret; - break; - case ssl_encryption_handshake: - c2s_secret = ssl->client_hand_traffic_secret; diff --git a/openwrt/patch/openssl/quic/0011-QUIC-Add-client-early-traffic-secret-storage.patch b/openwrt/patch/openssl/quic/0011-QUIC-Add-client-early-traffic-secret-storage.patch deleted file mode 100644 index 6fefff0d3..000000000 --- a/openwrt/patch/openssl/quic/0011-QUIC-Add-client-early-traffic-secret-storage.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 9796392fbe8d7cb0540176de2ad602610f066b61 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 30 Aug 2019 09:09:42 -0400 -Subject: [PATCH 11/43] QUIC: Add client early traffic secret storage - ---- - ssl/ssl_local.h | 1 + - ssl/ssl_quic.c | 2 +- - ssl/tls13_enc.c | 2 ++ - 3 files changed, 4 insertions(+), 1 deletion(-) - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1493,6 +1493,7 @@ struct ssl_st { - unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE]; -+ unsigned char client_early_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char exporter_master_secret[EVP_MAX_MD_SIZE]; - unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE]; - EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -207,7 +207,7 @@ int quic_set_encryption_secrets(SSL *ssl - /* secrets from the POV of the client */ - switch (level) { - case ssl_encryption_early_data: -- c2s_secret = ssl->early_secret; -+ c2s_secret = ssl->client_early_traffic_secret; - break; - case ssl_encryption_handshake: - c2s_secret = ssl->client_hand_traffic_secret; ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -728,6 +728,8 @@ int tls13_change_cipher_state(SSL *s, in - memcpy(s->client_hand_traffic_secret, secret, hashlen); - else if (label == server_handshake_traffic) - memcpy(s->server_hand_traffic_secret, secret, hashlen); -+ else if (label == client_early_traffic) -+ memcpy(s->client_early_traffic_secret, secret, hashlen); - #endif - - if (!ssl_log_secret(s, log_label, secret, hashlen)) { diff --git a/openwrt/patch/openssl/quic/0012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch b/openwrt/patch/openssl/quic/0012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch deleted file mode 100644 index 271893b35..000000000 --- a/openwrt/patch/openssl/quic/0012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 41e5fc307ef92a747a5b81758185cca47307faf6 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 30 Aug 2019 09:15:31 -0400 -Subject: [PATCH 12/43] QUIC: Add OPENSSL_NO_QUIC wrapper - ---- - ssl/ssl_local.h | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1491,9 +1491,11 @@ struct ssl_st { - unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE]; - unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE]; -+# ifndef OPENSSL_NO_QUIC - unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE]; - unsigned char client_early_traffic_secret[EVP_MAX_MD_SIZE]; -+# endif - unsigned char exporter_master_secret[EVP_MAX_MD_SIZE]; - unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE]; - EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ diff --git a/openwrt/patch/openssl/quic/0013-QUIC-Correctly-disable-middlebox-compat.patch b/openwrt/patch/openssl/quic/0013-QUIC-Correctly-disable-middlebox-compat.patch deleted file mode 100644 index be5aa0aca..000000000 --- a/openwrt/patch/openssl/quic/0013-QUIC-Correctly-disable-middlebox-compat.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 9103ae64bb8f2abc4d4f146293bd104b641209cc Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 30 Aug 2019 09:47:48 -0400 -Subject: [PATCH 13/43] QUIC: Correctly disable middlebox compat - ---- - ssl/ssl_quic.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -173,7 +173,7 @@ int SSL_CTX_set_quic_method(SSL_CTX *ctx - break; - } - ctx->quic_method = quic_method; -- ctx->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; -+ ctx->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; - return 1; - } - -@@ -189,7 +189,7 @@ int SSL_set_quic_method(SSL *ssl, const - break; - } - ssl->quic_method = quic_method; -- ssl->options &= SSL_OP_ENABLE_MIDDLEBOX_COMPAT; -+ ssl->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; - return 1; - } - diff --git a/openwrt/patch/openssl/quic/0014-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch b/openwrt/patch/openssl/quic/0014-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch deleted file mode 100644 index 6d57731a9..000000000 --- a/openwrt/patch/openssl/quic/0014-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch +++ /dev/null @@ -1,327 +0,0 @@ -From ad33923b6596437c1e63954decd6cf261bfa5dc7 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 30 Aug 2019 11:17:58 -0400 -Subject: [PATCH 14/43] QUIC: Move QUIC code out of tls13_change_cipher_state() - -Create quic_change_cipher_state() that does the minimal required -to generate the QUIC secrets. (e.g. encryption contexts are not -initialized). ---- - ssl/ssl_quic.c | 7 -- - ssl/tls13_enc.c | 217 ++++++++++++++++++++++++++++++------------------ - 2 files changed, 138 insertions(+), 86 deletions(-) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -199,7 +199,6 @@ int quic_set_encryption_secrets(SSL *ssl - uint8_t *s2c_secret = NULL; - size_t len; - const EVP_MD *md; -- static const unsigned char zeros[EVP_MAX_MD_SIZE]; - - if (!SSL_IS_QUIC(ssl)) - return 1; -@@ -240,12 +239,6 @@ int quic_set_encryption_secrets(SSL *ssl - return 0; - } - -- /* In some cases, we want to set the secret only when BOTH are non-zero */ -- if (c2s_secret != NULL && s2c_secret != NULL -- && !memcmp(c2s_secret, zeros, len) -- && !memcmp(s2c_secret, zeros, len)) -- return 1; -- - if (ssl->server) { - if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret, - s2c_secret, len)) { ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -400,27 +400,144 @@ static int derive_secret_key_and_iv(SSL - return 1; - } - --int tls13_change_cipher_state(SSL *s, int which) --{ - #ifdef CHARSET_EBCDIC -- static const unsigned char client_early_traffic[] = {0x63, 0x20, 0x65, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -- static const unsigned char client_handshake_traffic[] = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -- static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -- static const unsigned char server_handshake_traffic[] = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -- static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -- static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; -- static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; -- static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; -+static const unsigned char client_early_traffic[] = {0x63, 0x20, 0x65, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -+static const unsigned char client_handshake_traffic[] = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -+static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -+static const unsigned char server_handshake_traffic[] = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -+static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00}; -+static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; -+static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; -+static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20, /* master*/ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00}; - #else -- static const unsigned char client_early_traffic[] = "c e traffic"; -- static const unsigned char client_handshake_traffic[] = "c hs traffic"; -- static const unsigned char client_application_traffic[] = "c ap traffic"; -- static const unsigned char server_handshake_traffic[] = "s hs traffic"; -- static const unsigned char server_application_traffic[] = "s ap traffic"; -- static const unsigned char exporter_master_secret[] = "exp master"; -- static const unsigned char resumption_master_secret[] = "res master"; -- static const unsigned char early_exporter_master_secret[] = "e exp master"; -+static const unsigned char client_early_traffic[] = "c e traffic"; -+static const unsigned char client_handshake_traffic[] = "c hs traffic"; -+static const unsigned char client_application_traffic[] = "c ap traffic"; -+static const unsigned char server_handshake_traffic[] = "s hs traffic"; -+static const unsigned char server_application_traffic[] = "s ap traffic"; -+static const unsigned char exporter_master_secret[] = "exp master"; -+static const unsigned char resumption_master_secret[] = "res master"; -+static const unsigned char early_exporter_master_secret[] = "e exp master"; - #endif -+#ifndef OPENSSL_NO_QUIC -+static int quic_change_cipher_state(SSL *s, int which) -+{ -+ unsigned char hash[EVP_MAX_MD_SIZE]; -+ size_t hashlen = 0; -+ int hashleni; -+ int ret = 0; -+ const EVP_MD *md = NULL; -+ OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; -+ int is_handshake = ((which & SSL3_CC_HANDSHAKE) == SSL3_CC_HANDSHAKE); -+ int is_client_read = ((which & SSL3_CHANGE_CIPHER_CLIENT_READ) == SSL3_CHANGE_CIPHER_CLIENT_READ); -+ int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE); -+ int is_early = (which & SSL3_CC_EARLY); -+ -+ md = ssl_handshake_md(s); -+ if (!ssl3_digest_cached_records(s, 1) -+ || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) { -+ /* SSLfatal() already called */; -+ goto err; -+ } -+ -+ /* Ensure cast to size_t is safe */ -+ hashleni = EVP_MD_size(md); -+ if (!ossl_assert(hashleni >= 0)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); -+ goto err; -+ } -+ hashlen = (size_t)hashleni; -+ -+ if (is_handshake) -+ level = ssl_encryption_handshake; -+ else -+ level = ssl_encryption_application; -+ -+ if (is_client_read || is_server_write) { -+ if (is_handshake) { -+ level = ssl_encryption_handshake; -+ -+ if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic, -+ sizeof(client_handshake_traffic)-1, hash, hashlen, -+ s->client_hand_traffic_secret, hashlen, 1)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ if (!ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ -+ if (!tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, -+ sizeof(server_handshake_traffic)-1, hash, hashlen, -+ s->server_hand_traffic_secret, hashlen, 1)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ if (!ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ } else { -+ level = ssl_encryption_application; -+ -+ if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic, -+ sizeof(client_application_traffic)-1, hash, hashlen, -+ s->client_app_traffic_secret, hashlen, 1)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ if (!ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ -+ if (!tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, -+ sizeof(server_application_traffic)-1, hash, hashlen, -+ s->server_app_traffic_secret, hashlen, 1)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ if (!ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ } -+ if (s->server) -+ s->quic_write_level = level; -+ else -+ s->quic_read_level = level; -+ } else { -+ if (is_early) { -+ level = ssl_encryption_early_data; -+ -+ if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic, -+ sizeof(client_early_traffic)-1, hash, hashlen, -+ s->client_early_traffic_secret, hashlen, 1)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ if (!ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } -+ } -+ if (s->server) -+ s->quic_read_level = level; -+ else -+ s->quic_write_level = level; -+ } -+ -+ if (level != ssl_encryption_initial && !quic_set_encryption_secrets(s, level)) -+ goto err; -+ -+ ret = 1; -+ err: -+ return ret; -+} -+#endif /* OPENSSL_NO_QUIC */ -+int tls13_change_cipher_state(SSL *s, int which) -+{ - unsigned char *iv; - unsigned char key[EVP_MAX_KEY_LENGTH]; - unsigned char secret[EVP_MAX_MD_SIZE]; -@@ -440,8 +557,10 @@ int tls13_change_cipher_state(SSL *s, in - ktls_crypto_info_t crypto_info; - BIO *bio; - #endif -+ - #ifndef OPENSSL_NO_QUIC -- OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; -+ if (SSL_IS_QUIC(s)) -+ return quic_change_cipher_state(s, which); - #endif - - if (which & SSL3_CC_READ) { -@@ -488,9 +607,6 @@ int tls13_change_cipher_state(SSL *s, in - label = client_early_traffic; - labellen = sizeof(client_early_traffic) - 1; - log_label = CLIENT_EARLY_LABEL; --#ifndef OPENSSL_NO_QUIC -- level = ssl_encryption_early_data; --#endif - - handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata); - if (handlen <= 0) { -@@ -567,14 +683,6 @@ int tls13_change_cipher_state(SSL *s, in - /* SSLfatal() already called */ - goto err; - } --#ifndef OPENSSL_NO_QUIC -- if (SSL_IS_QUIC(s)) { -- if (s->server) -- s->quic_read_level = ssl_encryption_early_data; -- else -- s->quic_write_level = ssl_encryption_early_data; -- } --#endif - } else if (which & SSL3_CC_HANDSHAKE) { - insecret = s->handshake_secret; - finsecret = s->client_finished_secret; -@@ -582,15 +690,6 @@ int tls13_change_cipher_state(SSL *s, in - label = client_handshake_traffic; - labellen = sizeof(client_handshake_traffic) - 1; - log_label = CLIENT_HANDSHAKE_LABEL; --#ifndef OPENSSL_NO_QUIC -- if (SSL_IS_QUIC(s)) { -- level = ssl_encryption_handshake; -- if (s->server) -- s->quic_read_level = ssl_encryption_handshake; -- else -- s->quic_write_level = ssl_encryption_handshake; -- } --#endif - /* - * The handshake hash used for the server read/client write handshake - * traffic secret is the same as the hash for the server -@@ -613,15 +712,6 @@ int tls13_change_cipher_state(SSL *s, in - * previously saved value. - */ - hash = s->server_finished_hash; --#ifndef OPENSSL_NO_QUIC -- if (SSL_IS_QUIC(s)) { -- level = ssl_encryption_application; /* ??? */ -- if (s->server) -- s->quic_read_level = ssl_encryption_application; -- else -- s->quic_write_level = ssl_encryption_application; -- } --#endif - } - } else { - /* Early data never applies to client-read/server-write */ -@@ -632,29 +722,11 @@ int tls13_change_cipher_state(SSL *s, in - label = server_handshake_traffic; - labellen = sizeof(server_handshake_traffic) - 1; - log_label = SERVER_HANDSHAKE_LABEL; --#ifndef OPENSSL_NO_QUIC -- if (SSL_IS_QUIC(s)) { -- level = ssl_encryption_handshake; -- if (s->server) -- s->quic_write_level = ssl_encryption_handshake; -- else -- s->quic_read_level = ssl_encryption_handshake; -- } --#endif - } else { - insecret = s->master_secret; - label = server_application_traffic; - labellen = sizeof(server_application_traffic) - 1; - log_label = SERVER_APPLICATION_LABEL; --#ifndef OPENSSL_NO_QUIC -- if (SSL_IS_QUIC(s)) { -- level = ssl_encryption_application; -- if (s->server) -- s->quic_write_level = ssl_encryption_application; -- else -- s->quic_read_level = ssl_encryption_application; -- } --#endif - } - } - -@@ -723,14 +795,6 @@ int tls13_change_cipher_state(SSL *s, in - } - } else if (label == client_application_traffic) - memcpy(s->client_app_traffic_secret, secret, hashlen); --#ifndef OPENSSL_NO_QUIC -- else if (label == client_handshake_traffic) -- memcpy(s->client_hand_traffic_secret, secret, hashlen); -- else if (label == server_handshake_traffic) -- memcpy(s->server_hand_traffic_secret, secret, hashlen); -- else if (label == client_early_traffic) -- memcpy(s->client_early_traffic_secret, secret, hashlen); --#endif - - if (!ssl_log_secret(s, log_label, secret, hashlen)) { - /* SSLfatal() already called */ -@@ -791,11 +855,6 @@ skip_ktls: - # endif - #endif - --#ifndef OPENSSL_NO_QUIC -- if (!quic_set_encryption_secrets(s, level)) -- goto err; --#endif -- - ret = 1; - err: - if ((which & SSL3_CC_EARLY) != 0) { diff --git a/openwrt/patch/openssl/quic/0015-QUIC-Tweeks-to-quic_change_cipher_state.patch b/openwrt/patch/openssl/quic/0015-QUIC-Tweeks-to-quic_change_cipher_state.patch deleted file mode 100644 index f18795f52..000000000 --- a/openwrt/patch/openssl/quic/0015-QUIC-Tweeks-to-quic_change_cipher_state.patch +++ /dev/null @@ -1,121 +0,0 @@ -From f1f40a948479350a0d38a6bd5e932cf7b523f13e Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 30 Aug 2019 11:38:56 -0400 -Subject: [PATCH 15/43] QUIC: Tweeks to quic_change_cipher_state() - ---- - ssl/tls13_enc.c | 69 +++++++++++++++++-------------------------------- - 1 file changed, 24 insertions(+), 45 deletions(-) - ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -448,33 +448,18 @@ static int quic_change_cipher_state(SSL - } - hashlen = (size_t)hashleni; - -- if (is_handshake) -- level = ssl_encryption_handshake; -- else -- level = ssl_encryption_application; -- - if (is_client_read || is_server_write) { - if (is_handshake) { - level = ssl_encryption_handshake; - - if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic, - sizeof(client_handshake_traffic)-1, hash, hashlen, -- s->client_hand_traffic_secret, hashlen, 1)) { -- /* SSLfatal() already called */ -- goto err; -- } -- if (!ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen)) { -- /* SSLfatal() already called */ -- goto err; -- } -- -- if (!tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, -- sizeof(server_handshake_traffic)-1, hash, hashlen, -- s->server_hand_traffic_secret, hashlen, 1)) { -- /* SSLfatal() already called */ -- goto err; -- } -- if (!ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { -+ s->client_hand_traffic_secret, hashlen, 1) -+ || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen) -+ || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, -+ sizeof(server_handshake_traffic)-1, hash, hashlen, -+ s->server_hand_traffic_secret, hashlen, 1) -+ || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { - /* SSLfatal() already called */ - goto err; - } -@@ -483,26 +468,20 @@ static int quic_change_cipher_state(SSL - - if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic, - sizeof(client_application_traffic)-1, hash, hashlen, -- s->client_app_traffic_secret, hashlen, 1)) { -- /* SSLfatal() already called */ -- goto err; -- } -- if (!ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen)) { -- /* SSLfatal() already called */ -- goto err; -- } -- -- if (!tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, -- sizeof(server_application_traffic)-1, hash, hashlen, -- s->server_app_traffic_secret, hashlen, 1)) { -- /* SSLfatal() already called */ -- goto err; -- } -- if (!ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { -+ s->client_app_traffic_secret, hashlen, 1) -+ || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen) -+ || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, -+ sizeof(server_application_traffic)-1, hash, hashlen, -+ s->server_app_traffic_secret, hashlen, 1) -+ || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { - /* SSLfatal() already called */ - goto err; - } - } -+ if (!quic_set_encryption_secrets(s, level)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } - if (s->server) - s->quic_write_level = level; - else -@@ -513,24 +492,24 @@ static int quic_change_cipher_state(SSL - - if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic, - sizeof(client_early_traffic)-1, hash, hashlen, -- s->client_early_traffic_secret, hashlen, 1)) { -- /* SSLfatal() already called */ -- goto err; -- } -- if (!ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen)) { -+ s->client_early_traffic_secret, hashlen, 1) -+ || !ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen) -+ || !quic_set_encryption_secrets(s, level)) { - /* SSLfatal() already called */ - goto err; - } -+ } else if (is_handshake) { -+ level = ssl_encryption_handshake; -+ } else { -+ level = ssl_encryption_application; - } -+ - if (s->server) - s->quic_read_level = level; - else - s->quic_write_level = level; - } - -- if (level != ssl_encryption_initial && !quic_set_encryption_secrets(s, level)) -- goto err; -- - ret = 1; - err: - return ret; diff --git a/openwrt/patch/openssl/quic/0016-QUIC-Add-support-for-more-secrets.patch b/openwrt/patch/openssl/quic/0016-QUIC-Add-support-for-more-secrets.patch deleted file mode 100644 index fa5ad9c1c..000000000 --- a/openwrt/patch/openssl/quic/0016-QUIC-Add-support-for-more-secrets.patch +++ /dev/null @@ -1,39 +0,0 @@ -From fadf42665c7a7c3f57477391d121ad2ca8698164 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 24 Sep 2019 10:26:42 -0400 -Subject: [PATCH 16/43] QUIC: Add support for more secrets - ---- - ssl/tls13_enc.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -456,10 +456,14 @@ static int quic_change_cipher_state(SSL - sizeof(client_handshake_traffic)-1, hash, hashlen, - s->client_hand_traffic_secret, hashlen, 1) - || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen) -+ || !tls13_derive_finishedkey(s, md, s->client_hand_traffic_secret, -+ s->client_finished_secret, hashlen) - || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, - sizeof(server_handshake_traffic)-1, hash, hashlen, - s->server_hand_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen)) { -+ || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen) -+ || !tls13_derive_finishedkey(s, md, s->server_hand_traffic_secret, -+ s->server_finished_secret, hashlen)) { - /* SSLfatal() already called */ - goto err; - } -@@ -473,7 +477,10 @@ static int quic_change_cipher_state(SSL - || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, - sizeof(server_application_traffic)-1, hash, hashlen, - s->server_app_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { -+ || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen) -+ || !tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, -+ sizeof(resumption_master_secret)-1, hash, hashlen, -+ s->resumption_master_secret, hashlen, 1)) { - /* SSLfatal() already called */ - goto err; - } diff --git a/openwrt/patch/openssl/quic/0017-QUIC-Fix-resumption-secret.patch b/openwrt/patch/openssl/quic/0017-QUIC-Fix-resumption-secret.patch deleted file mode 100644 index f493bcdb6..000000000 --- a/openwrt/patch/openssl/quic/0017-QUIC-Fix-resumption-secret.patch +++ /dev/null @@ -1,49 +0,0 @@ -From a86dc6757fdd4129d08a46fc3604cdbad3c0be41 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 12 Nov 2019 13:52:35 -0500 -Subject: [PATCH 17/43] QUIC: Fix resumption secret - ---- - ssl/tls13_enc.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -477,10 +477,7 @@ static int quic_change_cipher_state(SSL - || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, - sizeof(server_application_traffic)-1, hash, hashlen, - s->server_app_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen) -- || !tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, -- sizeof(resumption_master_secret)-1, hash, hashlen, -- s->resumption_master_secret, hashlen, 1)) { -+ || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { - /* SSLfatal() already called */ - goto err; - } -@@ -494,6 +491,8 @@ static int quic_change_cipher_state(SSL - else - s->quic_read_level = level; - } else { -+ /* is_client_write || is_server_read */ -+ - if (is_early) { - level = ssl_encryption_early_data; - -@@ -509,6 +508,16 @@ static int quic_change_cipher_state(SSL - level = ssl_encryption_handshake; - } else { - level = ssl_encryption_application; -+ /* -+ * We also create the resumption master secret, but this time use the -+ * hash for the whole handshake including the Client Finished -+ */ -+ if (!tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, -+ sizeof(resumption_master_secret)-1, hash, hashlen, -+ s->resumption_master_secret, hashlen, 1)) { -+ /* SSLfatal() already called */ -+ goto err; -+ } - } - - if (s->server) diff --git a/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch b/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch deleted file mode 100644 index bb9370d8a..000000000 --- a/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 70a17b75867850760ebf90b899e53f31b3b7c256 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Wed, 13 Nov 2019 12:11:00 -0500 -Subject: [PATCH 18/43] QUIC: Handle EndOfEarlyData and MaxEarlyData - ---- - ssl/statem/extensions_clnt.c | 11 +++++++++++ - ssl/statem/extensions_srvr.c | 12 ++++++++++-- - ssl/statem/statem_clnt.c | 8 ++++++++ - ssl/statem/statem_srvr.c | 4 ++++ - 4 files changed, 33 insertions(+), 2 deletions(-) - ---- a/ssl/statem/extensions_clnt.c -+++ b/ssl/statem/extensions_clnt.c -@@ -1944,6 +1944,17 @@ int tls_parse_stoc_early_data(SSL *s, PA - return 0; - } - -+#ifndef OPENSSL_NO_QUIC -+ /* -+ * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION -+ * per draft-ietf-quic-tls-24 S4.5 -+ */ -+ if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { -+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); -+ return 0; -+ } -+#endif -+ - s->session->ext.max_early_data = max_early_data; - - return 1; ---- a/ssl/statem/extensions_srvr.c -+++ b/ssl/statem/extensions_srvr.c -@@ -1908,12 +1908,20 @@ EXT_RETURN tls_construct_stoc_early_data - size_t chainidx) - { - if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) { -- if (s->max_early_data == 0) -+ uint32_t max_early_data = s->max_early_data; -+ -+ if (max_early_data == 0) - return EXT_RETURN_NOT_SENT; - -+#ifndef OPENSSL_NO_QUIC -+ /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-24 S4.5 */ -+ if (s->quic_method != NULL) -+ max_early_data = 0xFFFFFFFF; -+#endif -+ - if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data) - || !WPACKET_start_sub_packet_u16(pkt) -- || !WPACKET_put_bytes_u32(pkt, s->max_early_data) -+ || !WPACKET_put_bytes_u32(pkt, max_early_data) - || !WPACKET_close(pkt)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return EXT_RETURN_FAIL; ---- a/ssl/statem/statem_clnt.c -+++ b/ssl/statem/statem_clnt.c -@@ -904,6 +904,14 @@ int ossl_statem_client_construct_message - break; - - case TLS_ST_CW_END_OF_EARLY_DATA: -+#ifndef OPENSSL_NO_QUIC -+ /* QUIC does not send EndOfEarlyData, draft-ietf-quic-tls-24 S8.3 */ -+ if (s->quic_method != NULL) { -+ *confunc = NULL; -+ *mt = SSL3_MT_DUMMY; -+ break; -+ } -+#endif - *confunc = tls_construct_end_of_early_data; - *mt = SSL3_MT_END_OF_EARLY_DATA; - break; ---- a/ssl/statem/statem_srvr.c -+++ b/ssl/statem/statem_srvr.c -@@ -76,6 +76,10 @@ static int ossl_statem_server13_read_tra - break; - } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { - if (mt == SSL3_MT_END_OF_EARLY_DATA) { -+#ifndef OPENSSL_NO_QUIC -+ if (s->quic_method != NULL) -+ return 0; -+#endif - st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA; - return 1; - } diff --git a/openwrt/patch/openssl/quic/0019-QUIC-Fall-through-for-0RTT.patch b/openwrt/patch/openssl/quic/0019-QUIC-Fall-through-for-0RTT.patch deleted file mode 100644 index bbe6a325d..000000000 --- a/openwrt/patch/openssl/quic/0019-QUIC-Fall-through-for-0RTT.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 40a5be75bb65d1fc4e40052e19ff54f0974397d9 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 7 Jan 2020 10:59:08 -0500 -Subject: [PATCH 19/43] QUIC: Fall-through for 0RTT - ---- - ssl/statem/statem_srvr.c | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - ---- a/ssl/statem/statem_srvr.c -+++ b/ssl/statem/statem_srvr.c -@@ -74,12 +74,9 @@ static int ossl_statem_server13_read_tra - return 1; - } - break; -- } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { -+ } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED -+ && !SSL_IS_QUIC(s)) { - if (mt == SSL3_MT_END_OF_EARLY_DATA) { --#ifndef OPENSSL_NO_QUIC -- if (s->quic_method != NULL) -- return 0; --#endif - st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA; - return 1; - } diff --git a/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch b/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch deleted file mode 100644 index 4be49613e..000000000 --- a/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch +++ /dev/null @@ -1,640 +0,0 @@ -From aa803e9855f49779e4226f358f085dc0fb1eb93e Mon Sep 17 00:00:00 2001 -From: Benjamin Kaduk -Date: Wed, 22 Apr 2020 09:12:36 -0700 -Subject: [PATCH 20/43] QUIC: Some cleanup for the main QUIC changes - -Try to reduce unneeded whitespace changes and wrap new code to 80 columns. -Reword documentation to attempt to improve clarity. -Add some more sanity checks and clarifying comments to the code. -Update referenced I-D versions. ---- - doc/man3/SSL_CTX_set_quic_method.pod | 43 +++++++------- - include/openssl/ssl.h.in | 4 +- - include/openssl/tls1.h | 2 +- - ssl/build.info | 7 ++- - ssl/ssl_ciph.c | 2 + - ssl/ssl_lib.c | 2 +- - ssl/ssl_local.h | 1 + - ssl/ssl_quic.c | 45 +++++++-------- - ssl/statem/extensions_clnt.c | 2 +- - ssl/statem/extensions_srvr.c | 2 +- - ssl/statem/statem.c | 2 +- - ssl/statem/statem_lib.c | 26 +++++---- - ssl/statem/statem_local.h | 2 + - ssl/statem/statem_quic.c | 22 ++++---- - ssl/tls13_enc.c | 84 +++++++++++++++++++--------- - test/sslapitest.c | 11 ++-- - util/libssl.num | 2 +- - 17 files changed, 155 insertions(+), 104 deletions(-) - ---- a/doc/man3/SSL_CTX_set_quic_method.pod -+++ b/doc/man3/SSL_CTX_set_quic_method.pod -@@ -63,22 +63,25 @@ SSL_quic_max_handshake_flight_len() retu - that may be received at the given encryption level. This function should be - used to limit buffering in the QUIC implementation. - --See https://tools.ietf.org/html/draft-ietf-quic-transport-16#section-4.4. -+See https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-4. - - SSL_quic_read_level() returns the current read encryption level. - - SSL_quic_write_level() returns the current write encryption level. - --SSL_provide_quic_data() provides data from QUIC at a particular encryption --level B. It is an error to call this function outside of the handshake --or with an encryption level other than the current read level. It returns one --on success and zero on error. -+SSL_provide_quic_data() is used to provide data from QUIC CRYPTO frames to the -+state machine, at a particular encryption level B. It is an error to -+call this function outside of the handshake or with an encryption level other -+than the current read level. The application must buffer and consolidate any -+frames with less than four bytes of content. It returns one on success and -+zero on error. - - SSL_process_quic_post_handshake() processes any data that QUIC has provided - after the handshake has completed. This includes NewSessionTicket messages - sent by the server. - --SSL_is_quic() indicates whether a connection uses QUIC. -+SSL_is_quic() indicates whether a connection uses QUIC. A given B -+or B can only be used with QUIC or TLS, but not both. - - =head1 NOTES - -@@ -89,11 +92,11 @@ functions allow a QUIC implementation to - described in draft-ietf-quic-tls. - - When configured for QUIC, SSL_do_handshake() will drive the handshake as --before, but it will not use the configured B. It will call functions on --B to configure secrets and send data. If data is needed from --the peer, it will return B. When received, the caller --should call SSL_provide_quic_data() and then SSL_do_handshake() to continue --the handshake. After the handshake is complete, the caller should call -+before, but it will not use the configured B. It will call functions from -+the configured B to configure secrets and send data. If data -+is needed from the peer, it will return B. When received, -+the caller should call SSL_provide_quic_data() and then SSL_do_handshake() to -+continue the handshake. After the handshake is complete, the caller should call - SSL_provide_quic_data() for any post-handshake data, followed by - SSL_process_quic_post_handshake() to process it. It is an error to call - SSL_read()/SSL_read_ex() and SSL_write()/SSL_write_ex() in QUIC. -@@ -105,7 +108,7 @@ pass the active write level to add_hands - can use SSL_quic_write_level() to query the active write level when - generating their own errors. - --See https://tools.ietf.org/html/draft-ietf-quic-tls-15#section-4.1 for more -+See https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-4.1 for more - details. - - To avoid DoS attacks, the QUIC implementation must limit the amount of data -@@ -113,11 +116,12 @@ being queued up. The implementation can - SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each - encryption level. - --draft-ietf-quic-tls defines a new TLS extension quic_transport_parameters -+draft-ietf-quic-tls defines a new TLS extension "quic_transport_parameters" - used by QUIC for each endpoint to unilaterally declare its supported --transport parameters. draft-ietf-quic-transport (section 7.4) defines the --contents of that extension (a TransportParameters struct) and describes how --to handle it and its semantic meaning. -+transport parameters. The contents of the extension are specified in -+https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-18 (as -+a sequence of tag/length/value parameters) along with the interpretation of the -+various parameters and the rules for their processing. - - OpenSSL handles this extension as an opaque byte string. The caller is - responsible for serializing and parsing it. -@@ -205,10 +209,11 @@ SSL_process_quic_post_handshake() - return 1 on success, and 0 on error. - - SSL_quic_read_level() and SSL_quic_write_level() return the current --encryption level as B (B). -+encryption level as an B -+(B). - --SSL_quic_max_handshake_flight_len() returns the maximum length of a flight --for a given encryption level. -+SSL_quic_max_handshake_flight_len() returns the maximum length in bytes of a -+flight for a given encryption level. - - SSL_is_quic() returns 1 if QUIC is being used, 0 if not. - ---- a/include/openssl/ssl.h.in -+++ b/include/openssl/ssl.h.in -@@ -2562,10 +2562,10 @@ __owur int SSL_process_quic_post_handsha - - __owur int SSL_is_quic(SSL *ssl); - --# endif -- - int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); - -+# endif -+ - # ifdef __cplusplus - } - # endif ---- a/include/openssl/tls1.h -+++ b/include/openssl/tls1.h -@@ -151,7 +151,7 @@ extern "C" { - /* Temporary extension type */ - # define TLSEXT_TYPE_renegotiate 0xff01 - --/* ExtensionType value from draft-ietf-quic-tls-13 */ -+/* ExtensionType value from draft-ietf-quic-tls-27 */ - # define TLSEXT_TYPE_quic_transport_parameters 0xffa5 - - # ifndef OPENSSL_NO_NEXTPROTONEG ---- a/ssl/build.info -+++ b/ssl/build.info -@@ -37,10 +37,11 @@ IF[{- !$disabled{'deprecated-3.0'} -}] - SHARED_SOURCE[../libssl]=s3_cbc.c - SOURCE[../libssl]=ssl_rsa_legacy.c - ENDIF -- --SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c -- - DEFINE[../libssl]=$AESDEF - -+IF[{- !$disabled{quic} -}] -+ SOURCE[../libssl]=ssl_quic.c statem/statem_quic.c -+ENDIF -+ - SOURCE[../providers/libcommon.a]=record/tls_pad.c - SOURCE[../providers/libdefault.a ../providers/libfips.a]=s3_cbc.c ---- a/ssl/ssl_ciph.c -+++ b/ssl/ssl_ciph.c -@@ -2241,6 +2241,7 @@ const char *OSSL_default_ciphersuites(vo - "TLS_AES_128_GCM_SHA256"; - } - -+#ifndef OPENSSL_NO_QUIC - int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c) - { - switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) { -@@ -2272,3 +2273,4 @@ int SSL_CIPHER_get_prf_nid(const SSL_CIP - } - return NID_undef; - } -+#endif ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -4281,7 +4281,7 @@ EVP_PKEY *SSL_CTX_get0_privatekey(const - - const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) - { -- if (s->session != NULL) -+ if ((s->session != NULL) && (s->session->cipher != NULL)) - return s->session->cipher; - return NULL; - } ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1227,6 +1227,7 @@ struct quic_data_st { - OSSL_ENCRYPTION_LEVEL level; - size_t offset; - size_t length; -+ /* char data[]; should be here but C90 VLAs not allowed here */ - }; - typedef struct quic_data_st QUIC_DATA; - int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -11,10 +11,6 @@ - #include "internal/cryptlib.h" - #include "internal/refcount.h" - --#ifdef OPENSSL_NO_QUIC --NON_EMPTY_TRANSLATION_UNIT --#else -- - int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params, - size_t params_len) - { -@@ -109,10 +105,10 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - return 0; - } - -- /* Split the QUIC messages up, if necessary */ -+ /* Split on handshake message boundaries, if necessary */ - while (len > 0) { - QUIC_DATA *qd; -- const uint8_t *p = data + 1; -+ const uint8_t *p; - - /* Check for an incomplete block */ - qd = ssl->quic_input_data_tail; -@@ -130,6 +126,12 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - } - } - -+ if (len < SSL3_HM_HEADER_LENGTH) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH); -+ return 0; -+ } -+ /* TLS Handshake message header has 1-byte type and 3-byte length */ -+ p = data + 1; - n2l3(p, l); - l += SSL3_HM_HEADER_LENGTH; - -@@ -163,15 +165,8 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - - int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method) - { -- switch (ctx->method->version) { -- case DTLS1_VERSION: -- case DTLS1_2_VERSION: -- case DTLS_ANY_VERSION: -- case DTLS1_BAD_VER: -+ if (ctx->method->version != TLS_ANY_VERSION) - return 0; -- default: -- break; -- } - ctx->quic_method = quic_method; - ctx->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; - return 1; -@@ -179,15 +174,8 @@ int SSL_CTX_set_quic_method(SSL_CTX *ctx - - int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method) - { -- switch (ssl->method->version) { -- case DTLS1_VERSION: -- case DTLS1_2_VERSION: -- case DTLS_ANY_VERSION: -- case DTLS1_BAD_VER: -+ if (ssl->method->version != TLS_ANY_VERSION) - return 0; -- default: -- break; -- } - ssl->quic_method = quic_method; - ssl->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT; - return 1; -@@ -225,6 +213,12 @@ int quic_set_encryption_secrets(SSL *ssl - /* May not have selected cipher, yet */ - const SSL_CIPHER *c = NULL; - -+ /* -+ * It probably doesn't make sense to use an (external) PSK session, -+ * but in theory some kinds of external session caches could be -+ * implemented using it, so allow psksession to be used as well as -+ * the regular session. -+ */ - if (ssl->session != NULL) - c = SSL_SESSION_get0_cipher(ssl->session); - else if (ssl->psksession != NULL) -@@ -265,6 +259,11 @@ int SSL_process_quic_post_handshake(SSL - return 0; - } - -+ /* -+ * This is always safe (we are sure to be at a record boundary) because -+ * SSL_read()/SSL_write() are never used for QUIC connections -- the -+ * application data is handled at the QUIC layer instead. -+ */ - ossl_statem_set_in_init(ssl, 1); - ret = ssl->handshake_func(ssl); - ossl_statem_set_in_init(ssl, 0); -@@ -278,5 +277,3 @@ int SSL_is_quic(SSL* ssl) - { - return SSL_IS_QUIC(ssl); - } -- --#endif ---- a/ssl/statem/extensions_clnt.c -+++ b/ssl/statem/extensions_clnt.c -@@ -1947,7 +1947,7 @@ int tls_parse_stoc_early_data(SSL *s, PA - #ifndef OPENSSL_NO_QUIC - /* - * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION -- * per draft-ietf-quic-tls-24 S4.5 -+ * per draft-ietf-quic-tls-27 S4.5 - */ - if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); ---- a/ssl/statem/extensions_srvr.c -+++ b/ssl/statem/extensions_srvr.c -@@ -1914,7 +1914,7 @@ EXT_RETURN tls_construct_stoc_early_data - return EXT_RETURN_NOT_SENT; - - #ifndef OPENSSL_NO_QUIC -- /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-24 S4.5 */ -+ /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ - if (s->quic_method != NULL) - max_early_data = 0xFFFFFFFF; - #endif ---- a/ssl/statem/statem.c -+++ b/ssl/statem/statem.c -@@ -585,6 +585,7 @@ static SUB_STATE_RETURN read_state_machi - ret = dtls_get_message(s, &mt); - #ifndef OPENSSL_NO_QUIC - } else if (SSL_IS_QUIC(s)) { -+ /* QUIC behaves like DTLS -- all in one go. */ - ret = quic_get_message(s, &mt, &len); - #endif - } else { -@@ -929,7 +930,6 @@ int statem_flush(SSL *s) - #ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { - if (!s->quic_method->flush_flight(s)) { -- /* NOTE: BIO_flush() does not generate an error */ - SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR); - return 0; - } ---- a/ssl/statem/statem_lib.c -+++ b/ssl/statem/statem_lib.c -@@ -44,17 +44,24 @@ int ssl3_do_write(SSL *s, int type) - { - int ret; - size_t written = 0; -+ - #ifndef OPENSSL_NO_QUIC -- if (SSL_IS_QUIC(s) && type == SSL3_RT_HANDSHAKE) { -- ret = s->quic_method->add_handshake_data(s, s->quic_write_level, -- (const uint8_t*)&s->init_buf->data[s->init_off], -- s->init_num); -- if (!ret) { -- ret = -1; -- /* QUIC can't sent anything out sice the above failed */ -- SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); -+ if (SSL_IS_QUIC(s)) { -+ if (type == SSL3_RT_HANDSHAKE) { -+ ret = s->quic_method->add_handshake_data(s, s->quic_write_level, -+ (const uint8_t*)&s->init_buf->data[s->init_off], -+ s->init_num); -+ if (!ret) { -+ ret = -1; -+ /* QUIC can't sent anything out sice the above failed */ -+ SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); -+ } else { -+ written = s->init_num; -+ } - } else { -- written = s->init_num; -+ /* QUIC doesn't use ChangeCipherSpec */ -+ ret = -1; -+ SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - } - } else - #endif -@@ -1187,7 +1194,6 @@ int tls_get_message_header(SSL *s, int * - - do { - while (s->init_num < SSL3_HM_HEADER_LENGTH) { -- /* QUIC: either create a special ssl_read_bytes... or if/else this */ - i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, - &p[s->init_num], - SSL3_HM_HEADER_LENGTH - s->init_num, ---- a/ssl/statem/statem_local.h -+++ b/ssl/statem/statem_local.h -@@ -104,7 +104,9 @@ __owur int tls_get_message_header(SSL *s - __owur int tls_get_message_body(SSL *s, size_t *len); - __owur int dtls_get_message(SSL *s, int *mt); - __owur int dtls_get_message_body(SSL *s, size_t *len); -+#ifndef OPENSSL_NO_QUIC - __owur int quic_get_message(SSL *s, int *mt, size_t *len); -+#endif - - /* Message construction and processing functions */ - __owur int tls_process_initial_server_flight(SSL *s); ---- a/ssl/statem/statem_quic.c -+++ b/ssl/statem/statem_quic.c -@@ -11,10 +11,6 @@ - #include "statem_local.h" - #include "internal/cryptlib.h" - --#ifdef OPENSSL_NO_QUIC --NON_EMPTY_TRANSLATION_UNIT --#else -- - int quic_get_message(SSL *s, int *mt, size_t *len) - { - size_t l; -@@ -23,20 +19,26 @@ int quic_get_message(SSL *s, int *mt, si - - if (qd == NULL || (qd->length - qd->offset) != 0) { - s->rwstate = SSL_READING; -- *len = 0; -+ *mt = *len = 0; -+ return 0; -+ } -+ -+ if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH); -+ *mt = *len = 0; - return 0; - } - - /* This is where we check for the proper level, not when data is given */ - if (qd->level != s->quic_read_level) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); -- *len = 0; -+ *mt = *len = 0; - return 0; - } - - if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); -- *len = 0; -+ *mt = *len = 0; - return 0; - } - -@@ -79,8 +81,8 @@ int quic_get_message(SSL *s, int *mt, si - */ - #define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2) - /* KeyUpdate and NewSessionTicket do not need to be added */ -- if (!SSL_IS_TLS13(s) || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET -- && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) { -+ if (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET -+ && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE) { - if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO - || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE - || memcmp(hrrrandom, -@@ -101,5 +103,3 @@ int quic_get_message(SSL *s, int *mt, si - - return 1; - } -- --#endif ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -419,6 +419,7 @@ static const unsigned char exporter_mast - static const unsigned char resumption_master_secret[] = "res master"; - static const unsigned char early_exporter_master_secret[] = "e exp master"; - #endif -+ - #ifndef OPENSSL_NO_QUIC - static int quic_change_cipher_state(SSL *s, int which) - { -@@ -427,7 +428,7 @@ static int quic_change_cipher_state(SSL - int hashleni; - int ret = 0; - const EVP_MD *md = NULL; -- OSSL_ENCRYPTION_LEVEL level = ssl_encryption_initial; -+ OSSL_ENCRYPTION_LEVEL level; - int is_handshake = ((which & SSL3_CC_HANDSHAKE) == SSL3_CC_HANDSHAKE); - int is_client_read = ((which & SSL3_CHANGE_CIPHER_CLIENT_READ) == SSL3_CHANGE_CIPHER_CLIENT_READ); - int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE); -@@ -450,34 +451,62 @@ static int quic_change_cipher_state(SSL - - if (is_client_read || is_server_write) { - if (is_handshake) { -+ /* -+ * This looks a bit weird, since the condition is basically "the -+ * server is writing" but we set both the server *and* client -+ * handshake traffic keys here. That's because there's only a fixed -+ * number of change-cipher-state events in the TLS 1.3 handshake, -+ * and in particular there's not an event in between when the server -+ * writes encrypted handshake messages and when the client writes -+ * encrypted handshake messages, so we generate both here. -+ */ - level = ssl_encryption_handshake; - -- if (!tls13_hkdf_expand(s, md, s->handshake_secret, client_handshake_traffic, -- sizeof(client_handshake_traffic)-1, hash, hashlen, -- s->client_hand_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, s->client_hand_traffic_secret, hashlen) -- || !tls13_derive_finishedkey(s, md, s->client_hand_traffic_secret, -+ if (!tls13_hkdf_expand(s, md, s->handshake_secret, -+ client_handshake_traffic, -+ sizeof(client_handshake_traffic)-1, hash, -+ hashlen, s->client_hand_traffic_secret, -+ hashlen, 1) -+ || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL, -+ s->client_hand_traffic_secret, hashlen) -+ || !tls13_derive_finishedkey(s, md, -+ s->client_hand_traffic_secret, - s->client_finished_secret, hashlen) -- || !tls13_hkdf_expand(s, md, s->handshake_secret, server_handshake_traffic, -- sizeof(server_handshake_traffic)-1, hash, hashlen, -- s->server_hand_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, s->server_hand_traffic_secret, hashlen) -- || !tls13_derive_finishedkey(s, md, s->server_hand_traffic_secret, -- s->server_finished_secret, hashlen)) { -+ || !tls13_hkdf_expand(s, md, s->handshake_secret, -+ server_handshake_traffic, -+ sizeof(server_handshake_traffic)-1, hash, -+ hashlen, s->server_hand_traffic_secret, -+ hashlen, 1) -+ || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL, -+ s->server_hand_traffic_secret, hashlen) -+ || !tls13_derive_finishedkey(s, md, -+ s->server_hand_traffic_secret, -+ s->server_finished_secret, -+ hashlen)) { - /* SSLfatal() already called */ - goto err; - } - } else { -+ /* -+ * As above, we generate both sets of application traffic keys at -+ * the same time. -+ */ - level = ssl_encryption_application; - -- if (!tls13_hkdf_expand(s, md, s->master_secret, client_application_traffic, -- sizeof(client_application_traffic)-1, hash, hashlen, -- s->client_app_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, s->client_app_traffic_secret, hashlen) -- || !tls13_hkdf_expand(s, md, s->master_secret, server_application_traffic, -- sizeof(server_application_traffic)-1, hash, hashlen, -+ if (!tls13_hkdf_expand(s, md, s->master_secret, -+ client_application_traffic, -+ sizeof(client_application_traffic)-1, hash, -+ hashlen, s->client_app_traffic_secret, -+ hashlen, 1) -+ || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL, -+ s->client_app_traffic_secret, hashlen) -+ || !tls13_hkdf_expand(s, md, s->master_secret, -+ server_application_traffic, -+ sizeof(server_application_traffic)-1, -+ hash, hashlen, - s->server_app_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, s->server_app_traffic_secret, hashlen)) { -+ || !ssl_log_secret(s, SERVER_APPLICATION_LABEL, -+ s->server_app_traffic_secret, hashlen)) { - /* SSLfatal() already called */ - goto err; - } -@@ -497,9 +526,11 @@ static int quic_change_cipher_state(SSL - level = ssl_encryption_early_data; - - if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic, -- sizeof(client_early_traffic)-1, hash, hashlen, -- s->client_early_traffic_secret, hashlen, 1) -- || !ssl_log_secret(s, CLIENT_EARLY_LABEL, s->client_early_traffic_secret, hashlen) -+ sizeof(client_early_traffic)-1, hash, -+ hashlen, s->client_early_traffic_secret, -+ hashlen, 1) -+ || !ssl_log_secret(s, CLIENT_EARLY_LABEL, -+ s->client_early_traffic_secret, hashlen) - || !quic_set_encryption_secrets(s, level)) { - /* SSLfatal() already called */ - goto err; -@@ -512,9 +543,11 @@ static int quic_change_cipher_state(SSL - * We also create the resumption master secret, but this time use the - * hash for the whole handshake including the Client Finished - */ -- if (!tls13_hkdf_expand(s, md, s->master_secret, resumption_master_secret, -- sizeof(resumption_master_secret)-1, hash, hashlen, -- s->resumption_master_secret, hashlen, 1)) { -+ if (!tls13_hkdf_expand(s, md, s->master_secret, -+ resumption_master_secret, -+ sizeof(resumption_master_secret)-1, hash, -+ hashlen, s->resumption_master_secret, -+ hashlen, 1)) { - /* SSLfatal() already called */ - goto err; - } -@@ -531,6 +564,7 @@ static int quic_change_cipher_state(SSL - return ret; - } - #endif /* OPENSSL_NO_QUIC */ -+ - int tls13_change_cipher_state(SSL *s, int which) - { - unsigned char *iv; ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10766,9 +10766,11 @@ static int test_multi_resume(int idx) - } - - #ifndef OPENSSL_NO_QUIC --static int test_quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, -+static int test_quic_set_encryption_secrets(SSL *ssl, -+ OSSL_ENCRYPTION_LEVEL level, - const uint8_t *read_secret, -- const uint8_t *write_secret, size_t secret_len) -+ const uint8_t *write_secret, -+ size_t secret_len) - { - test_printf_stderr("quic_set_encryption_secrets() %s, lvl=%d, len=%zd\n", - ssl->server ? "server" : "client", level, secret_len); -@@ -10780,11 +10782,12 @@ static int test_quic_add_handshake_data( - { - SSL *peer = (SSL*)SSL_get_app_data(ssl); - -- test_printf_stderr("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", -- ssl->server ? "server" : "client", level, (int)*data, len); -+ TEST_info("quic_add_handshake_data() %s, lvl=%d, *data=0x%02X, len=%zd\n", -+ ssl->server ? "server" : "client", level, (int)*data, len); - if (!TEST_ptr(peer)) - return 0; - -+ /* We're called with what is locally written; this gives it to the peer */ - if (!TEST_true(SSL_provide_quic_data(peer, level, data, len))) { - ERR_print_errors_fp(stderr); - return 0; ---- a/util/libssl.num -+++ b/util/libssl.num -@@ -522,7 +522,7 @@ SSL_CTX_set0_tmp_dh_pkey - SSL_group_to_name 523 3_0_0 EXIST::FUNCTION: - SSL_quic_read_level 20000 3_0_0 EXIST::FUNCTION:QUIC - SSL_set_quic_transport_params 20001 3_0_0 EXIST::FUNCTION:QUIC --SSL_CIPHER_get_prf_nid 20002 3_0_0 EXIST::FUNCTION: -+SSL_CIPHER_get_prf_nid 20002 3_0_0 EXIST::FUNCTION:QUIC - SSL_is_quic 20003 3_0_0 EXIST::FUNCTION:QUIC - SSL_get_peer_quic_transport_params 20004 3_0_0 EXIST::FUNCTION:QUIC - SSL_quic_write_level 20005 3_0_0 EXIST::FUNCTION:QUIC diff --git a/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch b/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch deleted file mode 100644 index 931608807..000000000 --- a/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0749642cb0df330f91388a2fe72dc9b2824b7da7 Mon Sep 17 00:00:00 2001 -From: Benjamin Kaduk -Date: Mon, 11 May 2020 13:13:01 -0700 -Subject: [PATCH 21/43] QUIC: Prevent KeyUpdate for QUIC - -QUIC does not use the TLS KeyUpdate message/mechanism, and indeed -it is an error to generate or receive such a message. Add the -necessary checks (noting that the check for receipt should be -redundant since SSL_provide_quic_data() is the only way to provide -input to the TLS layer for a QUIC connection). ---- - ssl/ssl_quic.c | 6 ++++++ - ssl/statem/statem_lib.c | 14 ++++++++++++++ - 2 files changed, 20 insertions(+) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -92,6 +92,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - const uint8_t *data, size_t len) - { - size_t l; -+ uint8_t mt; - - if (!SSL_IS_QUIC(ssl)) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -@@ -131,9 +132,14 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - return 0; - } - /* TLS Handshake message header has 1-byte type and 3-byte length */ -+ mt = *data; - p = data + 1; - n2l3(p, l); - l += SSL3_HM_HEADER_LENGTH; -+ if (mt == SSL3_MT_KEY_UPDATE) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE); -+ return 0; -+ } - - qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l); - if (qd == NULL) { ---- a/ssl/statem/statem_lib.c -+++ b/ssl/statem/statem_lib.c -@@ -666,6 +666,13 @@ int tls_construct_finished(SSL *s, WPACK - - int tls_construct_key_update(SSL *s, WPACKET *pkt) - { -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_is_quic(s)) { -+ /* TLS KeyUpdate is not used for QUIC, so this is an error. */ -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+#endif - if (!WPACKET_put_bytes_u8(pkt, s->key_update)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); - return 0; -@@ -688,6 +695,13 @@ MSG_PROCESS_RETURN tls_process_key_updat - return MSG_PROCESS_ERROR; - } - -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_is_quic(s)) { -+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); -+ return MSG_PROCESS_ERROR; -+ } -+#endif -+ - if (!PACKET_get_1(pkt, &updatetype) - || PACKET_remaining(pkt) != 0) { - SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_KEY_UPDATE); diff --git a/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch b/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch deleted file mode 100644 index 8d252fca0..000000000 --- a/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0d6350e28e3b684ce10693dc6921f46441a0da21 Mon Sep 17 00:00:00 2001 -From: Benjamin Kaduk -Date: Mon, 11 May 2020 13:26:07 -0700 -Subject: [PATCH 22/43] QUIC: Test KeyUpdate rejection - -For now, just test that we don't generate any, since we don't really -expose the mechanics for encrypting one and the QUIC API is not -integrated into the TLSProxy setup. ---- - test/sslapitest.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10890,6 +10890,17 @@ static int test_quic_api(void) - || !TEST_true(SSL_process_quic_post_handshake(clientssl))) - goto end; - -+ /* Dummy handshake call should succeed */ -+ if (!TEST_true(SSL_do_handshake(clientssl))) -+ goto end; -+ /* Test that we (correctly) fail to send KeyUpdate */ -+ if (!TEST_true(SSL_key_update(clientssl, SSL_KEY_UPDATE_NOT_REQUESTED)) -+ || !TEST_int_le(SSL_do_handshake(clientssl), 0)) -+ goto end; -+ if (!TEST_true(SSL_key_update(serverssl, SSL_KEY_UPDATE_NOT_REQUESTED)) -+ || !TEST_int_le(SSL_do_handshake(serverssl), 0)) -+ goto end; -+ - testresult = 1; - - end: diff --git a/openwrt/patch/openssl/quic/0023-QUIC-Buffer-all-provided-quic-data.patch b/openwrt/patch/openssl/quic/0023-QUIC-Buffer-all-provided-quic-data.patch deleted file mode 100644 index e1d061e3f..000000000 --- a/openwrt/patch/openssl/quic/0023-QUIC-Buffer-all-provided-quic-data.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 7b72427c6d4694085c8b140eaa741126e04466a4 Mon Sep 17 00:00:00 2001 -From: Benjamin Kaduk -Date: Mon, 31 Aug 2020 12:27:33 -0700 -Subject: [PATCH 23/43] QUIC: Buffer all provided quic data - -Make all data supplied via SSL_provide_quic_data() pass through an -internal buffer, so that we can handle data supplied with arbitrary -framing and only parse complete TLS records onto the list of QUIC_DATA -managed by quic_input_data_head/quic_input_data_tail. - -This lets us remove the concept of "incomplete" QUIC_DATA structures, -and the 'offset' field needed to support them. - -However, we've already moved the provided data onto the buffer by -the time we can check for KeyUpdate messages, so defer that check -to quic_get_message() (where it is adjacent to the preexisting -ChangeCipherSpec check). - -To avoid extra memory copies, we also make the QUIC_DATA structures -just store offsets into the consolidated buffer instead of having copies -of the TLS handshake messages themselves. ---- - ssl/ssl_lib.c | 1 + - ssl/ssl_local.h | 5 +-- - ssl/ssl_quic.c | 75 +++++++++++++++++++--------------------- - ssl/statem/statem_quic.c | 11 ++++-- - 4 files changed, 49 insertions(+), 43 deletions(-) - ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -1260,6 +1260,7 @@ void SSL_free(SSL *s) - #ifndef OPENSSL_NO_QUIC - OPENSSL_free(s->ext.quic_transport_params); - OPENSSL_free(s->ext.peer_quic_transport_params); -+ BUF_MEM_free(s->quic_buf); - while (s->quic_input_data_head != NULL) { - QUIC_DATA *qd; - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1225,9 +1225,8 @@ typedef struct cert_pkey_st CERT_PKEY; - struct quic_data_st { - struct quic_data_st *next; - OSSL_ENCRYPTION_LEVEL level; -- size_t offset; -+ size_t start; /* offset into quic_buf->data */ - size_t length; -- /* char data[]; should be here but C90 VLAs not allowed here */ - }; - typedef struct quic_data_st QUIC_DATA; - int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level); -@@ -1721,8 +1720,10 @@ struct ssl_st { - #ifndef OPENSSL_NO_QUIC - OSSL_ENCRYPTION_LEVEL quic_read_level; - OSSL_ENCRYPTION_LEVEL quic_write_level; -+ BUF_MEM *quic_buf; /* buffer incoming handshake messages */ - QUIC_DATA *quic_input_data_head; - QUIC_DATA *quic_input_data_tail; -+ size_t quic_next_record_start; - const SSL_QUIC_METHOD *quic_method; - #endif - /* ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -91,8 +91,7 @@ OSSL_ENCRYPTION_LEVEL SSL_quic_write_lev - int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level, - const uint8_t *data, size_t len) - { -- size_t l; -- uint8_t mt; -+ size_t l, offset; - - if (!SSL_IS_QUIC(ssl)) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -@@ -106,42 +105,46 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - return 0; - } - -- /* Split on handshake message boundaries, if necessary */ -- while (len > 0) { -- QUIC_DATA *qd; -- const uint8_t *p; -- -- /* Check for an incomplete block */ -- qd = ssl->quic_input_data_tail; -- if (qd != NULL) { -- l = qd->length - qd->offset; -- if (l != 0) { -- /* we still need to copy `l` bytes into the last data block */ -- if (l > len) -- l = len; -- memcpy((char*)(qd+1) + qd->offset, data, l); -- qd->offset += l; -- len -= l; -- data += l; -- continue; -- } -+ if (ssl->quic_buf == NULL) { -+ BUF_MEM *buf; -+ if ((buf = BUF_MEM_new()) == NULL) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ return 0; - } -- -- if (len < SSL3_HM_HEADER_LENGTH) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_BAD_LENGTH); -+ if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ BUF_MEM_free(buf); - return 0; - } -+ ssl->quic_buf = buf; -+ /* We preallocated storage, but there's still no *data*. */ -+ ssl->quic_buf->length = 0; -+ buf = NULL; -+ } -+ -+ offset = ssl->quic_buf->length; -+ if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ memcpy(ssl->quic_buf->data + offset, data, len); -+ -+ /* Split on handshake message boundaries */ -+ while (ssl->quic_buf->length > ssl->quic_next_record_start -+ + SSL3_HM_HEADER_LENGTH) { -+ QUIC_DATA *qd; -+ const uint8_t *p; -+ - /* TLS Handshake message header has 1-byte type and 3-byte length */ -- mt = *data; -- p = data + 1; -+ p = (const uint8_t *)ssl->quic_buf->data -+ + ssl->quic_next_record_start + 1; - n2l3(p, l); - l += SSL3_HM_HEADER_LENGTH; -- if (mt == SSL3_MT_KEY_UPDATE) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_UNEXPECTED_MESSAGE); -- return 0; -- } -+ /* Don't allocate a QUIC_DATA if we don't have a full record */ -+ if (l > ssl->quic_buf->length - ssl->quic_next_record_start) -+ break; - -- qd = OPENSSL_zalloc(sizeof(QUIC_DATA) + l); -+ qd = OPENSSL_zalloc(sizeof(*qd)); - if (qd == NULL) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); - return 0; -@@ -149,21 +152,15 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - - qd->next = NULL; - qd->length = l; -+ qd->start = ssl->quic_next_record_start; - qd->level = level; -- /* partial data received? */ -- if (l > len) -- l = len; -- qd->offset = l; - -- memcpy((void*)(qd + 1), data, l); - if (ssl->quic_input_data_tail != NULL) - ssl->quic_input_data_tail->next = qd; - else - ssl->quic_input_data_head = qd; - ssl->quic_input_data_tail = qd; -- -- data += l; -- len -= l; -+ ssl->quic_next_record_start += l; - } - - return 1; ---- a/ssl/statem/statem_quic.c -+++ b/ssl/statem/statem_quic.c -@@ -17,7 +17,7 @@ int quic_get_message(SSL *s, int *mt, si - QUIC_DATA *qd = s->quic_input_data_head; - uint8_t *p; - -- if (qd == NULL || (qd->length - qd->offset) != 0) { -+ if (qd == NULL) { - s->rwstate = SSL_READING; - *mt = *len = 0; - return 0; -@@ -43,7 +43,7 @@ int quic_get_message(SSL *s, int *mt, si - } - - /* Copy buffered data */ -- memcpy(s->init_buf->data, (void*)(qd + 1), qd->length); -+ memcpy(s->init_buf->data, s->quic_buf->data + qd->start, qd->length); - s->init_buf->length = qd->length; - s->quic_input_data_head = qd->next; - if (s->quic_input_data_head == NULL) -@@ -62,6 +62,13 @@ int quic_get_message(SSL *s, int *mt, si - *len = 0; - return 0; - } -+ /* No KeyUpdate in QUIC */ -+ if (*mt == SSL3_MT_KEY_UPDATE) { -+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); -+ *len = 0; -+ return 0; -+ } -+ - - /* - * If receiving Finished, record MAC of prior handshake messages for diff --git a/openwrt/patch/openssl/quic/0024-QUIC-Enforce-consistent-encryption-level-for-handsha.patch b/openwrt/patch/openssl/quic/0024-QUIC-Enforce-consistent-encryption-level-for-handsha.patch deleted file mode 100644 index 77bd445d9..000000000 --- a/openwrt/patch/openssl/quic/0024-QUIC-Enforce-consistent-encryption-level-for-handsha.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 6e4c15e6bd52743d79956d3d149c70e021f47d11 Mon Sep 17 00:00:00 2001 -From: Benjamin Kaduk -Date: Tue, 1 Sep 2020 15:10:41 -0700 -Subject: [PATCH 24/43] QUIC: Enforce consistent encryption level for handshake - messages - -The QUIC-TLS spec requires that TLS handshake messages do not cross -encryption level boundaries, but we were not previously enforcing this. ---- - ssl/ssl_local.h | 1 + - ssl/ssl_quic.c | 12 +++++++++++- - 2 files changed, 12 insertions(+), 1 deletion(-) - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -1720,6 +1720,7 @@ struct ssl_st { - #ifndef OPENSSL_NO_QUIC - OSSL_ENCRYPTION_LEVEL quic_read_level; - OSSL_ENCRYPTION_LEVEL quic_write_level; -+ OSSL_ENCRYPTION_LEVEL quic_latest_level_received; - BUF_MEM *quic_buf; /* buffer incoming handshake messages */ - QUIC_DATA *quic_input_data_head; - QUIC_DATA *quic_input_data_tail; ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -100,7 +100,8 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - - /* Level can be different than the current read, but not less */ - if (level < ssl->quic_read_level -- || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)) { -+ || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level) -+ || level < ssl->quic_latest_level_received) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); - return 0; - } -@@ -122,6 +123,15 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - buf = NULL; - } - -+ /* A TLS message must not cross an encryption level boundary */ -+ if (ssl->quic_buf->length != ssl->quic_next_record_start -+ && level != ssl->quic_latest_level_received) { -+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, -+ SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); -+ return 0; -+ } -+ ssl->quic_latest_level_received = level; -+ - offset = ssl->quic_buf->length; - if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) { - SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); diff --git a/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch b/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch deleted file mode 100644 index 952e835b2..000000000 --- a/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch +++ /dev/null @@ -1,634 +0,0 @@ -From 7fdd78ad2b87cfa7d8cbbff7a4b673824c5bc6cd Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Sat, 12 Dec 2020 17:27:46 +0900 -Subject: [PATCH 25/43] QUIC: add v1 quic_transport_parameters - ---- - crypto/err/openssl.txt | 2 + - doc/man3/SSL_CTX_set_quic_method.pod | 25 +++++- - include/openssl/ssl.h.in | 13 ++++ - include/openssl/sslerr.h | 1 + - include/openssl/tls1.h | 3 +- - ssl/ssl_err.c | 2 + - ssl/ssl_lib.c | 1 + - ssl/ssl_local.h | 11 +++ - ssl/ssl_quic.c | 41 +++++++++- - ssl/statem/extensions.c | 39 ++++++++++ - ssl/statem/extensions_clnt.c | 44 ++++++++++- - ssl/statem/extensions_srvr.c | 46 ++++++++++- - ssl/statem/statem_local.h | 17 +++++ - test/sslapitest.c | 110 +++++++++++++++++++++------ - util/libssl.num | 4 + - 15 files changed, 322 insertions(+), 37 deletions(-) - ---- a/crypto/err/openssl.txt -+++ b/crypto/err/openssl.txt -@@ -1391,6 +1391,8 @@ SSL_R_MISSING_ECDSA_SIGNING_CERT:381:mis - SSL_R_MISSING_FATAL:256:missing fatal - SSL_R_MISSING_PARAMETERS:290:missing parameters - SSL_R_MISSING_PSK_KEX_MODES_EXTENSION:310:missing psk kex modes extension -+SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION:801:\ -+ missing quic transport parameters extension - SSL_R_MISSING_RSA_CERTIFICATE:168:missing rsa certificate - SSL_R_MISSING_RSA_ENCRYPTING_CERT:169:missing rsa encrypting cert - SSL_R_MISSING_RSA_SIGNING_CERT:170:missing rsa signing cert ---- a/doc/man3/SSL_CTX_set_quic_method.pod -+++ b/doc/man3/SSL_CTX_set_quic_method.pod -@@ -13,7 +13,11 @@ SSL_quic_read_level, - SSL_quic_write_level, - SSL_provide_quic_data, - SSL_process_quic_post_handshake, --SSL_is_quic -+SSL_is_quic, -+SSL_get_peer_quic_transport_version, -+SSL_get_quic_transport_version, -+SSL_set_quic_transport_version, -+SSL_set_quic_use_legacy_codepoint - - QUIC support - - =head1 SYNOPSIS -@@ -39,6 +43,11 @@ SSL_is_quic - int SSL_process_quic_post_handshake(SSL *ssl); - int SSL_is_quic(SSL *ssl); - -+ void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); -+ void SSL_set_quic_transport_version(SSL *ssl, int version); -+ int SSL_get_quic_transport_version(const SSL *ssl); -+ int SSL_get_peer_quic_transport_version(const SSL *ssl); -+ - =head1 DESCRIPTION - - SSL_CTX_set_quic_method() and SSL_set_quic_method() configures the QUIC methods. -@@ -83,6 +92,20 @@ sent by the server. - SSL_is_quic() indicates whether a connection uses QUIC. A given B - or B can only be used with QUIC or TLS, but not both. - -+SSL_set_quic_use_legacy_codepoint() specifies the legacy extension codepoint -+in manner compatible with some versions of BoringSSL. -+ -+SSL_set_quic_transport_version() specifies the quic transport version that -+allows for backwards and forwards compatibility. If set to 0 (default) the -+server will use the highest version the client sent. If set to 0 (default) -+the client will send both extensions. -+ -+SSL_get_quic_transport_version() returns the value set by -+SSL_set_quic_transport_version(). -+ -+SSL_get_peer_quic_transport_version() returns the version the that was -+negotiated. -+ - =head1 NOTES - - These APIs are implementations of BoringSSL's QUIC APIs. ---- a/include/openssl/ssl.h.in -+++ b/include/openssl/ssl.h.in -@@ -2562,6 +2562,19 @@ __owur int SSL_process_quic_post_handsha - - __owur int SSL_is_quic(SSL *ssl); - -+/* BoringSSL API */ -+__owur void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); -+ -+/* -+ * Set an explicit value that you want to use -+ * If 0 (default) the server will use the highest extenstion the client sent -+ * If 0 (default) the client will send both extensions -+ */ -+void SSL_set_quic_transport_version(SSL *ssl, int version); -+__owur int SSL_get_quic_transport_version(const SSL *ssl); -+/* Returns the negotiated version, or -1 on error */ -+__owur int SSL_get_peer_quic_transport_version(const SSL *ssl); -+ - int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); - - # endif ---- a/include/openssl/sslerr.h -+++ b/include/openssl/sslerr.h -@@ -162,6 +162,7 @@ - # define SSL_R_MISSING_FATAL 256 - # define SSL_R_MISSING_PARAMETERS 290 - # define SSL_R_MISSING_PSK_KEX_MODES_EXTENSION 310 -+# define SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION 801 - # define SSL_R_MISSING_RSA_CERTIFICATE 168 - # define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169 - # define SSL_R_MISSING_RSA_SIGNING_CERT 170 ---- a/include/openssl/tls1.h -+++ b/include/openssl/tls1.h -@@ -152,7 +152,8 @@ extern "C" { - # define TLSEXT_TYPE_renegotiate 0xff01 - - /* ExtensionType value from draft-ietf-quic-tls-27 */ --# define TLSEXT_TYPE_quic_transport_parameters 0xffa5 -+# define TLSEXT_TYPE_quic_transport_parameters_draft 0xffa5 -+# define TLSEXT_TYPE_quic_transport_parameters 0x0039 - - # ifndef OPENSSL_NO_NEXTPROTONEG - /* This is not an IANA defined extension number */ ---- a/ssl/ssl_err.c -+++ b/ssl/ssl_err.c -@@ -242,6 +242,8 @@ static const ERR_STRING_DATA SSL_str_rea - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PARAMETERS), "missing parameters"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION), - "missing psk kex modes extension"}, -+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION), -+ "missing quic transport parameters extension"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE), - "missing rsa certificate"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT), ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -1259,6 +1259,7 @@ void SSL_free(SSL *s) - - #ifndef OPENSSL_NO_QUIC - OPENSSL_free(s->ext.quic_transport_params); -+ OPENSSL_free(s->ext.peer_quic_transport_params_draft); - OPENSSL_free(s->ext.peer_quic_transport_params); - BUF_MEM_free(s->quic_buf); - while (s->quic_input_data_head != NULL) { ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -773,6 +773,7 @@ typedef enum tlsext_index_en { - TLSEXT_IDX_cryptopro_bug, - TLSEXT_IDX_early_data, - TLSEXT_IDX_certificate_authorities, -+ TLSEXT_IDX_quic_transport_params_draft, - TLSEXT_IDX_quic_transport_params, - TLSEXT_IDX_padding, - TLSEXT_IDX_psk, -@@ -1712,6 +1713,8 @@ struct ssl_st { - #ifndef OPENSSL_NO_QUIC - uint8_t *quic_transport_params; - size_t quic_transport_params_len; -+ uint8_t *peer_quic_transport_params_draft; -+ size_t peer_quic_transport_params_draft_len; - uint8_t *peer_quic_transport_params; - size_t peer_quic_transport_params_len; - #endif -@@ -1722,6 +1725,14 @@ struct ssl_st { - OSSL_ENCRYPTION_LEVEL quic_write_level; - OSSL_ENCRYPTION_LEVEL quic_latest_level_received; - BUF_MEM *quic_buf; /* buffer incoming handshake messages */ -+ /* -+ * defaults to 0, but can be set to: -+ * - TLSEXT_TYPE_quic_transport_parameters_draft -+ * - TLSEXT_TYPE_quic_transport_parameters -+ * Client: if 0, send both -+ * Server: if 0, use same version as client sent -+ */ -+ int quic_transport_version; - QUIC_DATA *quic_input_data_head; - QUIC_DATA *quic_input_data_tail; - size_t quic_next_record_start; ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -35,8 +35,45 @@ void SSL_get_peer_quic_transport_params( - const uint8_t **out_params, - size_t *out_params_len) - { -- *out_params = ssl->ext.peer_quic_transport_params; -- *out_params_len = ssl->ext.peer_quic_transport_params_len; -+ if (ssl->ext.peer_quic_transport_params_len) { -+ *out_params = ssl->ext.peer_quic_transport_params; -+ *out_params_len = ssl->ext.peer_quic_transport_params_len; -+ } else { -+ *out_params = ssl->ext.peer_quic_transport_params_draft; -+ *out_params_len = ssl->ext.peer_quic_transport_params_draft_len; -+ } -+} -+ -+/* Returns the negotiated version, or -1 on error */ -+int SSL_get_peer_quic_transport_version(const SSL *ssl) -+{ -+ if (ssl->ext.peer_quic_transport_params_len != 0 -+ && ssl->ext.peer_quic_transport_params_draft_len != 0) -+ return -1; -+ if (ssl->ext.peer_quic_transport_params_len != 0) -+ return TLSEXT_TYPE_quic_transport_parameters; -+ if (ssl->ext.peer_quic_transport_params_draft_len != 0) -+ return TLSEXT_TYPE_quic_transport_parameters_draft; -+ -+ return -1; -+} -+ -+void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy) -+{ -+ if (use_legacy) -+ ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters_draft; -+ else -+ ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters; -+} -+ -+void SSL_set_quic_transport_version(SSL *ssl, int version) -+{ -+ ssl->quic_transport_version = version; -+} -+ -+int SSL_get_quic_transport_version(const SSL *ssl) -+{ -+ return ssl->quic_transport_version; - } - - size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level) ---- a/ssl/statem/extensions.c -+++ b/ssl/statem/extensions.c -@@ -61,6 +61,7 @@ static int init_post_handshake_auth(SSL - static int final_psk(SSL *s, unsigned int context, int sent); - #ifndef OPENSSL_NO_QUIC - static int init_quic_transport_params(SSL *s, unsigned int context); -+static int final_quic_transport_params_draft(SSL *s, unsigned int context, int sent); - static int final_quic_transport_params(SSL *s, unsigned int context, int sent); - #endif - -@@ -376,6 +377,15 @@ static const EXTENSION_DEFINITION ext_de - }, - #ifndef OPENSSL_NO_QUIC - { -+ TLSEXT_TYPE_quic_transport_parameters_draft, -+ SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS -+ | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, -+ init_quic_transport_params, -+ tls_parse_ctos_quic_transport_params_draft, tls_parse_stoc_quic_transport_params_draft, -+ tls_construct_stoc_quic_transport_params_draft, tls_construct_ctos_quic_transport_params_draft, -+ final_quic_transport_params_draft, -+ }, -+ { - TLSEXT_TYPE_quic_transport_parameters, - SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS - | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY, -@@ -1746,8 +1756,37 @@ static int init_quic_transport_params(SS - return 1; - } - -+static int final_quic_transport_params_draft(SSL *s, unsigned int context, -+ int sent) -+{ -+ return 1; -+} -+ - static int final_quic_transport_params(SSL *s, unsigned int context, int sent) - { -+ /* called after final_quic_transport_params_draft */ -+ if (SSL_IS_QUIC(s)) { -+ if (s->ext.peer_quic_transport_params_len == 0 -+ && s->ext.peer_quic_transport_params_draft_len == 0) { -+ SSLfatal(s, SSL_AD_MISSING_EXTENSION, -+ SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION); -+ return 0; -+ } -+ /* if we got both, discard the one we can't use */ -+ if (s->ext.peer_quic_transport_params_len != 0 -+ && s->ext.peer_quic_transport_params_draft_len != 0) { -+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft) { -+ OPENSSL_free(s->ext.peer_quic_transport_params); -+ s->ext.peer_quic_transport_params = NULL; -+ s->ext.peer_quic_transport_params_len = 0; -+ } else { -+ OPENSSL_free(s->ext.peer_quic_transport_params_draft); -+ s->ext.peer_quic_transport_params_draft = NULL; -+ s->ext.peer_quic_transport_params_draft_len = 0; -+ } -+ } -+ } -+ - return 1; - } - #endif ---- a/ssl/statem/extensions_clnt.c -+++ b/ssl/statem/extensions_clnt.c -@@ -1197,13 +1197,33 @@ EXT_RETURN tls_construct_ctos_post_hands - } - - #ifndef OPENSSL_NO_QUIC --/* SAME AS tls_construct_stoc_quic_transport_params() */ -+EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx) -+{ -+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters -+ || s->ext.quic_transport_params == NULL -+ || s->ext.quic_transport_params_len == 0) { -+ return EXT_RETURN_NOT_SENT; -+ } -+ -+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft) -+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -+ s->ext.quic_transport_params_len)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return EXT_RETURN_FAIL; -+ } -+ -+ return EXT_RETURN_SENT; -+} -+ - EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, - unsigned int context, X509 *x, - size_t chainidx) - { -- if (s->ext.quic_transport_params == NULL -- || s->ext.quic_transport_params_len == 0) { -+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft -+ || s->ext.quic_transport_params == NULL -+ || s->ext.quic_transport_params_len == 0) { - return EXT_RETURN_NOT_SENT; - } - -@@ -2038,7 +2058,23 @@ int tls_parse_stoc_psk(SSL *s, PACKET *p - return 1; - } - #ifndef OPENSSL_NO_QUIC --/* SAME AS tls_parse_ctos_quic_transport_params() */ -+int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx) -+{ -+ OPENSSL_free(s->ext.peer_quic_transport_params_draft); -+ s->ext.peer_quic_transport_params_draft = NULL; -+ s->ext.peer_quic_transport_params_draft_len = 0; -+ -+ if (!PACKET_memdup(pkt, -+ &s->ext.peer_quic_transport_params_draft, -+ &s->ext.peer_quic_transport_params_draft_len)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ return 1; -+} -+ - int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx) - { ---- a/ssl/statem/extensions_srvr.c -+++ b/ssl/statem/extensions_srvr.c -@@ -1250,7 +1250,22 @@ int tls_parse_ctos_post_handshake_auth(S - } - - #ifndef OPENSSL_NO_QUIC --/* SAME AS tls_parse_stoc_quic_transport_params() */ -+int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt, unsigned int context, -+ X509 *x, size_t chainidx) -+{ -+ OPENSSL_free(s->ext.peer_quic_transport_params_draft); -+ s->ext.peer_quic_transport_params_draft = NULL; -+ s->ext.peer_quic_transport_params_draft_len = 0; -+ -+ if (!PACKET_memdup(pkt, -+ &s->ext.peer_quic_transport_params_draft, -+ &s->ext.peer_quic_transport_params_draft_len)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } -+ return 1; -+} -+ - int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx) - { -@@ -1961,13 +1976,36 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s - } - - #ifndef OPENSSL_NO_QUIC --/* SAME AS tls_construct_ctos_quic_transport_params() */ -+EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt, -+ unsigned int context, -+ X509 *x, -+ size_t chainidx) -+{ -+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters -+ || s->ext.peer_quic_transport_params_draft_len == 0 -+ || s->ext.quic_transport_params == NULL -+ || s->ext.quic_transport_params_len == 0) { -+ return EXT_RETURN_NOT_SENT; -+ } -+ -+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft) -+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params, -+ s->ext.quic_transport_params_len)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return EXT_RETURN_FAIL; -+ } -+ -+ return EXT_RETURN_SENT; -+} -+ - EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, - unsigned int context, X509 *x, - size_t chainidx) - { -- if (s->ext.quic_transport_params == NULL -- || s->ext.quic_transport_params_len == 0) { -+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft -+ || s->ext.peer_quic_transport_params_len == 0 -+ || s->ext.quic_transport_params == NULL -+ || s->ext.quic_transport_params_len == 0) { - return EXT_RETURN_NOT_SENT; - } - ---- a/ssl/statem/statem_local.h -+++ b/ssl/statem/statem_local.h -@@ -255,6 +255,10 @@ int tls_parse_ctos_psk(SSL *s, PACKET *p - int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); - #ifndef OPENSSL_NO_QUIC -+int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx); -+ - int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); - #endif -@@ -319,6 +323,11 @@ EXT_RETURN tls_construct_stoc_cryptopro_ - EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); - #ifndef OPENSSL_NO_QUIC -+EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt, -+ unsigned int context, -+ X509 *x, -+ size_t chainidx); -+ - EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt, - unsigned int context, X509 *x, - size_t chainidx); -@@ -393,6 +402,10 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s - EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); - #ifndef OPENSSL_NO_QUIC -+EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx); -+ - EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt, - unsigned int context, X509 *x, - size_t chainidx); -@@ -441,6 +454,10 @@ int tls_parse_stoc_cookie(SSL *s, PACKET - int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, - size_t chainidx); - #ifndef OPENSSL_NO_QUIC -+int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt, -+ unsigned int context, X509 *x, -+ size_t chainidx); -+ - int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context, - X509 *x, size_t chainidx); - #endif ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10816,7 +10816,13 @@ static SSL_QUIC_METHOD quic_method = { - test_quic_send_alert, - }; - --static int test_quic_api(void) -+static int test_quic_api_set_versions(SSL *ssl, int ver) -+{ -+ SSL_set_quic_transport_version(ssl, ver); -+ return 1; -+} -+ -+static int test_quic_api_version(int clnt, int srvr) - { - SSL_CTX *cctx = NULL, *sctx = NULL; - SSL *clientssl = NULL, *serverssl = NULL; -@@ -10827,29 +10833,7 @@ static int test_quic_api(void) - const uint8_t *peer_str; - size_t peer_str_len; - -- /* Clean up logging space */ -- memset(client_log_buffer, 0, sizeof(client_log_buffer)); -- memset(server_log_buffer, 0, sizeof(server_log_buffer)); -- client_log_buffer_index = 0; -- server_log_buffer_index = 0; -- error_writing_log = 0; -- -- -- if (!TEST_ptr(sctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method())) -- || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) -- || !TEST_ptr(sctx->quic_method) -- || !TEST_ptr(serverssl = SSL_new(sctx)) -- || !TEST_true(SSL_IS_QUIC(serverssl)) -- || !TEST_true(SSL_set_quic_method(serverssl, NULL)) -- || !TEST_false(SSL_IS_QUIC(serverssl)) -- || !TEST_true(SSL_set_quic_method(serverssl, &quic_method)) -- || !TEST_true(SSL_IS_QUIC(serverssl))) -- goto end; -- -- SSL_CTX_free(sctx); -- sctx = NULL; -- SSL_free(serverssl); -- serverssl = NULL; -+ TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); - - if (!TEST_true(create_ssl_ctx_pair(libctx, - TLS_server_method(), -@@ -10868,6 +10852,8 @@ static int test_quic_api(void) - sizeof(client_str))) - || !TEST_true(SSL_set_app_data(serverssl, clientssl)) - || !TEST_true(SSL_set_app_data(clientssl, serverssl)) -+ || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) -+ || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) - || !TEST_true(create_ssl_connection(serverssl, clientssl, - SSL_ERROR_NONE)) - || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) -@@ -10901,11 +10887,85 @@ static int test_quic_api(void) - || !TEST_int_le(SSL_do_handshake(serverssl), 0)) - goto end; - -+ TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); -+ if (srvr == 0 && clnt == 0) -+ srvr = clnt = TLSEXT_TYPE_quic_transport_parameters; -+ else if (srvr == 0) -+ srvr = clnt; -+ else if (clnt == 0) -+ clnt = srvr; -+ TEST_info("expected clnt=0x%X, srvr=0x%X\n", clnt, srvr); -+ if (!TEST_int_eq(SSL_get_peer_quic_transport_version(serverssl), clnt)) -+ goto end; -+ if (!TEST_int_eq(SSL_get_peer_quic_transport_version(clientssl), srvr)) -+ goto end; -+ - testresult = 1; - - end: - return testresult; - } -+ -+static int test_quic_api(int tst) -+{ -+ SSL_CTX *sctx = NULL; -+ SSL *serverssl = NULL; -+ int testresult = 0; -+ static int clnt_params[] = { 0, -+ TLSEXT_TYPE_quic_transport_parameters_draft, -+ TLSEXT_TYPE_quic_transport_parameters, -+ 0, -+ TLSEXT_TYPE_quic_transport_parameters_draft, -+ TLSEXT_TYPE_quic_transport_parameters, -+ 0, -+ TLSEXT_TYPE_quic_transport_parameters_draft, -+ TLSEXT_TYPE_quic_transport_parameters }; -+ static int srvr_params[] = { 0, -+ 0, -+ 0, -+ TLSEXT_TYPE_quic_transport_parameters_draft, -+ TLSEXT_TYPE_quic_transport_parameters_draft, -+ TLSEXT_TYPE_quic_transport_parameters_draft, -+ TLSEXT_TYPE_quic_transport_parameters, -+ TLSEXT_TYPE_quic_transport_parameters, -+ TLSEXT_TYPE_quic_transport_parameters }; -+ static int results[] = { 1, 1, 1, 1, 1, 0, 1, 0, 1 }; -+ -+ /* Failure cases: -+ * test 6/[5] clnt = parameters, srvr = draft -+ * test 8/[7] clnt = draft, srvr = parameters -+ */ -+ -+ /* Clean up logging space */ -+ memset(client_log_buffer, 0, sizeof(client_log_buffer)); -+ memset(server_log_buffer, 0, sizeof(server_log_buffer)); -+ client_log_buffer_index = 0; -+ server_log_buffer_index = 0; -+ error_writing_log = 0; -+ -+ if (!TEST_ptr(sctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method())) -+ || !TEST_true(SSL_CTX_set_quic_method(sctx, &quic_method)) -+ || !TEST_ptr(sctx->quic_method) -+ || !TEST_ptr(serverssl = SSL_new(sctx)) -+ || !TEST_true(SSL_IS_QUIC(serverssl)) -+ || !TEST_true(SSL_set_quic_method(serverssl, NULL)) -+ || !TEST_false(SSL_IS_QUIC(serverssl)) -+ || !TEST_true(SSL_set_quic_method(serverssl, &quic_method)) -+ || !TEST_true(SSL_IS_QUIC(serverssl))) -+ goto end; -+ -+ if (!TEST_int_eq(test_quic_api_version(clnt_params[tst], srvr_params[tst]), results[tst])) -+ goto end; -+ -+ testresult = 1; -+ -+end: -+ SSL_CTX_free(sctx); -+ sctx = NULL; -+ SSL_free(serverssl); -+ serverssl = NULL; -+ return testresult; -+} - #endif /* OPENSSL_NO_QUIC */ - - static struct next_proto_st { -@@ -11626,7 +11686,7 @@ int setup_tests(void) - ADD_ALL_TESTS(test_alpn, 4); - ADD_ALL_TESTS(test_no_renegotiation, 2); - #ifndef OPENSSL_NO_QUIC -- ADD_TEST(test_quic_api); -+ ADD_ALL_TESTS(test_quic_api, 9); - #endif - return 1; - ---- a/util/libssl.num -+++ b/util/libssl.num -@@ -531,3 +531,7 @@ SSL_set_quic_method - SSL_quic_max_handshake_flight_len 20008 3_0_0 EXIST::FUNCTION:QUIC - SSL_process_quic_post_handshake 20009 3_0_0 EXIST::FUNCTION:QUIC - SSL_provide_quic_data 20010 3_0_0 EXIST::FUNCTION:QUIC -+SSL_set_quic_use_legacy_codepoint 20011 3_0_0 EXIST::FUNCTION:QUIC -+SSL_set_quic_transport_version 20012 3_0_0 EXIST::FUNCTION:QUIC -+SSL_get_peer_quic_transport_version 20013 3_0_0 EXIST::FUNCTION:QUIC -+SSL_get_quic_transport_version 20014 3_0_0 EXIST::FUNCTION:QUIC diff --git a/openwrt/patch/openssl/quic/0026-QUIC-return-success-when-no-post-handshake-data.patch b/openwrt/patch/openssl/quic/0026-QUIC-return-success-when-no-post-handshake-data.patch deleted file mode 100644 index 93a703fd0..000000000 --- a/openwrt/patch/openssl/quic/0026-QUIC-return-success-when-no-post-handshake-data.patch +++ /dev/null @@ -1,22 +0,0 @@ -From a68e084550b8863d3f6b809ddfb26cb4c3e2307e Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 5 Jan 2021 13:50:21 -0500 -Subject: [PATCH 26/43] QUIC: return success when no post-handshake data - ---- - ssl/ssl_quic.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -309,6 +309,10 @@ int SSL_process_quic_post_handshake(SSL - return 0; - } - -+ /* if there is no data, return success as BoringSSL */ -+ if (ssl->quic_input_data_head == NULL) -+ return 1; -+ - /* - * This is always safe (we are sure to be at a record boundary) because - * SSL_read()/SSL_write() are never used for QUIC connections -- the diff --git a/openwrt/patch/openssl/quic/0027-QUIC-__owur-makes-no-sense-for-void-return-values.patch b/openwrt/patch/openssl/quic/0027-QUIC-__owur-makes-no-sense-for-void-return-values.patch deleted file mode 100644 index 026188497..000000000 --- a/openwrt/patch/openssl/quic/0027-QUIC-__owur-makes-no-sense-for-void-return-values.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 244d4b0ebd3ab4102f3e1892623bb96adcdef150 Mon Sep 17 00:00:00 2001 -From: Benjamin Kaduk -Date: Fri, 15 Jan 2021 15:04:00 -0800 -Subject: [PATCH 27/43] QUIC: __owur makes no sense for void return values - ---- - include/openssl/ssl.h.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/include/openssl/ssl.h.in -+++ b/include/openssl/ssl.h.in -@@ -2563,7 +2563,7 @@ __owur int SSL_process_quic_post_handsha - __owur int SSL_is_quic(SSL *ssl); - - /* BoringSSL API */ --__owur void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); -+void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy); - - /* - * Set an explicit value that you want to use diff --git a/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch b/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch deleted file mode 100644 index 4a922741b..000000000 --- a/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 86793f1d5a316687aea683127d7d5a3a09b0c692 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 19 Feb 2021 10:12:15 -0500 -Subject: [PATCH 28/43] QUIC: remove SSL_R_BAD_DATA_LENGTH (unused) - ---- - crypto/err/openssl.txt | 1 - - include/openssl/sslerr.h | 1 - - ssl/ssl_err.c | 1 - - 3 files changed, 3 deletions(-) - ---- a/crypto/err/openssl.txt -+++ b/crypto/err/openssl.txt -@@ -1253,7 +1253,6 @@ SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_ - SSL_R_BAD_CHANGE_CIPHER_SPEC:103:bad change cipher spec - SSL_R_BAD_CIPHER:186:bad cipher - SSL_R_BAD_DATA:390:bad data --SSL_R_BAD_DATA_LENGTH:802:bad data length - SSL_R_BAD_DATA_RETURNED_BY_CALLBACK:106:bad data returned by callback - SSL_R_BAD_DECOMPRESSION:107:bad decompression - SSL_R_BAD_DH_VALUE:102:bad dh value ---- a/include/openssl/sslerr.h -+++ b/include/openssl/sslerr.h -@@ -28,7 +28,6 @@ - # define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 - # define SSL_R_BAD_CIPHER 186 - # define SSL_R_BAD_DATA 390 --# define SSL_R_BAD_DATA_LENGTH 802 - # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 - # define SSL_R_BAD_DECOMPRESSION 107 - # define SSL_R_BAD_DH_VALUE 102 ---- a/ssl/ssl_err.c -+++ b/ssl/ssl_err.c -@@ -27,7 +27,6 @@ static const ERR_STRING_DATA SSL_str_rea - "bad change cipher spec"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"}, -- {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_LENGTH), "bad data length"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), - "bad data returned by callback"}, - {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"}, diff --git a/openwrt/patch/openssl/quic/0029-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch b/openwrt/patch/openssl/quic/0029-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch deleted file mode 100644 index 00bd8f850..000000000 --- a/openwrt/patch/openssl/quic/0029-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch +++ /dev/null @@ -1,152 +0,0 @@ -From e662060166f881e94d14702c1fda2b4fbdeeb041 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Wed, 3 Mar 2021 17:43:46 -0500 -Subject: [PATCH 29/43] QUIC: SSLerr() -> ERR_raise(ERR_LIB_SSL) - ---- - ssl/s3_msg.c | 2 +- - ssl/ssl_lib.c | 6 +++--- - ssl/ssl_quic.c | 17 ++++++++--------- - ssl/statem/statem.c | 2 +- - ssl/statem/statem_lib.c | 4 ++-- - 5 files changed, 15 insertions(+), 16 deletions(-) - ---- a/ssl/s3_msg.c -+++ b/ssl/s3_msg.c -@@ -85,7 +85,7 @@ int ssl3_dispatch_alert(SSL *s) - if (SSL_IS_QUIC(s)) { - if (!s->quic_method->send_alert(s, s->quic_write_level, - s->s3.send_alert[1])) { -- SSLerr(SSL_F_SSL3_DISPATCH_ALERT, ERR_R_INTERNAL_ERROR); -+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - i = 1; ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -1872,7 +1872,7 @@ int ssl_read_internal(SSL *s, void *buf, - { - #ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { -- SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return -1; - } - #endif -@@ -2009,7 +2009,7 @@ static int ssl_peek_internal(SSL *s, voi - { - #ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { -- SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return -1; - } - #endif -@@ -2075,7 +2075,7 @@ int ssl_write_internal(SSL *s, const voi - { - #ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { -- SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return -1; - } - #endif ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -131,7 +131,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - size_t l, offset; - - if (!SSL_IS_QUIC(ssl)) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - -@@ -139,18 +139,18 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - if (level < ssl->quic_read_level - || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level) - || level < ssl->quic_latest_level_received) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); -+ ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); - return 0; - } - - if (ssl->quic_buf == NULL) { - BUF_MEM *buf; - if ((buf = BUF_MEM_new()) == NULL) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); - BUF_MEM_free(buf); - return 0; - } -@@ -163,15 +163,14 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - /* A TLS message must not cross an encryption level boundary */ - if (ssl->quic_buf->length != ssl->quic_next_record_start - && level != ssl->quic_latest_level_received) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, -- SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); -+ ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); - return 0; - } - ssl->quic_latest_level_received = level; - - offset = ssl->quic_buf->length; - if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - memcpy(ssl->quic_buf->data + offset, data, len); -@@ -193,7 +192,7 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - - qd = OPENSSL_zalloc(sizeof(*qd)); - if (qd == NULL) { -- SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR); -+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - -@@ -305,7 +304,7 @@ int SSL_process_quic_post_handshake(SSL - int ret; - - if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) { -- SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - ---- a/ssl/statem/statem.c -+++ b/ssl/statem/statem.c -@@ -930,7 +930,7 @@ int statem_flush(SSL *s) - #ifndef OPENSSL_NO_QUIC - if (SSL_IS_QUIC(s)) { - if (!s->quic_method->flush_flight(s)) { -- SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR); -+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - } else ---- a/ssl/statem/statem_lib.c -+++ b/ssl/statem/statem_lib.c -@@ -54,14 +54,14 @@ int ssl3_do_write(SSL *s, int type) - if (!ret) { - ret = -1; - /* QUIC can't sent anything out sice the above failed */ -- SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR); -+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); - } else { - written = s->init_num; - } - } else { - /* QUIC doesn't use ChangeCipherSpec */ - ret = -1; -- SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); -+ ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - } - } else - #endif diff --git a/openwrt/patch/openssl/quic/0030-QUIC-Add-compile-run-time-checking-for-QUIC.patch b/openwrt/patch/openssl/quic/0030-QUIC-Add-compile-run-time-checking-for-QUIC.patch deleted file mode 100644 index f74974266..000000000 --- a/openwrt/patch/openssl/quic/0030-QUIC-Add-compile-run-time-checking-for-QUIC.patch +++ /dev/null @@ -1,90 +0,0 @@ -From ee45542f244a1cb2eb6dd19b09b44662a04059d9 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 5 Mar 2021 15:22:18 -0500 -Subject: [PATCH 30/43] QUIC: Add compile/run-time checking for QUIC - ---- - apps/info.c | 12 ++++++++++++ - crypto/info.c | 4 ++++ - doc/man3/OpenSSL_version.pod | 8 ++++++++ - include/openssl/crypto.h.in | 4 ++++ - 4 files changed, 28 insertions(+) - ---- a/apps/info.c -+++ b/apps/info.c -@@ -15,6 +15,9 @@ typedef enum OPTION_choice { - OPT_COMMON, - OPT_CONFIGDIR, OPT_ENGINESDIR, OPT_MODULESDIR, OPT_DSOEXT, OPT_DIRNAMESEP, - OPT_LISTSEP, OPT_SEEDS, OPT_CPUSETTINGS -+#ifndef OPENSSL_NO_QUIC -+ , OPT_QUIC -+#endif - } OPTION_CHOICE; - - const OPTIONS info_options[] = { -@@ -32,6 +35,9 @@ const OPTIONS info_options[] = { - {"listsep", OPT_LISTSEP, '-', "List separator character"}, - {"seeds", OPT_SEEDS, '-', "Seed sources"}, - {"cpusettings", OPT_CPUSETTINGS, '-', "CPU settings info"}, -+#ifndef OPENSSL_NO_QUIC -+ {"quic", OPT_QUIC, '-', "QUIC info"}, -+#endif - {NULL} - }; - -@@ -84,6 +90,12 @@ opthelp: - type = OPENSSL_INFO_CPU_SETTINGS; - dirty++; - break; -+#ifndef OPENSSL_NO_QUIC -+ case OPT_QUIC: -+ type = OPENSSL_INFO_QUIC; -+ dirty++; -+ break; -+#endif - } - } - if (opt_num_rest() != 0) ---- a/crypto/info.c -+++ b/crypto/info.c -@@ -199,6 +199,10 @@ const char *OPENSSL_info(int t) - if (ossl_cpu_info_str[0] != '\0') - return ossl_cpu_info_str + strlen(CPUINFO_PREFIX); - break; -+#ifndef OPENSSL_NO_QUIC -+ case OPENSSL_INFO_QUIC: -+ return "QUIC"; -+#endif - default: - break; - } ---- a/doc/man3/OpenSSL_version.pod -+++ b/doc/man3/OpenSSL_version.pod -@@ -211,6 +211,14 @@ automatically configured but may be set - The value has the same syntax as the environment variable. - For x86 the string looks like C. - -+=item OPENSSL_INFO_QUIC -+ -+This is only defined when compiling with a QUIC-enabled version of -+OpenSSL. At run time, this will return "QUIC" if QUIC is supported. -+ -+This can be used as a build time flag to determine if OpenSSL has -+QUIC enabled. -+ - =back - - For an unknown I, NULL is returned. ---- a/include/openssl/crypto.h.in -+++ b/include/openssl/crypto.h.in -@@ -176,6 +176,10 @@ const char *OPENSSL_info(int type); - # define OPENSSL_INFO_SEED_SOURCE 1007 - # define OPENSSL_INFO_CPU_SETTINGS 1008 - -+# ifndef OPENSSL_NO_QUIC -+# define OPENSSL_INFO_QUIC 2000 -+# endif -+ - int OPENSSL_issetugid(void); - - struct crypto_ex_data_st { diff --git a/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch b/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch deleted file mode 100644 index dde67aa6c..000000000 --- a/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch +++ /dev/null @@ -1,485 +0,0 @@ -From ccd7adf0401d1c7e0cb3c7f874777d7d7246679b Mon Sep 17 00:00:00 2001 -From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com> -Date: Thu, 11 Mar 2021 23:07:55 +0900 -Subject: [PATCH 31/43] QUIC: Add early data support - -* QUIC: Add early data support - -This commit adds SSL_set_quic_early_data_enabled to add early data -support to QUIC. ---- - doc/man3/SSL_CTX_set_quic_method.pod | 10 +- - include/openssl/ssl.h.in | 2 + - ssl/ssl_lib.c | 15 +++ - ssl/ssl_quic.c | 76 ++++++++++--- - ssl/statem/statem_srvr.c | 10 ++ - ssl/tls13_enc.c | 90 +++++++++++++--- - test/sslapitest.c | 156 +++++++++++++++++++++++++++ - util/libssl.num | 1 + - 8 files changed, 327 insertions(+), 33 deletions(-) - ---- a/doc/man3/SSL_CTX_set_quic_method.pod -+++ b/doc/man3/SSL_CTX_set_quic_method.pod -@@ -17,7 +17,8 @@ SSL_is_quic, - SSL_get_peer_quic_transport_version, - SSL_get_quic_transport_version, - SSL_set_quic_transport_version, --SSL_set_quic_use_legacy_codepoint -+SSL_set_quic_use_legacy_codepoint, -+SSL_set_quic_early_data_enabled - - QUIC support - - =head1 SYNOPSIS -@@ -47,6 +48,7 @@ SSL_set_quic_use_legacy_codepoint - void SSL_set_quic_transport_version(SSL *ssl, int version); - int SSL_get_quic_transport_version(const SSL *ssl); - int SSL_get_peer_quic_transport_version(const SSL *ssl); -+ void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled); - - =head1 DESCRIPTION - -@@ -106,6 +108,12 @@ SSL_set_quic_transport_version(). - SSL_get_peer_quic_transport_version() returns the version the that was - negotiated. - -+SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero -+value is passed. Client must set a resumed session before calling -+this function. Server must set 0xffffffffu to -+SSL_CTX_set_max_early_data() or SSL_set_max_early_data() so that a -+session ticket indicates that server is able to accept early data. -+ - =head1 NOTES - - These APIs are implementations of BoringSSL's QUIC APIs. ---- a/include/openssl/ssl.h.in -+++ b/include/openssl/ssl.h.in -@@ -2577,6 +2577,8 @@ __owur int SSL_get_peer_quic_transport_v - - int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c); - -+void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled); -+ - # endif - - # ifdef __cplusplus ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -4015,6 +4015,21 @@ int SSL_do_handshake(SSL *s) - ret = s->handshake_func(s); - } - } -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s) && ret == 1) { -+ if (s->server) { -+ if (s->early_data_state == SSL_EARLY_DATA_ACCEPTING) { -+ s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; -+ s->rwstate = SSL_READING; -+ ret = 0; -+ } -+ } else if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) { -+ s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY; -+ s->rwstate = SSL_READING; -+ ret = 0; -+ } -+ } -+#endif - return ret; - } - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -257,24 +257,46 @@ int quic_set_encryption_secrets(SSL *ssl - return 1; - } - -- md = ssl_handshake_md(ssl); -- if (md == NULL) { -- /* May not have selected cipher, yet */ -- const SSL_CIPHER *c = NULL; -- -- /* -- * It probably doesn't make sense to use an (external) PSK session, -- * but in theory some kinds of external session caches could be -- * implemented using it, so allow psksession to be used as well as -- * the regular session. -- */ -- if (ssl->session != NULL) -- c = SSL_SESSION_get0_cipher(ssl->session); -- else if (ssl->psksession != NULL) -+ if (level == ssl_encryption_early_data) { -+ const SSL_CIPHER *c = SSL_SESSION_get0_cipher(ssl->session); -+ if (ssl->early_data_state == SSL_EARLY_DATA_CONNECTING -+ && ssl->max_early_data > 0 -+ && ssl->session->ext.max_early_data == 0) { -+ if (!ossl_assert(ssl->psksession != NULL -+ && ssl->max_early_data == -+ ssl->psksession->ext.max_early_data)) { -+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } - c = SSL_SESSION_get0_cipher(ssl->psksession); -+ } -+ -+ if (c == NULL) { -+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ return 0; -+ } - -- if (c != NULL) -- md = SSL_CIPHER_get_handshake_digest(c); -+ md = ssl_md(ssl->ctx, c->algorithm2); -+ } else { -+ md = ssl_handshake_md(ssl); -+ if (md == NULL) { -+ /* May not have selected cipher, yet */ -+ const SSL_CIPHER *c = NULL; -+ -+ /* -+ * It probably doesn't make sense to use an (external) PSK session, -+ * but in theory some kinds of external session caches could be -+ * implemented using it, so allow psksession to be used as well as -+ * the regular session. -+ */ -+ if (ssl->session != NULL) -+ c = SSL_SESSION_get0_cipher(ssl->session); -+ else if (ssl->psksession != NULL) -+ c = SSL_SESSION_get0_cipher(ssl->psksession); -+ -+ if (c != NULL) -+ md = SSL_CIPHER_get_handshake_digest(c); -+ } - } - - if ((len = EVP_MD_size(md)) <= 0) { -@@ -330,3 +352,25 @@ int SSL_is_quic(SSL* ssl) - { - return SSL_IS_QUIC(ssl); - } -+ -+void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled) -+{ -+ if (!SSL_is_quic(ssl) || !SSL_in_before(ssl)) -+ return; -+ -+ if (!enabled) { -+ ssl->early_data_state = SSL_EARLY_DATA_NONE; -+ return; -+ } -+ -+ if (ssl->server) { -+ ssl->early_data_state = SSL_EARLY_DATA_ACCEPTING; -+ return; -+ } -+ -+ if ((ssl->session == NULL || ssl->session->ext.max_early_data == 0) -+ && ssl->psk_use_session_cb == NULL) -+ return; -+ -+ ssl->early_data_state = SSL_EARLY_DATA_CONNECTING; -+} ---- a/ssl/statem/statem_srvr.c -+++ b/ssl/statem/statem_srvr.c -@@ -964,6 +964,16 @@ WORK_STATE ossl_statem_server_post_work( - SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE)) - /* SSLfatal() already called */ - return WORK_ERROR; -+ -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s) && s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { -+ s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; -+ if (!s->method->ssl3_enc->change_cipher_state( -+ s, SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ)) -+ /* SSLfatal() already called */ -+ return WORK_ERROR; -+ } -+#endif - } - break; - ---- a/ssl/tls13_enc.c -+++ b/ssl/tls13_enc.c -@@ -434,20 +434,76 @@ static int quic_change_cipher_state(SSL - int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE); - int is_early = (which & SSL3_CC_EARLY); - -- md = ssl_handshake_md(s); -- if (!ssl3_digest_cached_records(s, 1) -- || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) { -- /* SSLfatal() already called */; -- goto err; -- } -+ if (is_early) { -+ EVP_MD_CTX *mdctx = NULL; -+ long handlen; -+ void *hdata; -+ unsigned int hashlenui; -+ const SSL_CIPHER *sslcipher = SSL_SESSION_get0_cipher(s->session); -+ -+ handlen = BIO_get_mem_data(s->s3.handshake_buffer, &hdata); -+ if (handlen <= 0) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_HANDSHAKE_LENGTH); -+ goto err; -+ } -+ -+ if (s->early_data_state == SSL_EARLY_DATA_CONNECTING -+ && s->max_early_data > 0 -+ && s->session->ext.max_early_data == 0) { -+ /* -+ * If we are attempting to send early data, and we've decided to -+ * actually do it but max_early_data in s->session is 0 then we -+ * must be using an external PSK. -+ */ -+ if (!ossl_assert(s->psksession != NULL -+ && s->max_early_data == -+ s->psksession->ext.max_early_data)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ goto err; -+ } -+ sslcipher = SSL_SESSION_get0_cipher(s->psksession); -+ } -+ if (sslcipher == NULL) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_PSK); -+ goto err; -+ } -+ -+ /* -+ * We need to calculate the handshake digest using the digest from -+ * the session. We haven't yet selected our ciphersuite so we can't -+ * use ssl_handshake_md(). -+ */ -+ mdctx = EVP_MD_CTX_new(); -+ if (mdctx == NULL) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE); -+ goto err; -+ } -+ md = ssl_md(s->ctx, sslcipher->algorithm2); -+ if (md == NULL || !EVP_DigestInit_ex(mdctx, md, NULL) -+ || !EVP_DigestUpdate(mdctx, hdata, handlen) -+ || !EVP_DigestFinal_ex(mdctx, hash, &hashlenui)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); -+ EVP_MD_CTX_free(mdctx); -+ goto err; -+ } -+ hashlen = hashlenui; -+ EVP_MD_CTX_free(mdctx); -+ } else { -+ md = ssl_handshake_md(s); -+ if (!ssl3_digest_cached_records(s, 1) -+ || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) { -+ /* SSLfatal() already called */; -+ goto err; -+ } - -- /* Ensure cast to size_t is safe */ -- hashleni = EVP_MD_size(md); -- if (!ossl_assert(hashleni >= 0)) { -- SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); -- goto err; -+ /* Ensure cast to size_t is safe */ -+ hashleni = EVP_MD_size(md); -+ if (!ossl_assert(hashleni >= 0)) { -+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); -+ goto err; -+ } -+ hashlen = (size_t)hashleni; - } -- hashlen = (size_t)hashleni; - - if (is_client_read || is_server_write) { - if (is_handshake) { -@@ -553,10 +609,12 @@ static int quic_change_cipher_state(SSL - } - } - -- if (s->server) -- s->quic_read_level = level; -- else -- s->quic_write_level = level; -+ if (level != ssl_encryption_early_data) { -+ if (s->server) -+ s->quic_read_level = level; -+ else -+ s->quic_write_level = level; -+ } - } - - ret = 1; ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10966,6 +10966,159 @@ end: - serverssl = NULL; - return testresult; - } -+ -+# ifndef OSSL_NO_USABLE_TLS1_3 -+/* -+ * Helper method to setup objects for QUIC early data test. Caller -+ * frees objects on error. -+ */ -+static int quic_setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, -+ SSL **clientssl, SSL **serverssl, -+ SSL_SESSION **sess, int idx) -+{ -+ static const char *server_str = "SERVER"; -+ static const char *client_str = "CLIENT"; -+ -+ if (*sctx == NULL -+ && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -+ TLS_client_method(), -+ TLS1_3_VERSION, 0, -+ sctx, cctx, cert, privkey)) -+ || !TEST_true(SSL_CTX_set_quic_method(*sctx, &quic_method)) -+ || !TEST_true(SSL_CTX_set_quic_method(*cctx, &quic_method)) -+ || !TEST_true(SSL_CTX_set_max_early_data(*sctx, 0xffffffffu)))) -+ return 0; -+ -+ if (idx == 1) { -+ /* When idx == 1 we repeat the tests with read_ahead set */ -+ SSL_CTX_set_read_ahead(*cctx, 1); -+ SSL_CTX_set_read_ahead(*sctx, 1); -+ } else if (idx == 2) { -+ /* When idx == 2 we are doing early_data with a PSK. Set up callbacks */ -+ SSL_CTX_set_psk_use_session_callback(*cctx, use_session_cb); -+ SSL_CTX_set_psk_find_session_callback(*sctx, find_session_cb); -+ use_session_cb_cnt = 0; -+ find_session_cb_cnt = 0; -+ srvid = pskid; -+ } -+ -+ if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl, clientssl, -+ NULL, NULL)) -+ || !TEST_true(SSL_set_quic_transport_params(*serverssl, -+ (unsigned char*)server_str, -+ strlen(server_str)+1)) -+ || !TEST_true(SSL_set_quic_transport_params(*clientssl, -+ (unsigned char*)client_str, -+ strlen(client_str)+1)) -+ || !TEST_true(SSL_set_app_data(*serverssl, *clientssl)) -+ || !TEST_true(SSL_set_app_data(*clientssl, *serverssl))) -+ return 0; -+ -+ /* -+ * For one of the run throughs (doesn't matter which one), we'll try sending -+ * some SNI data in the initial ClientHello. This will be ignored (because -+ * there is no SNI cb set up by the server), so it should not impact -+ * early_data. -+ */ -+ if (idx == 1 -+ && !TEST_true(SSL_set_tlsext_host_name(*clientssl, "localhost"))) -+ return 0; -+ -+ if (idx == 2) { -+ clientpsk = create_a_psk(*clientssl, SHA256_DIGEST_LENGTH); -+ if (!TEST_ptr(clientpsk) -+ || !TEST_true(SSL_SESSION_set_max_early_data(clientpsk, -+ 0xffffffffu)) -+ || !TEST_true(SSL_SESSION_up_ref(clientpsk))) { -+ SSL_SESSION_free(clientpsk); -+ clientpsk = NULL; -+ return 0; -+ } -+ serverpsk = clientpsk; -+ -+ if (sess != NULL) { -+ if (!TEST_true(SSL_SESSION_up_ref(clientpsk))) { -+ SSL_SESSION_free(clientpsk); -+ SSL_SESSION_free(serverpsk); -+ clientpsk = serverpsk = NULL; -+ return 0; -+ } -+ *sess = clientpsk; -+ } -+ -+ SSL_set_quic_early_data_enabled(*serverssl, 1); -+ SSL_set_quic_early_data_enabled(*clientssl, 1); -+ -+ return 1; -+ } -+ -+ if (sess == NULL) -+ return 1; -+ -+ if (!TEST_true(create_ssl_connection(*serverssl, *clientssl, -+ SSL_ERROR_NONE))) -+ return 0; -+ -+ /* Deal with two NewSessionTickets */ -+ if (!TEST_true(SSL_process_quic_post_handshake(*clientssl)) -+ || !TEST_true(SSL_process_quic_post_handshake(*clientssl))) -+ return 0; -+ -+ *sess = SSL_get1_session(*clientssl); -+ SSL_shutdown(*clientssl); -+ SSL_shutdown(*serverssl); -+ SSL_free(*serverssl); -+ SSL_free(*clientssl); -+ *serverssl = *clientssl = NULL; -+ -+ if (!TEST_true(create_ssl_objects(*sctx, *cctx, serverssl, -+ clientssl, NULL, NULL)) -+ || !TEST_true(SSL_set_session(*clientssl, *sess)) -+ || !TEST_true(SSL_set_quic_transport_params(*serverssl, -+ (unsigned char*)server_str, -+ strlen(server_str)+1)) -+ || !TEST_true(SSL_set_quic_transport_params(*clientssl, -+ (unsigned char*)client_str, -+ strlen(client_str)+1)) -+ || !TEST_true(SSL_set_app_data(*serverssl, *clientssl)) -+ || !TEST_true(SSL_set_app_data(*clientssl, *serverssl))) -+ return 0; -+ -+ SSL_set_quic_early_data_enabled(*serverssl, 1); -+ SSL_set_quic_early_data_enabled(*clientssl, 1); -+ -+ return 1; -+} -+ -+static int test_quic_early_data(int tst) -+{ -+ SSL_CTX *cctx = NULL, *sctx = NULL; -+ SSL *clientssl = NULL, *serverssl = NULL; -+ int testresult = 0; -+ SSL_SESSION *sess = NULL; -+ -+ if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl, -+ &serverssl, &sess, tst))) -+ goto end; -+ -+ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) -+ || !TEST_true(SSL_get_early_data_status(serverssl))) -+ goto end; -+ -+ testresult = 1; -+ -+ end: -+ SSL_SESSION_free(sess); -+ SSL_SESSION_free(clientpsk); -+ SSL_SESSION_free(serverpsk); -+ clientpsk = serverpsk = NULL; -+ SSL_free(serverssl); -+ SSL_free(clientssl); -+ SSL_CTX_free(sctx); -+ SSL_CTX_free(cctx); -+ return testresult; -+} -+# endif /* OSSL_NO_USABLE_TLS1_3 */ - #endif /* OPENSSL_NO_QUIC */ - - static struct next_proto_st { -@@ -11687,6 +11840,9 @@ int setup_tests(void) - ADD_ALL_TESTS(test_no_renegotiation, 2); - #ifndef OPENSSL_NO_QUIC - ADD_ALL_TESTS(test_quic_api, 9); -+# ifndef OSSL_NO_USABLE_TLS1_3 -+ ADD_ALL_TESTS(test_quic_early_data, 3); -+# endif - #endif - return 1; - ---- a/util/libssl.num -+++ b/util/libssl.num -@@ -535,3 +535,4 @@ SSL_set_quic_use_legacy_codepoint - SSL_set_quic_transport_version 20012 3_0_0 EXIST::FUNCTION:QUIC - SSL_get_peer_quic_transport_version 20013 3_0_0 EXIST::FUNCTION:QUIC - SSL_get_quic_transport_version 20014 3_0_0 EXIST::FUNCTION:QUIC -+SSL_set_quic_early_data_enabled 20015 3_0_0 EXIST::FUNCTION:QUIC diff --git a/openwrt/patch/openssl/quic/0032-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch b/openwrt/patch/openssl/quic/0032-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch deleted file mode 100644 index 37435342c..000000000 --- a/openwrt/patch/openssl/quic/0032-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 01bc5c3a5aa160c2e9bba9c0c45a94eb5702772d Mon Sep 17 00:00:00 2001 -From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com> -Date: Fri, 12 Mar 2021 00:39:20 +0900 -Subject: [PATCH 32/43] QUIC: Make SSL_provide_quic_data accept 0 length data - -This commit makes SSL_provide_quic_data accept 0 length data, which -matches BoringSSL behavior. ---- - ssl/ssl_quic.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -143,6 +143,9 @@ int SSL_provide_quic_data(SSL *ssl, OSSL - return 0; - } - -+ if (len == 0) -+ return 1; -+ - if (ssl->quic_buf == NULL) { - BUF_MEM *buf; - if ((buf = BUF_MEM_new()) == NULL) { diff --git a/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch b/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch deleted file mode 100644 index 10654746c..000000000 --- a/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch +++ /dev/null @@ -1,68 +0,0 @@ -From d286825de6b6243fab9b5ad6c7d522067c4d0e3a Mon Sep 17 00:00:00 2001 -From: Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com> -Date: Sat, 13 Mar 2021 05:37:34 +0900 -Subject: [PATCH 33/43] QUIC: Process multiple post-handshake messages in a - single call - ---- - ssl/ssl_quic.c | 27 +++++++++++++-------------- - test/sslapitest.c | 6 ++---- - 2 files changed, 15 insertions(+), 18 deletions(-) - ---- a/ssl/ssl_quic.c -+++ b/ssl/ssl_quic.c -@@ -334,20 +334,19 @@ int SSL_process_quic_post_handshake(SSL - } - - /* if there is no data, return success as BoringSSL */ -- if (ssl->quic_input_data_head == NULL) -- return 1; -- -- /* -- * This is always safe (we are sure to be at a record boundary) because -- * SSL_read()/SSL_write() are never used for QUIC connections -- the -- * application data is handled at the QUIC layer instead. -- */ -- ossl_statem_set_in_init(ssl, 1); -- ret = ssl->handshake_func(ssl); -- ossl_statem_set_in_init(ssl, 0); -+ while (ssl->quic_input_data_head != NULL) { -+ /* -+ * This is always safe (we are sure to be at a record boundary) because -+ * SSL_read()/SSL_write() are never used for QUIC connections -- the -+ * application data is handled at the QUIC layer instead. -+ */ -+ ossl_statem_set_in_init(ssl, 1); -+ ret = ssl->handshake_func(ssl); -+ ossl_statem_set_in_init(ssl, 0); - -- if (ret <= 0) -- return 0; -+ if (ret <= 0) -+ return 0; -+ } - return 1; - } - ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10872,8 +10872,7 @@ static int test_quic_api_version(int cln - goto end; - - /* Deal with two NewSessionTickets */ -- if (!TEST_true(SSL_process_quic_post_handshake(clientssl)) -- || !TEST_true(SSL_process_quic_post_handshake(clientssl))) -+ if (!TEST_true(SSL_process_quic_post_handshake(clientssl))) - goto end; - - /* Dummy handshake call should succeed */ -@@ -11060,8 +11059,7 @@ static int quic_setupearly_data_test(SSL - return 0; - - /* Deal with two NewSessionTickets */ -- if (!TEST_true(SSL_process_quic_post_handshake(*clientssl)) -- || !TEST_true(SSL_process_quic_post_handshake(*clientssl))) -+ if (!TEST_true(SSL_process_quic_post_handshake(*clientssl))) - return 0; - - *sess = SSL_get1_session(*clientssl); diff --git a/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch b/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch deleted file mode 100644 index 28914467b..000000000 --- a/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch +++ /dev/null @@ -1,84 +0,0 @@ -From db0ea38b914f434c1faa0a140a3ce5f9dfa8d248 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 18 Mar 2021 12:42:01 -0400 -Subject: [PATCH 34/43] QUIC: Fix CI - -Updates `Configure` script to disable QUIC with `no-bulk` and `no-ec` -Updates build.info doc docs -Fixes an issue with extension defintions and `no-quic` ---- - Configure | 3 ++- - doc/build.info | 6 ++++++ - ssl/statem/extensions.c | 1 + - ssl/statem/extensions_srvr.c | 2 +- - 4 files changed, 10 insertions(+), 2 deletions(-) - ---- a/Configure -+++ b/Configure -@@ -579,6 +579,7 @@ my @disable_cascades = ( - "sm3", "sm4", "srp", - "srtp", "ssl3-method", "ssl-trace", - "ts", "ui-console", "whirlpool", -+ "quic", - "fips-securitychecks" ], - sub { $config{processor} eq "386" } - => [ "sse2" ], -@@ -586,7 +587,7 @@ my @disable_cascades = ( - "ssl3-method" => [ "ssl3" ], - "zlib" => [ "zlib-dynamic" ], - "des" => [ "mdc2" ], -- "ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ], -+ "ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost", "quic" ], - "dgram" => [ "dtls", "sctp" ], - "sock" => [ "dgram" ], - "dtls" => [ @dtls ], ---- a/doc/build.info -+++ b/doc/build.info -@@ -2271,6 +2271,10 @@ DEPEND[html/man3/SSL_CTX_set_psk_client_ - GENERATE[html/man3/SSL_CTX_set_psk_client_callback.html]=man3/SSL_CTX_set_psk_client_callback.pod - DEPEND[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod - GENERATE[man/man3/SSL_CTX_set_psk_client_callback.3]=man3/SSL_CTX_set_psk_client_callback.pod -+DEPEND[html/man3/SSL_CTX_set_quic_method.html]=man3/SSL_CTX_set_quic_method.pod -+GENERATE[html/man3/SSL_CTX_set_quic_method.html]=man3/SSL_CTX_set_quic_method.pod -+DEPEND[man/man3/SSL_CTX_set_quic_method.3]=man3/SSL_CTX_set_quic_method.pod -+GENERATE[man/man3/SSL_CTX_set_quic_method.3]=man3/SSL_CTX_set_quic_method.pod - DEPEND[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod - GENERATE[html/man3/SSL_CTX_set_quiet_shutdown.html]=man3/SSL_CTX_set_quiet_shutdown.pod - DEPEND[man/man3/SSL_CTX_set_quiet_shutdown.3]=man3/SSL_CTX_set_quiet_shutdown.pod -@@ -3351,6 +3355,7 @@ html/man3/SSL_CTX_set_msg_callback.html - html/man3/SSL_CTX_set_num_tickets.html \ - html/man3/SSL_CTX_set_options.html \ - html/man3/SSL_CTX_set_psk_client_callback.html \ -+html/man3/SSL_CTX_set_quic_method.html \ - html/man3/SSL_CTX_set_quiet_shutdown.html \ - html/man3/SSL_CTX_set_read_ahead.html \ - html/man3/SSL_CTX_set_record_padding_callback.html \ -@@ -3959,6 +3964,7 @@ man/man3/SSL_CTX_set_msg_callback.3 \ - man/man3/SSL_CTX_set_num_tickets.3 \ - man/man3/SSL_CTX_set_options.3 \ - man/man3/SSL_CTX_set_psk_client_callback.3 \ -+man/man3/SSL_CTX_set_quic_method.3 \ - man/man3/SSL_CTX_set_quiet_shutdown.3 \ - man/man3/SSL_CTX_set_read_ahead.3 \ - man/man3/SSL_CTX_set_record_padding_callback.3 \ ---- a/ssl/statem/extensions.c -+++ b/ssl/statem/extensions.c -@@ -396,6 +396,7 @@ static const EXTENSION_DEFINITION ext_de - }, - #else - INVALID_EXTENSION, -+ INVALID_EXTENSION, - #endif - { - /* Must be immediately before pre_shared_key */ ---- a/ssl/statem/extensions_srvr.c -+++ b/ssl/statem/extensions_srvr.c -@@ -1930,7 +1930,7 @@ EXT_RETURN tls_construct_stoc_early_data - - #ifndef OPENSSL_NO_QUIC - /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ -- if (s->quic_method != NULL) -+ if (SSL_IS_QUIC(s)) - max_early_data = 0xFFFFFFFF; - #endif - diff --git a/openwrt/patch/openssl/quic/0035-QUIC-Break-up-header-body-processing.patch b/openwrt/patch/openssl/quic/0035-QUIC-Break-up-header-body-processing.patch deleted file mode 100644 index cf8aebcaa..000000000 --- a/openwrt/patch/openssl/quic/0035-QUIC-Break-up-header-body-processing.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 8771ca8598c700037896929db7deeef3687bd897 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Thu, 6 May 2021 16:24:03 -0400 -Subject: [PATCH 35/43] QUIC: Break up header/body processing - -As DTLS has changed, so too must QUIC. ---- - ssl/statem/statem.c | 9 ++++++--- - ssl/statem/statem_local.h | 3 ++- - ssl/statem/statem_quic.c | 25 +++++++++++++++---------- - 3 files changed, 23 insertions(+), 14 deletions(-) - ---- a/ssl/statem/statem.c -+++ b/ssl/statem/statem.c -@@ -586,7 +586,7 @@ static SUB_STATE_RETURN read_state_machi - #ifndef OPENSSL_NO_QUIC - } else if (SSL_IS_QUIC(s)) { - /* QUIC behaves like DTLS -- all in one go. */ -- ret = quic_get_message(s, &mt, &len); -+ ret = quic_get_message(s, &mt); - #endif - } else { - ret = tls_get_message_header(s, &mt); -@@ -636,8 +636,11 @@ static SUB_STATE_RETURN read_state_machi - * opportunity to do any further processing. - */ - ret = dtls_get_message_body(s, &len); -- } else if (!SSL_IS_QUIC(s)) { -- /* We already got this above for QUIC */ -+#ifndef OPENSSL_NO_QUIC -+ } else if (SSL_IS_QUIC(s)) { -+ ret = quic_get_message_body(s, &len); -+#endif -+ } else { - ret = tls_get_message_body(s, &len); - } - if (ret == 0) { ---- a/ssl/statem/statem_local.h -+++ b/ssl/statem/statem_local.h -@@ -105,7 +105,8 @@ __owur int tls_get_message_body(SSL *s, - __owur int dtls_get_message(SSL *s, int *mt); - __owur int dtls_get_message_body(SSL *s, size_t *len); - #ifndef OPENSSL_NO_QUIC --__owur int quic_get_message(SSL *s, int *mt, size_t *len); -+__owur int quic_get_message(SSL *s, int *mt); -+__owur int quic_get_message_body(SSL *s, size_t *len); - #endif - - /* Message construction and processing functions */ ---- a/ssl/statem/statem_quic.c -+++ b/ssl/statem/statem_quic.c -@@ -11,7 +11,7 @@ - #include "statem_local.h" - #include "internal/cryptlib.h" - --int quic_get_message(SSL *s, int *mt, size_t *len) -+int quic_get_message(SSL *s, int *mt) - { - size_t l; - QUIC_DATA *qd = s->quic_input_data_head; -@@ -19,26 +19,26 @@ int quic_get_message(SSL *s, int *mt, si - - if (qd == NULL) { - s->rwstate = SSL_READING; -- *mt = *len = 0; -+ *mt = 0; - return 0; - } - - if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_LENGTH); -- *mt = *len = 0; -+ *mt = 0; - return 0; - } - - /* This is where we check for the proper level, not when data is given */ - if (qd->level != s->quic_read_level) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED); -- *mt = *len = 0; -+ *mt = 0; - return 0; - } - - if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); -- *mt = *len = 0; -+ *mt = 0; - return 0; - } - -@@ -53,28 +53,32 @@ int quic_get_message(SSL *s, int *mt, si - s->s3.tmp.message_type = *mt = *(s->init_buf->data); - p = (uint8_t*)s->init_buf->data + 1; - n2l3(p, l); -- s->init_num = s->s3.tmp.message_size = *len = l; -+ s->init_num = s->s3.tmp.message_size = l; - s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH; - -+ return 1; -+} -+ -+int quic_get_message_body(SSL *s, size_t *len) -+{ - /* No CCS in QUIC/TLSv1.3? */ -- if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { -+ if (s->s3.tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) { - SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_CCS_RECEIVED_EARLY); - *len = 0; - return 0; - } - /* No KeyUpdate in QUIC */ -- if (*mt == SSL3_MT_KEY_UPDATE) { -+ if (s->s3.tmp.message_type == SSL3_MT_KEY_UPDATE) { - SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); - *len = 0; - return 0; - } - -- - /* - * If receiving Finished, record MAC of prior handshake messages for - * Finished verification. - */ -- if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { -+ if (s->s3.tmp.message_type == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { - /* SSLfatal() already called */ - *len = 0; - return 0; -@@ -108,5 +112,6 @@ int quic_get_message(SSL *s, int *mt, si - (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s, - s->msg_callback_arg); - -+ *len = s->init_num; - return 1; - } diff --git a/openwrt/patch/openssl/quic/0036-QUIC-Don-t-muck-with-FIPS-checksums.patch b/openwrt/patch/openssl/quic/0036-QUIC-Don-t-muck-with-FIPS-checksums.patch deleted file mode 100644 index 31c1a136b..000000000 --- a/openwrt/patch/openssl/quic/0036-QUIC-Don-t-muck-with-FIPS-checksums.patch +++ /dev/null @@ -1,113 +0,0 @@ -From e5b708383649146cbba45373bdf15a2e3c39240a Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 9 Jul 2021 13:29:03 -0400 -Subject: [PATCH 36/43] QUIC: Don't muck with FIPS checksums - ---- - apps/info.c | 1 + - crypto/info.c | 1 + - include/openssl/crypto.h.in | 4 ---- - include/openssl/evp.h | 4 ---- - include/openssl/quic.h | 19 +++++++++++++++++++ - include/openssl/ssl.h.in | 9 +++++++++ - include/openssl/types.h | 2 -- - 7 files changed, 30 insertions(+), 10 deletions(-) - create mode 100644 include/openssl/quic.h - ---- a/apps/info.c -+++ b/apps/info.c -@@ -10,6 +10,7 @@ - #include - #include "apps.h" - #include "progs.h" -+#include - - typedef enum OPTION_choice { - OPT_COMMON, ---- a/crypto/info.c -+++ b/crypto/info.c -@@ -14,6 +14,7 @@ - #include "internal/cryptlib.h" - #include "e_os.h" - #include "buildinf.h" -+#include - - #if defined(__arm__) || defined(__arm) || defined(__aarch64__) - # include "arm_arch.h" ---- a/include/openssl/crypto.h.in -+++ b/include/openssl/crypto.h.in -@@ -176,10 +176,6 @@ const char *OPENSSL_info(int type); - # define OPENSSL_INFO_SEED_SOURCE 1007 - # define OPENSSL_INFO_CPU_SETTINGS 1008 - --# ifndef OPENSSL_NO_QUIC --# define OPENSSL_INFO_QUIC 2000 --# endif -- - int OPENSSL_issetugid(void); - - struct crypto_ex_data_st { ---- a/include/openssl/evp.h -+++ b/include/openssl/evp.h -@@ -1742,10 +1742,6 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CT - */ - # define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 - --/* Used by Chromium/QUIC */ --# define X25519_PRIVATE_KEY_LEN 32 --# define X25519_PUBLIC_VALUE_LEN 32 -- - # ifndef OPENSSL_NO_DEPRECATED_3_0 - OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); - OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); ---- /dev/null -+++ b/include/openssl/quic.h -@@ -0,0 +1,19 @@ -+/* -+ * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. -+ * -+ * Licensed under the Apache License 2.0 (the "License"). You may not use -+ * this file except in compliance with the License. You can obtain a copy -+ * in the file LICENSE in the source distribution or at -+ * https://www.openssl.org/source/license.html -+ */ -+ -+#ifndef OPENSSL_QUIC_H -+# define OPENSSL_QUIC_H -+# pragma once -+# ifndef OPENSSL_NO_QUIC -+ -+/* moved from crypto.h.in to avoid breaking FIPS checksums */ -+# define OPENSSL_INFO_QUIC 2000 -+ -+# endif /* OPENSSL_NO_QUIC */ -+#endif /* OPENSSL_QUIC_H */ ---- a/include/openssl/ssl.h.in -+++ b/include/openssl/ssl.h.in -@@ -2528,6 +2528,15 @@ const char *OSSL_default_ciphersuites(vo - * ssl_encryption_level_t represents a specific QUIC encryption level used to - * transmit handshake messages. BoringSSL has this as an 'enum'. - */ -+#include -+ -+/* Used by Chromium/QUIC - moved from evp.h to avoid breaking FIPS checksums */ -+# define X25519_PRIVATE_KEY_LEN 32 -+# define X25519_PUBLIC_VALUE_LEN 32 -+ -+/* moved from types.h to avoid breaking FIPS checksums */ -+typedef struct ssl_quic_method_st SSL_QUIC_METHOD; -+ - typedef enum ssl_encryption_level_t { - ssl_encryption_initial = 0, - ssl_encryption_early_data, ---- a/include/openssl/types.h -+++ b/include/openssl/types.h -@@ -229,8 +229,6 @@ typedef struct ossl_decoder_ctx_st OSSL_ - - typedef struct ossl_self_test_st OSSL_SELF_TEST; - --typedef struct ssl_quic_method_st SSL_QUIC_METHOD; -- - #ifdef __cplusplus - } - #endif diff --git a/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch b/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch deleted file mode 100644 index f6d9674fd..000000000 --- a/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 00ba735b875be08adbf1bb388cbce8155a1ed978 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 7 Sep 2021 12:26:10 -0400 -Subject: [PATCH 37/43] QUIC: Update RFC references - ---- - doc/man3/SSL_CTX_set_quic_method.pod | 11 +++++------ - include/openssl/tls1.h | 2 +- - ssl/statem/extensions_clnt.c | 2 +- - ssl/statem/extensions_srvr.c | 2 +- - ssl/statem/statem_clnt.c | 2 +- - 5 files changed, 9 insertions(+), 10 deletions(-) - ---- a/doc/man3/SSL_CTX_set_quic_method.pod -+++ b/doc/man3/SSL_CTX_set_quic_method.pod -@@ -74,7 +74,7 @@ SSL_quic_max_handshake_flight_len() retu - that may be received at the given encryption level. This function should be - used to limit buffering in the QUIC implementation. - --See https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-4. -+See L. - - SSL_quic_read_level() returns the current read encryption level. - -@@ -120,7 +120,7 @@ These APIs are implementations of Boring - - QUIC acts as an underlying transport for the TLS 1.3 handshake. The following - functions allow a QUIC implementation to serve as the underlying transport as --described in draft-ietf-quic-tls. -+described in RFC9001. - - When configured for QUIC, SSL_do_handshake() will drive the handshake as - before, but it will not use the configured B. It will call functions from -@@ -139,18 +139,17 @@ pass the active write level to add_hands - can use SSL_quic_write_level() to query the active write level when - generating their own errors. - --See https://tools.ietf.org/html/draft-ietf-quic-tls-27#section-4.1 for more --details. -+See L for more details. - - To avoid DoS attacks, the QUIC implementation must limit the amount of data - being queued up. The implementation can call - SSL_quic_max_handshake_flight_len() to get the maximum buffer length at each - encryption level. - --draft-ietf-quic-tls defines a new TLS extension "quic_transport_parameters" -+RFC9001 defines a new TLS extension "quic_transport_parameters" - used by QUIC for each endpoint to unilaterally declare its supported - transport parameters. The contents of the extension are specified in --https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-18 (as -+L (as - a sequence of tag/length/value parameters) along with the interpretation of the - various parameters and the rules for their processing. - ---- a/include/openssl/tls1.h -+++ b/include/openssl/tls1.h -@@ -151,7 +151,7 @@ extern "C" { - /* Temporary extension type */ - # define TLSEXT_TYPE_renegotiate 0xff01 - --/* ExtensionType value from draft-ietf-quic-tls-27 */ -+ /* ExtensionType value from RFC9001 */ - # define TLSEXT_TYPE_quic_transport_parameters_draft 0xffa5 - # define TLSEXT_TYPE_quic_transport_parameters 0x0039 - ---- a/ssl/statem/extensions_clnt.c -+++ b/ssl/statem/extensions_clnt.c -@@ -1967,7 +1967,7 @@ int tls_parse_stoc_early_data(SSL *s, PA - #ifndef OPENSSL_NO_QUIC - /* - * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION -- * per draft-ietf-quic-tls-27 S4.5 -+ * per RFC9001 S4.6.1 - */ - if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); ---- a/ssl/statem/extensions_srvr.c -+++ b/ssl/statem/extensions_srvr.c -@@ -1929,7 +1929,7 @@ EXT_RETURN tls_construct_stoc_early_data - return EXT_RETURN_NOT_SENT; - - #ifndef OPENSSL_NO_QUIC -- /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */ -+ /* QUIC server must always send 0xFFFFFFFF, per RFC9001 S4.6.1 */ - if (SSL_IS_QUIC(s)) - max_early_data = 0xFFFFFFFF; - #endif ---- a/ssl/statem/statem_clnt.c -+++ b/ssl/statem/statem_clnt.c -@@ -905,7 +905,7 @@ int ossl_statem_client_construct_message - - case TLS_ST_CW_END_OF_EARLY_DATA: - #ifndef OPENSSL_NO_QUIC -- /* QUIC does not send EndOfEarlyData, draft-ietf-quic-tls-24 S8.3 */ -+ /* QUIC does not send EndOfEarlyData, RFC9001 S8.3 */ - if (s->quic_method != NULL) { - *confunc = NULL; - *mt = SSL3_MT_DUMMY; diff --git a/openwrt/patch/openssl/quic/0038-QUIC-revert-white-space-change.patch b/openwrt/patch/openssl/quic/0038-QUIC-revert-white-space-change.patch deleted file mode 100644 index 99001b957..000000000 --- a/openwrt/patch/openssl/quic/0038-QUIC-revert-white-space-change.patch +++ /dev/null @@ -1,19 +0,0 @@ -From d25cdd9dfed870991d6eeca1f76ed805eecbf184 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 7 Sep 2021 12:29:37 -0400 -Subject: [PATCH 38/43] QUIC: revert white-space change - ---- - include/openssl/evp.h | 1 - - 1 file changed, 1 deletion(-) - ---- a/include/openssl/evp.h -+++ b/include/openssl/evp.h -@@ -1741,7 +1741,6 @@ int EVP_PKEY_CTX_set_mac_key(EVP_PKEY_CT - * Method handles all operations: don't assume any digest related defaults. - */ - # define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4 -- - # ifndef OPENSSL_NO_DEPRECATED_3_0 - OSSL_DEPRECATEDIN_3_0 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type); - OSSL_DEPRECATEDIN_3_0 EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags); diff --git a/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch b/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch deleted file mode 100644 index f1842d866..000000000 --- a/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch +++ /dev/null @@ -1,44 +0,0 @@ -From b240c965d1c7c1d2095c2af798c4853d3379480a Mon Sep 17 00:00:00 2001 -From: Benjamin Kaduk -Date: Tue, 7 Sep 2021 14:21:22 -0700 -Subject: [PATCH 39/43] QUIC: use SSL_IS_QUIC() in more places - ---- - doc/man3/SSL_CTX_set_quic_method.pod | 2 +- - ssl/statem/extensions_clnt.c | 2 +- - ssl/statem/statem_clnt.c | 2 +- - 3 files changed, 3 insertions(+), 3 deletions(-) - ---- a/doc/man3/SSL_CTX_set_quic_method.pod -+++ b/doc/man3/SSL_CTX_set_quic_method.pod -@@ -105,7 +105,7 @@ the client will send both extensions. - SSL_get_quic_transport_version() returns the value set by - SSL_set_quic_transport_version(). - --SSL_get_peer_quic_transport_version() returns the version the that was -+SSL_get_peer_quic_transport_version() returns the version the that was - negotiated. - - SSL_set_quic_early_data_enabled() enables QUIC early data if a nonzero ---- a/ssl/statem/extensions_clnt.c -+++ b/ssl/statem/extensions_clnt.c -@@ -1969,7 +1969,7 @@ int tls_parse_stoc_early_data(SSL *s, PA - * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION - * per RFC9001 S4.6.1 - */ -- if (s->quic_method != NULL && max_early_data != 0xFFFFFFFF) { -+ if (SSL_IS_QUIC(s) && max_early_data != 0xFFFFFFFF) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_INVALID_MAX_EARLY_DATA); - return 0; - } ---- a/ssl/statem/statem_clnt.c -+++ b/ssl/statem/statem_clnt.c -@@ -906,7 +906,7 @@ int ossl_statem_client_construct_message - case TLS_ST_CW_END_OF_EARLY_DATA: - #ifndef OPENSSL_NO_QUIC - /* QUIC does not send EndOfEarlyData, RFC9001 S8.3 */ -- if (s->quic_method != NULL) { -+ if (SSL_IS_QUIC(s)) { - *confunc = NULL; - *mt = SSL3_MT_DUMMY; - break; diff --git a/openwrt/patch/openssl/quic/0040-QUIC-Error-when-non-empty-session_id-in-CH.patch b/openwrt/patch/openssl/quic/0040-QUIC-Error-when-non-empty-session_id-in-CH.patch deleted file mode 100644 index 03580aba6..000000000 --- a/openwrt/patch/openssl/quic/0040-QUIC-Error-when-non-empty-session_id-in-CH.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ed45a1c6b04d0a2f8b4cd3a43cc9f14de8f3c374 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Mon, 18 Oct 2021 16:54:31 -0400 -Subject: [PATCH 40/43] QUIC: Error when non-empty session_id in CH - ---- - ssl/statem/statem_srvr.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - ---- a/ssl/statem/statem_srvr.c -+++ b/ssl/statem/statem_srvr.c -@@ -1566,6 +1566,15 @@ MSG_PROCESS_RETURN tls_process_client_he - goto err; - } - } -+#ifndef OPENSSL_NO_QUIC -+ if (SSL_IS_QUIC(s)) { -+ /* Any other QUIC checks on ClientHello here */ -+ if (clienthello->session_id_len > 0) { -+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_LENGTH_MISMATCH); -+ goto err; -+ } -+ } -+#endif - } - - if (!PACKET_copy_all(&compression, clienthello->compressions, diff --git a/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch b/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch deleted file mode 100644 index 8d764eae5..000000000 --- a/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 53877ac198689b21a9fbdf71f0eeec5c15d550e4 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 19 Oct 2021 12:13:31 -0400 -Subject: [PATCH 41/43] QUIC: Update SSL_clear() to clear quic data - -Had to fixup tests because SSL_accept() eventually calls SSL_clear() and -it was removing the inital ClientHello sent via SSL_provide_quic_data() -from the server SSL. ---- - ssl/ssl_lib.c | 32 ++++++++++++++++++++++++++++++++ - test/helpers/ssltestlib.c | 5 ----- - test/sslapitest.c | 19 ++++++++++++++----- - 3 files changed, 46 insertions(+), 10 deletions(-) - ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -640,6 +640,38 @@ int SSL_clear(SSL *s) - s->shared_sigalgs = NULL; - s->shared_sigalgslen = 0; - -+#if !defined(OPENSSL_NO_QUIC) -+ OPENSSL_free(s->ext.peer_quic_transport_params_draft); -+ s->ext.peer_quic_transport_params_draft = NULL; -+ s->ext.peer_quic_transport_params_draft_len = 0; -+ OPENSSL_free(s->ext.peer_quic_transport_params); -+ s->ext.peer_quic_transport_params = NULL; -+ s->ext.peer_quic_transport_params_len = 0; -+ s->quic_read_level = ssl_encryption_initial; -+ s->quic_write_level = ssl_encryption_initial; -+ s->quic_latest_level_received = ssl_encryption_initial; -+ while (s->quic_input_data_head != NULL) { -+ QUIC_DATA *qd; -+ -+ qd = s->quic_input_data_head; -+ s->quic_input_data_head = qd->next; -+ OPENSSL_free(qd); -+ } -+ s->quic_input_data_tail = NULL; -+ BUF_MEM_free(s->quic_buf); -+ s->quic_buf = NULL; -+ s->quic_next_record_start = 0; -+ memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); -+ memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); -+ memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE); -+ /* -+ * CONFIG - DON'T CLEAR -+ * s->ext.quic_transport_params -+ * s->ext.quic_transport_params_len -+ * s->quic_transport_version -+ * s->quic_method = NULL; -+ */ -+#endif - /* - * Check to see if we were changed into a different method, if so, revert - * back. ---- a/test/helpers/ssltestlib.c -+++ b/test/helpers/ssltestlib.c -@@ -1166,11 +1166,6 @@ int create_ssl_connection(SSL *serverssl - if (!create_bare_ssl_connection(serverssl, clientssl, want, 1)) - return 0; - --#ifndef OPENSSL_NO_QUIC -- /* QUIC does not support SSL_read_ex */ -- if (SSL_is_quic(clientssl)) -- return 1; --#endif - /* - * We attempt to read some data on the client side which we expect to fail. - * This will ensure we have received the NewSessionTicket in TLSv1.3 where ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10832,6 +10832,7 @@ static int test_quic_api_version(int cln - static const char *client_str = "CLIENT"; - const uint8_t *peer_str; - size_t peer_str_len; -+ int err; - - TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); - -@@ -10854,8 +10855,10 @@ static int test_quic_api_version(int cln - || !TEST_true(SSL_set_app_data(clientssl, serverssl)) - || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) - || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) -- || !TEST_true(create_ssl_connection(serverssl, clientssl, -- SSL_ERROR_NONE)) -+ || !TEST_int_eq(err = SSL_accept(serverssl), -1) -+ || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) -+ || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, -+ SSL_ERROR_NONE, 0)) - || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) - || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) - || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) -@@ -10977,6 +10980,7 @@ static int quic_setupearly_data_test(SSL - { - static const char *server_str = "SERVER"; - static const char *client_str = "CLIENT"; -+ int err; - - if (*sctx == NULL - && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -11054,8 +11058,10 @@ static int quic_setupearly_data_test(SSL - if (sess == NULL) - return 1; - -- if (!TEST_true(create_ssl_connection(*serverssl, *clientssl, -- SSL_ERROR_NONE))) -+ if (!TEST_int_eq(err = SSL_accept(*serverssl), -1) -+ || !TEST_int_eq(SSL_get_error(*serverssl, err), SSL_ERROR_WANT_READ) -+ || !TEST_true(create_bare_ssl_connection(*serverssl, *clientssl, -+ SSL_ERROR_NONE, 0))) - return 0; - - /* Deal with two NewSessionTickets */ -@@ -11094,12 +11100,15 @@ static int test_quic_early_data(int tst) - SSL *clientssl = NULL, *serverssl = NULL; - int testresult = 0; - SSL_SESSION *sess = NULL; -+ int err; - - if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl, - &serverssl, &sess, tst))) - goto end; - -- if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) -+ if (!TEST_int_eq(err = SSL_accept(serverssl), -1) -+ || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) -+ || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0)) - || !TEST_true(SSL_get_early_data_status(serverssl))) - goto end; - diff --git a/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch b/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch deleted file mode 100644 index 885ec470e..000000000 --- a/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 87ce5b9478fbed0576abe1809a3eece9a5f28680 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Fri, 29 Oct 2021 14:15:06 -0400 -Subject: [PATCH 42/43] QUIC: Better SSL_clear() - -Undo SSL_clear() changes in test -Break apart SSL_clear() into SSL_clear_quic() and SSL_clear_not_quic() -In SSL_clear(), call both functions -In SSL_accept(), call SSL_clear_not_quic() -Don't make the new functions public. ---- - ssl/ssl_lib.c | 81 +++++++++++++++++++++++++++------------------ - ssl/ssl_local.h | 5 +++ - ssl/statem/statem.c | 5 +++ - test/sslapitest.c | 17 +++------- - 4 files changed, 63 insertions(+), 45 deletions(-) - ---- a/ssl/ssl_lib.c -+++ b/ssl/ssl_lib.c -@@ -581,8 +581,57 @@ static void clear_ciphers(SSL *s) - ssl_clear_hash_ctx(&s->write_hash); - } - -+#ifndef OPENSSL_NO_QUIC - int SSL_clear(SSL *s) - { -+ if (!SSL_clear_not_quic(s)) -+ return 0; -+ return SSL_clear_quic(s); -+} -+ -+int SSL_clear_quic(SSL *s) -+{ -+ OPENSSL_free(s->ext.peer_quic_transport_params_draft); -+ s->ext.peer_quic_transport_params_draft = NULL; -+ s->ext.peer_quic_transport_params_draft_len = 0; -+ OPENSSL_free(s->ext.peer_quic_transport_params); -+ s->ext.peer_quic_transport_params = NULL; -+ s->ext.peer_quic_transport_params_len = 0; -+ s->quic_read_level = ssl_encryption_initial; -+ s->quic_write_level = ssl_encryption_initial; -+ s->quic_latest_level_received = ssl_encryption_initial; -+ while (s->quic_input_data_head != NULL) { -+ QUIC_DATA *qd; -+ -+ qd = s->quic_input_data_head; -+ s->quic_input_data_head = qd->next; -+ OPENSSL_free(qd); -+ } -+ s->quic_input_data_tail = NULL; -+ BUF_MEM_free(s->quic_buf); -+ s->quic_buf = NULL; -+ s->quic_next_record_start = 0; -+ memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); -+ memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); -+ memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE); -+ /* -+ * CONFIG - DON'T CLEAR -+ * s->ext.quic_transport_params -+ * s->ext.quic_transport_params_len -+ * s->quic_transport_version -+ * s->quic_method = NULL; -+ */ -+ return 1; -+} -+#endif -+ -+/* Keep this conditional very local */ -+#ifndef OPENSSL_NO_QUIC -+int SSL_clear_not_quic(SSL *s) -+#else -+int SSL_clear(SSL *s) -+#endif -+{ - if (s->method == NULL) { - ERR_raise(ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED); - return 0; -@@ -640,38 +689,6 @@ int SSL_clear(SSL *s) - s->shared_sigalgs = NULL; - s->shared_sigalgslen = 0; - --#if !defined(OPENSSL_NO_QUIC) -- OPENSSL_free(s->ext.peer_quic_transport_params_draft); -- s->ext.peer_quic_transport_params_draft = NULL; -- s->ext.peer_quic_transport_params_draft_len = 0; -- OPENSSL_free(s->ext.peer_quic_transport_params); -- s->ext.peer_quic_transport_params = NULL; -- s->ext.peer_quic_transport_params_len = 0; -- s->quic_read_level = ssl_encryption_initial; -- s->quic_write_level = ssl_encryption_initial; -- s->quic_latest_level_received = ssl_encryption_initial; -- while (s->quic_input_data_head != NULL) { -- QUIC_DATA *qd; -- -- qd = s->quic_input_data_head; -- s->quic_input_data_head = qd->next; -- OPENSSL_free(qd); -- } -- s->quic_input_data_tail = NULL; -- BUF_MEM_free(s->quic_buf); -- s->quic_buf = NULL; -- s->quic_next_record_start = 0; -- memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); -- memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE); -- memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE); -- /* -- * CONFIG - DON'T CLEAR -- * s->ext.quic_transport_params -- * s->ext.quic_transport_params_len -- * s->quic_transport_version -- * s->quic_method = NULL; -- */ --#endif - /* - * Check to see if we were changed into a different method, if so, revert - * back. ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -2867,6 +2867,11 @@ void custom_exts_free(custom_ext_methods - - void ssl_comp_free_compression_methods_int(void); - -+#ifndef OPENSSL_NO_QUIC -+__owur int SSL_clear_not_quic(SSL *s); -+__owur int SSL_clear_quic(SSL *s); -+#endif -+ - /* ssl_mcnf.c */ - void ssl_ctx_system_config(SSL_CTX *ctx); - ---- a/ssl/statem/statem.c -+++ b/ssl/statem/statem.c -@@ -334,8 +334,13 @@ static int state_machine(SSL *s, int ser - * If we are stateless then we already called SSL_clear() - don't do - * it again and clear the STATELESS flag itself. - */ -+#ifndef OPENSSL_NO_QUIC -+ if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear_not_quic(s)) -+ return -1; -+#else - if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s)) - return -1; -+#endif - } - #ifndef OPENSSL_NO_SCTP - if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) { ---- a/test/sslapitest.c -+++ b/test/sslapitest.c -@@ -10832,7 +10832,6 @@ static int test_quic_api_version(int cln - static const char *client_str = "CLIENT"; - const uint8_t *peer_str; - size_t peer_str_len; -- int err; - - TEST_info("original clnt=0x%X, srvr=0x%X\n", clnt, srvr); - -@@ -10855,10 +10854,8 @@ static int test_quic_api_version(int cln - || !TEST_true(SSL_set_app_data(clientssl, serverssl)) - || !TEST_true(test_quic_api_set_versions(clientssl, clnt)) - || !TEST_true(test_quic_api_set_versions(serverssl, srvr)) -- || !TEST_int_eq(err = SSL_accept(serverssl), -1) -- || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) - || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, -- SSL_ERROR_NONE, 0)) -+ SSL_ERROR_NONE, 0)) - || !TEST_true(SSL_version(serverssl) == TLS1_3_VERSION) - || !TEST_true(SSL_version(clientssl) == TLS1_3_VERSION) - || !(TEST_int_eq(SSL_quic_read_level(clientssl), ssl_encryption_application)) -@@ -10980,7 +10977,6 @@ static int quic_setupearly_data_test(SSL - { - static const char *server_str = "SERVER"; - static const char *client_str = "CLIENT"; -- int err; - - if (*sctx == NULL - && (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), -@@ -11058,10 +11054,8 @@ static int quic_setupearly_data_test(SSL - if (sess == NULL) - return 1; - -- if (!TEST_int_eq(err = SSL_accept(*serverssl), -1) -- || !TEST_int_eq(SSL_get_error(*serverssl, err), SSL_ERROR_WANT_READ) -- || !TEST_true(create_bare_ssl_connection(*serverssl, *clientssl, -- SSL_ERROR_NONE, 0))) -+ if (!TEST_true(create_bare_ssl_connection(*serverssl, *clientssl, -+ SSL_ERROR_NONE, 0))) - return 0; - - /* Deal with two NewSessionTickets */ -@@ -11100,15 +11094,12 @@ static int test_quic_early_data(int tst) - SSL *clientssl = NULL, *serverssl = NULL; - int testresult = 0; - SSL_SESSION *sess = NULL; -- int err; - - if (!TEST_true(quic_setupearly_data_test(&cctx, &sctx, &clientssl, - &serverssl, &sess, tst))) - goto end; - -- if (!TEST_int_eq(err = SSL_accept(serverssl), -1) -- || !TEST_int_eq(SSL_get_error(serverssl, err), SSL_ERROR_WANT_READ) -- || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0)) -+ if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0)) - || !TEST_true(SSL_get_early_data_status(serverssl))) - goto end; - diff --git a/openwrt/patch/openssl/quic/0043-QUIC-Fix-extension-test.patch b/openwrt/patch/openssl/quic/0043-QUIC-Fix-extension-test.patch deleted file mode 100644 index 26f6dcf8a..000000000 --- a/openwrt/patch/openssl/quic/0043-QUIC-Fix-extension-test.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 83da964dc2da67fe779feddfc3a8d3baa9e446c5 Mon Sep 17 00:00:00 2001 -From: Todd Short -Date: Tue, 1 Nov 2022 12:55:46 -0400 -Subject: [PATCH 43/43] QUIC: Fix extension test - ---- - ssl/ssl_local.h | 4 ++-- - test/ext_internal_test.c | 7 +++++++ - 2 files changed, 9 insertions(+), 2 deletions(-) - ---- a/ssl/ssl_local.h -+++ b/ssl/ssl_local.h -@@ -773,8 +773,8 @@ typedef enum tlsext_index_en { - TLSEXT_IDX_cryptopro_bug, - TLSEXT_IDX_early_data, - TLSEXT_IDX_certificate_authorities, -- TLSEXT_IDX_quic_transport_params_draft, -- TLSEXT_IDX_quic_transport_params, -+ TLSEXT_IDX_quic_transport_parameters_draft, -+ TLSEXT_IDX_quic_transport_parameters, - TLSEXT_IDX_padding, - TLSEXT_IDX_psk, - /* Dummy index - must always be the last entry */ ---- a/test/ext_internal_test.c -+++ b/test/ext_internal_test.c -@@ -69,6 +69,13 @@ static EXT_LIST ext_list[] = { - EXT_ENTRY(cryptopro_bug), - EXT_ENTRY(early_data), - EXT_ENTRY(certificate_authorities), -+#ifndef OPENSSL_NO_QUIC -+ EXT_ENTRY(quic_transport_parameters_draft), -+ EXT_ENTRY(quic_transport_parameters), -+#else -+ EXT_EXCEPTION(quic_transport_parameters_draft), -+ EXT_EXCEPTION(quic_transport_parameters), -+#endif - EXT_ENTRY(padding), - EXT_ENTRY(psk), - EXT_END(num_builtins) diff --git a/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch b/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch deleted file mode 100644 index 33aaf0d00..000000000 --- a/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch +++ /dev/null @@ -1,5 +0,0 @@ ---- a/VERSION.dat -+++ b/VERSION.dat -@@ -5,1 +5,1 @@ --BUILD_METADATA= -+BUILD_METADATA=quic diff --git a/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch b/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch deleted file mode 100644 index 8df6a5891..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/acinclude.m4 -+++ b/acinclude.m4 -@@ -609,7 +609,7 @@ GMP_PROG_CC_WORKS_PART([$1], [long long - - #if defined (__GNUC__) && ! defined (__cplusplus) - typedef unsigned long long t1;typedef t1*t2; --void g(){} -+void g(int,t1 const*,t1,t2,t1 const*,int){} - void h(){} - static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0) - {t1 c,x,r;int i;if(v0){c=1;for(i=1;i -Date: Wed, 17 Jul 2024 17:46:42 +0800 -Subject: [PATCH] backends: fix string initialization error on gcc15 - -Signed-off-by: sbwml ---- - backends/i386_regs.c | 2 +- - backends/x86_64_regs.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/backends/i386_regs.c b/backends/i386_regs.c -index 7ec93bb..4bca1b1 100644 ---- a/backends/i386_regs.c -+++ b/backends/i386_regs.c -@@ -83,7 +83,7 @@ i386_register_info (Ebl *ebl __attribute__ ((unused)), - - switch (regno) - { -- static const char baseregs[][2] = -+ static const char baseregs[][3] = - { - "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "ip" - }; -diff --git a/backends/x86_64_regs.c b/backends/x86_64_regs.c -index ef987da..c92c862 100644 ---- a/backends/x86_64_regs.c -+++ b/backends/x86_64_regs.c -@@ -80,7 +80,7 @@ x86_64_register_info (Ebl *ebl __attribute__ ((unused)), - - switch (regno) - { -- static const char baseregs[][2] = -+ static const char baseregs[][3] = - { - "ax", "dx", "cx", "bx", "si", "di", "bp", "sp" - }; --- -2.43.5 - diff --git a/openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch b/openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch deleted file mode 100644 index 088930831..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/plugins/ssh-base/crypto/chacha.c b/plugins/ssh-base/crypto/chacha.c -index 182280d..cb4c5bf 100644 ---- a/plugins/ssh-base/crypto/chacha.c -+++ b/plugins/ssh-base/crypto/chacha.c -@@ -59,8 +59,8 @@ typedef struct chacha_ctx chacha_ctx; - a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); - --static const char sigma[16] = "expand 32-byte k"; --static const char tau[16] = "expand 16-byte k"; -+static const char sigma[18] = "expand 32-byte k"; -+static const char tau[18] = "expand 16-byte k"; - - void - chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) diff --git a/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch b/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch deleted file mode 100644 index 9724f4703..000000000 --- a/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/lib/crypt-port.h b/lib/crypt-port.h -index a707939..928a854 100644 ---- a/lib/crypt-port.h -+++ b/lib/crypt-port.h -@@ -473,7 +473,7 @@ make_failure_token (const char *setting, char *output, int size); - /* The base-64 encoding table used by most hashing methods. - (bcrypt uses a slightly different encoding.) Size 65 - because it's used as a C string in a few places. */ --extern const unsigned char ascii64[65]; -+extern const unsigned char ascii64[68]; - - /* Same table gets used with other names in various places. */ - #define b64t ((const char *) ascii64) -diff --git a/lib/util-base64.c b/lib/util-base64.c -index d55461f..fdd545d 100644 ---- a/lib/util-base64.c -+++ b/lib/util-base64.c -@@ -20,7 +20,7 @@ - - #include "crypt-port.h" - --const unsigned char ascii64[65] = -+const unsigned char ascii64[68] = - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - /* 0000000000111111111122222222223333333333444444444455555555556666 */ - /* 0123456789012345678901234567890123456789012345678901234567890123 */ diff --git a/openwrt/patch/openwrt-6.x/modules/bluetooth.mk b/openwrt/patch/openwrt-6.x/modules/bluetooth.mk new file mode 100644 index 000000000..f86763271 --- /dev/null +++ b/openwrt/patch/openwrt-6.x/modules/bluetooth.mk @@ -0,0 +1,165 @@ +# +# Copyright (C) 2006-2025 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +BLUETOOTH_MENU:=Bluetooth Support + +define KernelPackage/bluetooth + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=Bluetooth support + DEPENDS:=+kmod-crypto-hash +kmod-crypto-ecb +kmod-lib-crc16 +kmod-hid +kmod-crypto-cmac +kmod-regmap-core +kmod-crypto-ecdh + KCONFIG:= \ + CONFIG_BT \ + CONFIG_BT_BREDR=y \ + CONFIG_BT_DEBUGFS=n \ + CONFIG_BT_LE=y \ + CONFIG_BT_RFCOMM \ + CONFIG_BT_BNEP \ + CONFIG_BT_HIDP + $(call AddDepends/rfkill) + FILES:= \ + $(LINUX_DIR)/net/bluetooth/bluetooth.ko \ + $(LINUX_DIR)/net/bluetooth/rfcomm/rfcomm.ko \ + $(LINUX_DIR)/net/bluetooth/bnep/bnep.ko \ + $(LINUX_DIR)/net/bluetooth/hidp/hidp.ko + AUTOLOAD:=$(call AutoProbe,bluetooth rfcomm bnep hidp) +endef + +define KernelPackage/bluetooth/description + Kernel support for Bluetooth devices +endef + +$(eval $(call KernelPackage,bluetooth)) + + +define KernelPackage/hci-uart + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=Bluetooth HCI UART support + DEPENDS:=+kmod-bluetooth + KCONFIG:= \ + CONFIG_BT_HCIUART \ + CONFIG_BT_HCIUART_BCM=n \ + CONFIG_BT_HCIUART_INTEL=n \ + CONFIG_BT_HCIUART_H4 \ + CONFIG_BT_HCIUART_NOKIA=n + FILES:= \ + $(LINUX_DIR)/drivers/bluetooth/hci_uart.ko + AUTOLOAD:=$(call AutoProbe,hci_uart) +endef + +define KernelPackage/hci-uart/description + Kernel support for Bluetooth HCI UART devices +endef + +$(eval $(call KernelPackage,hci-uart)) + + +define KernelPackage/btusb + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=Bluetooth HCI USB support + DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-bluetooth +kmod-btmtk + KCONFIG:= \ + CONFIG_BT_HCIBTUSB \ + CONFIG_BT_HCIBTUSB_BCM=n \ + CONFIG_BT_HCIBTUSB_MTK=y \ + CONFIG_BT_HCIBTUSB_RTL=y + FILES:= \ + $(LINUX_DIR)/drivers/bluetooth/btusb.ko \ + $(LINUX_DIR)/drivers/bluetooth/btintel.ko \ + $(LINUX_DIR)/drivers/bluetooth/btrtl.ko + AUTOLOAD:=$(call AutoProbe,btusb) +endef + +define KernelPackage/btusb/description + Kernel support for USB Bluetooth HCI USB devices +endef + +$(eval $(call KernelPackage,btusb)) + + +define KernelPackage/btmtk + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=MTK Bluetooth support + HIDDEN:=1 + DEPENDS:=+kmod-bluetooth +USB_SUPPORT:kmod-usb-core + KCONFIG:=CONFIG_BT_MTK + FILES:=$(LINUX_DIR)/drivers/bluetooth/btmtk.ko +endef + +$(eval $(call KernelPackage,btmtk)) + + +define KernelPackage/ath3k + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=ATH3K Kernel Module support + DEPENDS:=+kmod-hci-uart +kmod-btusb +ar3k-firmware + KCONFIG:= \ + CONFIG_BT_ATH3K \ + CONFIG_BT_HCIUART_ATH3K=y + FILES:= \ + $(LINUX_DIR)/drivers/bluetooth/ath3k.ko + AUTOLOAD:=$(call AutoProbe,ath3k) +endef + +define KernelPackage/ath3k/description + Kernel support for ATH3K Module +endef + +$(eval $(call KernelPackage,ath3k)) + + +define KernelPackage/bluetooth-6lowpan + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=Bluetooth 6LoWPAN support + DEPENDS:=+kmod-6lowpan +kmod-bluetooth + KCONFIG:=CONFIG_BT_6LOWPAN + FILES:=$(LINUX_DIR)/net/bluetooth/bluetooth_6lowpan.ko + AUTOLOAD:=$(call AutoProbe,bluetooth_6lowpan) +endef + +define KernelPackage/bluetooth-6lowpan/description + Kernel support for 6LoWPAN over Bluetooth Low Energy devices +endef + +$(eval $(call KernelPackage,bluetooth-6lowpan)) + + +define KernelPackage/btmrvl + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=Marvell Bluetooth Kernel Module support + DEPENDS:=+kmod-mmc +kmod-bluetooth +mwifiex-sdio-firmware + KCONFIG:= \ + CONFIG_BT_MRVL \ + CONFIG_BT_MRVL_SDIO + FILES:= \ + $(LINUX_DIR)/drivers/bluetooth/btmrvl.ko \ + $(LINUX_DIR)/drivers/bluetooth/btmrvl_sdio.ko + AUTOLOAD:=$(call AutoProbe,btmrvl btmrvl_sdio) +endef + +define KernelPackage/btmrvl/description + Kernel support for Marvell SDIO Bluetooth Module +endef + +$(eval $(call KernelPackage,btmrvl)) + + +define KernelPackage/btsdio + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=Bluetooth HCI SDIO driver + DEPENDS:=+kmod-bluetooth +kmod-mmc + KCONFIG:= \ + CONFIG_BT_HCIBTSDIO + FILES:= \ + $(LINUX_DIR)/drivers/bluetooth/btsdio.ko + AUTOLOAD:=$(call AutoProbe,btsdio) +endef + +define KernelPackage/btsdio/description + Kernel support for Bluetooth device with SDIO interface +endef + +$(eval $(call KernelPackage,btsdio)) diff --git a/openwrt/patch/openwrt-6.x/modules/fs.mk b/openwrt/patch/openwrt-6.x/modules/fs.mk index b4b4c9209..4a6e77788 100644 --- a/openwrt/patch/openwrt-6.x/modules/fs.mk +++ b/openwrt/patch/openwrt-6.x/modules/fs.mk @@ -31,7 +31,7 @@ define KernelPackage/fs-afs SUBMENU:=$(FS_MENU) TITLE:=Andrew FileSystem client DEFAULT:=n - DEPENDS:=+kmod-rxrpc +kmod-dnsresolver +kmod-fs-fscache + DEPENDS:=+kmod-rxrpc +kmod-dnsresolver +kmod-fs-netfs KCONFIG:=\ CONFIG_AFS_FS=m \ CONFIG_AFS_DEBUG=n \ @@ -83,6 +83,22 @@ endef $(eval $(call KernelPackage,fs-btrfs)) +define KernelPackage/fs-cachefiles + SUBMENU:=$(FS_MENU) + TITLE:=Filesystem caching on files + DEPENDS:=kmod-fs-netfs + KCONFIG:=\ + CONFIG_CACHEFILES \ + CONFIG_CACHEFILES_DEBUG=n \ + CONFIG_CACHEFILES_ERROR_INJECTION=n \ + CONFIG_CACHEFILES_ONDEMAND=n + FILES:= $(LINUX_DIR)/fs/cachefiles/cachefiles.ko + AUTOLOAD:=$(call AutoLoad,30,cachefiles) +endef + +$(eval $(call KernelPackage,fs-cachefiles)) + + define KernelPackage/fs-smbfs-common SUBMENU:=$(FS_MENU) TITLE:=SMBFS common dependencies support @@ -258,30 +274,6 @@ endef $(eval $(call KernelPackage,fs-f2fs)) -define KernelPackage/fs-fscache - SUBMENU:=$(FS_MENU) - TITLE:=General filesystem local cache manager - DEPENDS:=+kmod-fs-netfs - KCONFIG:=\ - CONFIG_FSCACHE \ - CONFIG_FSCACHE_STATS=y \ - CONFIG_FSCACHE_HISTOGRAM=n \ - CONFIG_FSCACHE_DEBUG=n \ - CONFIG_FSCACHE_OBJECT_LIST=n \ - CONFIG_CACHEFILES \ - CONFIG_CACHEFILES_DEBUG=n \ - CONFIG_CACHEFILES_HISTOGRAM=n \ - CONFIG_CACHEFILES_ERROR_INJECTION=n \ - CONFIG_CACHEFILES_ONDEMAND=n - FILES:= \ - $(LINUX_DIR)/fs/fscache/fscache.ko \ - $(LINUX_DIR)/fs/cachefiles/cachefiles.ko - AUTOLOAD:=$(call AutoLoad,29,fscache cachefiles) -endef - -$(eval $(call KernelPackage,fs-fscache)) - - define KernelPackage/fs-hfs SUBMENU:=$(FS_MENU) TITLE:=HFS filesystem support @@ -421,7 +413,10 @@ $(eval $(call KernelPackage,fs-msdos)) define KernelPackage/fs-netfs SUBMENU:=$(FS_MENU) TITLE:=Network Filesystems support - KCONFIG:= CONFIG_NETFS_SUPPORT + KCONFIG:= \ + CONFIG_NETFS_SUPPORT \ + CONFIG_FSCACHE=y \ + CONFIG_FSCACHE_STATS=y FILES:=$(LINUX_DIR)/fs/netfs/netfs.ko AUTOLOAD:=$(call AutoLoad,28,netfs) endef @@ -429,6 +424,22 @@ endef $(eval $(call KernelPackage,fs-netfs)) +define KernelPackage/fs-nilfs2 + SUBMENU:=$(FS_MENU) + TITLE:=NILFS2 filesystem support + KCONFIG:=CONFIG_NILFS2_FS + FILES:=$(LINUX_DIR)/fs/nilfs2/nilfs2.ko + AUTOLOAD:=$(call AutoLoad,30,nilfs2) + $(call AddDepends/nls) +endef + +define KernelPackage/fs-nilfs2/description + Kernel module for NILFS2 filesystem support +endef + +$(eval $(call KernelPackage,fs-nilfs2)) + + define KernelPackage/fs-nfs SUBMENU:=$(FS_MENU) TITLE:=NFS filesystem client support @@ -525,7 +536,9 @@ define KernelPackage/fs-nfs-v4 KCONFIG:= \ CONFIG_NFS_V4=y FILES:= \ - $(LINUX_DIR)/fs/nfs/nfsv4.ko + $(LINUX_DIR)/fs/nfs/nfsv4.ko \ + $(LINUX_DIR)/fs/nfs/flexfilelayout/nfs_layout_flexfiles.ko \ + $(LINUX_DIR)/fs/nfs/filelayout/nfs_layout_nfsv41_files.ko AUTOLOAD:=$(call AutoLoad,41,nfsv4) endef @@ -560,24 +573,6 @@ endef $(eval $(call KernelPackage,fs-nfsd)) -define KernelPackage/fs-ntfs - SUBMENU:=$(FS_MENU) - TITLE:=NTFS filesystem read-only (old driver) support - DEPENDS:=@LINUX_6_6 - KCONFIG:=CONFIG_NTFS_FS - FILES:=$(LINUX_DIR)/fs/ntfs/ntfs.ko - AUTOLOAD:=$(call AutoLoad,30,ntfs) - $(call AddDepends/nls) -endef - -define KernelPackage/fs-ntfs/description - Kernel module for limited NTFS filesystem support. Support for writing - is extremely limited and disabled as a result. -endef - -$(eval $(call KernelPackage,fs-ntfs)) - - define KernelPackage/fs-ntfs3 SUBMENU:=$(FS_MENU) TITLE:=NTFS3 Read-Write file system support diff --git a/openwrt/patch/openwrt-6.x/modules/gpio.mk b/openwrt/patch/openwrt-6.x/modules/gpio.mk index fc6ab66ba..11a92192f 100644 --- a/openwrt/patch/openwrt-6.x/modules/gpio.mk +++ b/openwrt/patch/openwrt-6.x/modules/gpio.mk @@ -137,3 +137,20 @@ define KernelPackage/gpio-pcf857x/description endef $(eval $(call KernelPackage,gpio-pcf857x)) + + +define KernelPackage/gpio-pwm + SUBMENU:=$(GPIO_MENU) + DEPENDS:=@GPIO_SUPPORT @PWM_SUPPORT + TITLE:=PWM GPIO support + KCONFIG:=CONFIG_PWM_GPIO + FILES:=$(LINUX_DIR)/drivers/pwm/pwm-gpio.ko + AUTOLOAD:=$(call AutoProbe,pwm-gpio) +endef + +define KernelPackage/gpio-pwm/description + Generic PWM framework driver for software PWM toggling a GPIO pin from + kernel high-resolution timers. +endef + +$(eval $(call KernelPackage,gpio-pwm)) diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index c1014a417..bdc13f1e8 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -9,8 +9,8 @@ HWMON_MENU:=Hardware Monitoring Support define KernelPackage/hwmon-core SUBMENU:=$(HWMON_MENU) - TITLE:=Hardware monitoring support DEPENDS:=+kmod-i2c-core + TITLE:=Hardware monitoring support KCONFIG:= \ CONFIG_HWMON \ CONFIG_HWMON_DEBUG_CHIP=n @@ -402,21 +402,6 @@ endef $(eval $(call KernelPackage,hwmon-ltc4151)) -define KernelPackage/hwmon-max6642 - TITLE:=MAX6642 monitoring support - KCONFIG:=CONFIG_SENSORS_MAX6642 - FILES:=$(LINUX_DIR)/drivers/hwmon/max6642.ko - AUTOLOAD:=$(call AutoLoad,60,max6642 max6642) - $(call AddDepends/hwmon,+kmod-i2c-core) -endef - -define KernelPackage/hwmon-max6642/description - Kernel module for Maxim MAX6642 temperature monitor -endef - -$(eval $(call KernelPackage,hwmon-max6642)) - - define KernelPackage/hwmon-max6697 TITLE:=MAX6697 monitoring support KCONFIG:=CONFIG_SENSORS_MAX6697 @@ -746,3 +731,12 @@ endef $(eval $(call KernelPackage,hwmon-adcxx)) +define KernelPackage/polynomial + TITLE:=polynomial support + KCONFIG:=CONFIG_POLYNOMIAL + HIDDEN:=1 + FILES:=$(LINUX_DIR)/lib/polynomial.ko + AUTOLOAD:=$(call AutoProbe, polynomial) +endef + +$(eval $(call KernelPackage,polynomial)) diff --git a/openwrt/patch/openwrt-6.x/modules/i2c.mk b/openwrt/patch/openwrt-6.x/modules/i2c.mk index 9c506a2ad..e9e4e3965 100644 --- a/openwrt/patch/openwrt-6.x/modules/i2c.mk +++ b/openwrt/patch/openwrt-6.x/modules/i2c.mk @@ -116,17 +116,35 @@ I2C_DWPCI_MODULES:= \ define KernelPackage/i2c-designware-pci $(call i2c_defaults,$(I2C_DWPCI_MODULES),59) - TITLE:=Synopsys DesignWare PCI + TITLE:=Synopsys DesignWare I2C PCI DEPENDS:=@PCI_SUPPORT +kmod-i2c-designware-core +kmod-i2c-ccgs-ucsi endef define KernelPackage/i2c-designware-pci/description - Support for Synopsys DesignWare I2C controller. Only master mode is supported. + Support for Synopsys DesignWare I2C PCI controller. Only master mode is + supported. endef $(eval $(call KernelPackage,i2c-designware-pci)) +I2C_DWPLAT_MODULES:= \ + CONFIG_I2C_DESIGNWARE_PLATFORM:drivers/i2c/busses/i2c-designware-platform + +define KernelPackage/i2c-designware-platform + $(call i2c_defaults,$(I2C_DWPLAT_MODULES),59) + TITLE:=Synopsys DesignWare I2C Platform + DEPENDS:=+kmod-i2c-designware-core +endef + +define KernelPackage/i2c-designware-platform/description + Support for Synopsys DesignWare I2C Platform controller. Only master mode + is supported. +endef + +$(eval $(call KernelPackage,i2c-designware-platform)) + + I2C_GPIO_MODULES:= \ CONFIG_I2C_GPIO:drivers/i2c/busses/i2c-gpio @@ -144,13 +162,47 @@ endef $(eval $(call KernelPackage,i2c-gpio)) +I2C_HID_MODULES:= \ + CONFIG_I2C_HID_CORE:drivers/hid/i2c-hid/i2c-hid + +define KernelPackage/i2c-hid + $(call i2c_defaults,$(I2C_HID_MODULES),60) + TITLE:=I2C HID support + KCONFIG+= CONFIG_I2C_HID + DEPENDS:=+kmod-drm +kmod-hid + HIDDEN:=1 +endef + +$(eval $(call KernelPackage,i2c-hid)) + + +I2C_HID_ACPI_MODULES:= \ + CONFIG_I2C_HID_ACPI:drivers/hid/i2c-hid/i2c-hid-acpi + +define KernelPackage/i2c-hid-acpi + $(call i2c_defaults,$(I2C_HID_ACPI_MODULES),61) + TITLE:=HID over I2C transport layer ACPI driver + DEPENDS:=@TARGET_armsr_armv8||TARGET_loongarch64||TARGET_x86 +kmod-i2c-hid +endef + +define KernelPackage/i2c-hid-acpi/description + Support for keyboard, touchpad, touchscreen, or any + other HID based devices which is connected to your computer via I2C. + This driver supports ACPI-based systems. +endef + +$(eval $(call KernelPackage,i2c-hid-acpi)) + + I2C_I801_MODULES:= \ CONFIG_I2C_I801:drivers/i2c/busses/i2c-i801 define KernelPackage/i2c-i801 $(call i2c_defaults,$(I2C_I801_MODULES),59) TITLE:=Intel I801 and compatible I2C interfaces - DEPENDS:=@PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus +kmod-i2c-mux + DEPENDS:= \ + @PCI_SUPPORT @TARGET_x86 +kmod-i2c-core +kmod-i2c-smbus \ + PACKAGE_kmod-i2c-mux-gpio:kmod-i2c-mux-gpio endef define KernelPackage/i2c-i801/description @@ -236,6 +288,22 @@ endef $(eval $(call KernelPackage,i2c-mux-mlxcpld)) +I2C_MUX_PINCTRL_MODULES:= \ + CONFIG_I2C_MUX_PINCTRL:drivers/i2c/muxes/i2c-mux-pinctrl + +define KernelPackage/i2c-mux-pinctrl + $(call i2c_defaults,$(I2C_MUX_PINCTRL_MODULES),51) + TITLE:=Pinctrl-based I2C mux/switches + DEPENDS:=@PINCTRL_SUPPORT @USES_DEVICETREE +kmod-i2c-mux +endef + +define KernelPackage/i2c-mux-pinctrl/description + Kernel modules for Pinctrl-based I2C bus mux/switching devices +endef + +$(eval $(call KernelPackage,i2c-mux-pinctrl)) + + I2C_MUX_REG_MODULES:= \ CONFIG_I2C_MUX_REG:drivers/i2c/muxes/i2c-mux-reg diff --git a/openwrt/patch/openwrt-6.x/modules/iio.mk b/openwrt/patch/openwrt-6.x/modules/iio.mk index 3a5ae96f4..fcb67e0de 100644 --- a/openwrt/patch/openwrt-6.x/modules/iio.mk +++ b/openwrt/patch/openwrt-6.x/modules/iio.mk @@ -9,6 +9,7 @@ IIO_MENU:=Industrial I/O Modules define KernelPackage/iio-core SUBMENU:=$(IIO_MENU) TITLE:=Industrial IO core + DEPENDS:=+kmod-dma-buf KCONFIG:= \ CONFIG_IIO \ CONFIG_IIO_BUFFER=y \ @@ -46,6 +47,26 @@ endef $(eval $(call KernelPackage,iio-kfifo-buf)) +define KernelPackage/industrialio-backend + TITLE:=IIO Backend support + HIDDEN:=1 + KCONFIG=CONFIG_IIO_BACKEND + FILES:=$(LINUX_DIR)/drivers/iio/industrialio-backend.ko + AUTOLOAD:=$(call AutoProbe,industrialio-backend) + $(call AddDepends/iio) +endef + +define KernelPackage/industrialio-backend/description + Framework to handle complex IIO aggregate devices. The typical + architecture that can make use of this framework is to have one + device as the frontend device which can be "linked" against one or + multiple backend devices. The framework then makes it easy to get + and control such backend devices. +endef + +$(eval $(call KernelPackage,industrialio-backend)) + + define KernelPackage/industrialio-hw-consumer TITLE:=Provides a bonding way to an other device in hardware KCONFIG:=CONFIG_IIO_BUFFER_HW_CONSUMER @@ -128,6 +149,20 @@ endef $(eval $(call KernelPackage,iio-ads1015)) +define KernelPackage/iio-mcp3422 + TITLE:=Microchip MCP342x ADC driver + KCONFIG:=CONFIG_MCP3422 + FILES:=$(LINUX_DIR)/drivers/iio/adc/mcp3422.ko + AUTOLOAD:=$(call AutoProbe,mcp3422) + $(call AddDepends/iio, +kmod-i2c-core) +endef + +define KernelPackage/iio-mcp3422/description + Kernel module for the Microchip MCP342x I2C ADCs. +endef + +$(eval $(call KernelPackage,iio-mcp3422)) + define KernelPackage/iio-hmc5843 DEPENDS:=+kmod-i2c-core +kmod-regmap-i2c +kmod-industrialio-triggered-buffer TITLE:=Honeywell HMC58x3 Magnetometer @@ -298,6 +333,23 @@ endef $(eval $(call KernelPackage,iio-bmp280-spi)) + +define KernelPackage/iio-dps310 + TITLE:=DPS310/DPS368/DPS422 pressure temperatur sensor + DEPENDS:=+kmod-regmap-i2c + KCONFIG:=CONFIG_DPS310 + FILES:=$(LINUX_DIR)/drivers/iio/pressure/dps310.ko + AUTOLOAD:=$(call AutoProbe,dps310) + $(call AddDepends/iio) +endef +define KernelPackage/iio-dps310/description + Kernel module for Infineon DPS310/DPS368/DPS422 pressure and + temperature I2C sensor. +endef + +$(eval $(call KernelPackage,iio-dps310)) + + define KernelPackage/iio-htu21 DEPENDS:=+kmod-i2c-core TITLE:=HTU21 humidity & temperature sensor diff --git a/openwrt/patch/openwrt-6.x/modules/input.mk b/openwrt/patch/openwrt-6.x/modules/input.mk index 4eafc7d6b..b780c1c4b 100644 --- a/openwrt/patch/openwrt-6.x/modules/input.mk +++ b/openwrt/patch/openwrt-6.x/modules/input.mk @@ -37,6 +37,23 @@ endef $(eval $(call KernelPackage,hid-generic)) + +define KernelPackage/hid-alps + SUBMENU:=$(INPUT_MODULES_MENU) + TITLE:=Alps HID device support + DEPENDS:=+kmod-hid + KCONFIG:=CONFIG_HID_ALPS + FILES:=$(LINUX_DIR)/drivers/hid/hid-alps.ko + AUTOLOAD:=$(call AutoProbe,hid-alps) +endef + +define KernelPackage/hid-alps/description + Support for Alps I2C HID touchpads and StickPointer. +endef + +$(eval $(call KernelPackage,hid-alps)) + + define KernelPackage/input-core SUBMENU:=$(INPUT_MODULES_MENU) TITLE:=Input device core @@ -126,6 +143,23 @@ endef $(eval $(call KernelPackage,input-gpio-encoder)) +define KernelPackage/input-matrix-keypad + SUBMENU:=$(INPUT_MODULES_MENU) + TITLE:=GPIO matrix keypad support + DEPENDS:= @GPIO_SUPPORT +kmod-input-core +kmod-input-matrixkmap + KCONFIG:= \ + CONFIG_KEYBOARD_MATRIX \ + CONFIG_INPUT_KEYBOARD=y + FILES:=$(LINUX_DIR)/drivers/input/keyboard/matrix_keypad.ko + AUTOLOAD:=$(call AutoProbe,matrix_keypad,1) +endef + +define KernelPackage/input-matrix-keypad/description + Enable support for GPIO driven matrix keypad. +endef + +$(eval $(call KernelPackage,input-matrix-keypad)) + define KernelPackage/input-joydev SUBMENU:=$(INPUT_MODULES_MENU) TITLE:=Joystick device support @@ -229,3 +263,71 @@ define KernelPackage/input-uinput/description endef $(eval $(call KernelPackage,input-uinput)) + + +define KernelPackage/input-mouse-ps2 + SUBMENU:=$(INPUT_MODULES_MENU) + TITLE:=PS/2 mouse support + DEPENDS:=+kmod-i2c-core +kmod-input-core +kmod-input-serio-libps2 + KCONFIG:= \ + CONFIG_INPUT_MOUSE=y \ + CONFIG_MOUSE_PS2 \ + CONFIG_MOUSE_PS2_ALPS=y \ + CONFIG_MOUSE_PS2_BYD=y \ + CONFIG_MOUSE_PS2_LOGIPS2PP=y \ + CONFIG_MOUSE_PS2_SYNAPTICS=y \ + CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y \ + CONFIG_MOUSE_PS2_CYPRESS=y \ + CONFIG_MOUSE_PS2_LIFEBOOK=y \ + CONFIG_MOUSE_PS2_TRACKPOINT=y \ + CONFIG_MOUSE_PS2_ELANTECH=y \ + CONFIG_MOUSE_PS2_ELANTECH_SMBUS=y \ + CONFIG_MOUSE_PS2_SENTELIC=y \ + CONFIG_MOUSE_PS2_TOUCHKIT=y \ + CONFIG_MOUSE_PS2_OLPC=y \ + CONFIG_MOUSE_PS2_FOCALTECH=y \ + CONFIG_MOUSE_PS2_VMMOUSE=y + FILES:=$(LINUX_DIR)/drivers/input/mouse/psmouse.ko + AUTOLOAD:=$(call AutoProbe,psmouse) +endef + +define KernelPackage/input-mouse-ps2/description + Support for standard 2 or 3-button PS/2 mouse, as well as PS/2 + mice with wheels and extra buttons, Microsoft, Logitech or Genius + compatible, and many touchpads as well. +endef + +$(eval $(call KernelPackage,input-mouse-ps2)) + + +define KernelPackage/input-serio + SUBMENU:=$(INPUT_MODULES_MENU) + TITLE:=Serial I/O support + KCONFIG:= CONFIG_SERIO + FILES:=$(LINUX_DIR)/drivers/input/serio/serio.ko + AUTOLOAD:=$(call AutoProbe,serio,1) +endef + +define KernelPackage/input-serio/description + Kernel module to support input device that uses serial I/O to + communicate with the system +endef + +$(eval $(call KernelPackage,input-serio)) + + +define KernelPackage/input-serio-libps2 + SUBMENU:=$(INPUT_MODULES_MENU) + TITLE:=PS/2 Serial I/O support + DEPENDS:=+kmod-input-serio + KCONFIG:= CONFIG_SERIO_LIBPS2 + FILES:=$(LINUX_DIR)/drivers/input/serio/libps2.ko + AUTOLOAD:=$(call AutoProbe,libps2,1) +endef + +define KernelPackage/input-serio-libps2/description + Kernel module to support devices connected to a PS/2 port, such + as PS/2 mouse or standard AT keyboard. +endef + +$(eval $(call KernelPackage,input-serio-libps2)) diff --git a/openwrt/patch/openwrt-6.x/modules/leds.mk b/openwrt/patch/openwrt-6.x/modules/leds.mk index 98e6fc884..da1c0e461 100644 --- a/openwrt/patch/openwrt-6.x/modules/leds.mk +++ b/openwrt/patch/openwrt-6.x/modules/leds.mk @@ -24,6 +24,23 @@ $(eval $(call KernelPackage,leds-gpio)) LED_TRIGGER_DIR=$(LINUX_DIR)/drivers/leds/trigger +define KernelPackage/leds-group-multicolor + SUBMENU:=$(LEDS_MENU) + TITLE:=LEDs group multicolor support + KCONFIG:=CONFIG_LEDS_GROUP_MULTICOLOR + FILES:=$(LINUX_DIR)/drivers/leds/rgb/leds-group-multicolor.ko + AUTOLOAD:=$(call AutoProbe,leds-group-multicolor) +endef + +define KernelPackage/leds-group-multicolor/description + This option enables support for monochrome LEDs that are grouped + into multicolor LEDs which is useful in the case where LEDs of + different colors are physically grouped in a single multi-color LED + and driven by a controller that does not have multi-color support. +endef + +$(eval $(call KernelPackage,leds-group-multicolor)) + define KernelPackage/ledtrig-activity SUBMENU:=$(LEDS_MENU) TITLE:=LED Activity Trigger @@ -316,6 +333,23 @@ endef $(eval $(call KernelPackage,leds-lp55xx-common)) +define KernelPackage/leds-lp5523 + SUBMENU:=$(LEDS_MENU) + TITLE:=LED driver for LP5523/LP55231 controllers + DEPENDS:=+kmod-i2c-core +kmod-leds-lp55xx-common + KCONFIG:=CONFIG_LEDS_LP5523 + FILES:=$(LINUX_DIR)/drivers/leds/leds-lp5523.ko + AUTOLOAD:=$(call AutoLoad,60,leds-lp5523,1) +endef + +define KernelPackage/leds-lp5523/description + This option enables support for Texas Instruments LP5523/LP55231 + LED controllers. +endef + +$(eval $(call KernelPackage,leds-lp5523)) + + define KernelPackage/leds-lp5562 SUBMENU:=$(LEDS_MENU) TITLE:=LED driver for LP5562 controllers diff --git a/openwrt/patch/openwrt-6.x/modules/lib.mk b/openwrt/patch/openwrt-6.x/modules/lib.mk index e1512fbbb..c119ae05b 100644 --- a/openwrt/patch/openwrt-6.x/modules/lib.mk +++ b/openwrt/patch/openwrt-6.x/modules/lib.mk @@ -398,35 +398,6 @@ endef $(eval $(call KernelPackage,libwx)) -define KernelPackage/libie - SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Intel Ethernet library - KCONFIG:=CONFIG_LIBIE - FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie.ko - AUTOLOAD:=$(call AutoLoad,15,libie,1) -endef - -define KernelPackage/libie/description - Intel Ethernet library -endef - -$(eval $(call KernelPackage,libie)) - - -define KernelPackage/libeth - SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Intel Ethernet common library - KCONFIG:=CONFIG_LIBETH - FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libeth/libeth.ko - AUTOLOAD:=$(call AutoLoad,15,libeth,1) -endef - -define KernelPackage/libeth/description -endef - -$(eval $(call KernelPackage,libeth)) - - define KernelPackage/libie-fwlog SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=LIBIE_FWLOG diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index d80e69416..b104b657d 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -36,7 +36,7 @@ $(eval $(call KernelPackage,skge)) define KernelPackage/ag71xx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Atheros AR7XXX/AR9XXX ethernet mac support - DEPENDS:=@PCI_SUPPORT||TARGET_ath79 +kmod-phylink +kmod-mdio-devres +kmod-net-selftests + DEPENDS:=@TARGET_ath79 +kmod-phylink +kmod-mdio-devres +kmod-net-selftests KCONFIG:=CONFIG_AG71XX FILES:=$(LINUX_DIR)/drivers/net/ethernet/atheros/ag71xx.ko AUTOLOAD:=$(call AutoLoad,50,ag71xx,1) @@ -120,6 +120,37 @@ endef $(eval $(call KernelPackage,atl1e)) +define KernelPackage/libie + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Intel Ethernet library + DEPENDS:=+kmod-libeth + KCONFIG:=CONFIG_LIBIE + HIDDEN:=1 + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libie/libie.ko +endef + +define KernelPackage/libie/description + Intel Ethernet library +endef + +$(eval $(call KernelPackage,libie)) + + +define KernelPackage/libeth + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Common Intel Ethernet library + KCONFIG:=CONFIG_LIBETH + HIDDEN:=1 + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/libeth/libeth.ko +endef + +define KernelPackage/libeth/description + Common Intel Ethernet library +endef + +$(eval $(call KernelPackage,libeth)) + + define KernelPackage/libphy SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=PHY library @@ -235,6 +266,21 @@ endef $(eval $(call KernelPackage,phy-package)) +define KernelPackage/phy-maxlinear + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Maxlinear Ethernet PHY driver + KCONFIG:=CONFIG_MAXLINEAR_GPHY + DEPENDS:=+kmod-libphy +kmod-hwmon-core +kmod-polynomial + FILES:=$(LINUX_DIR)/drivers/net/phy/mxl-gpy.ko + AUTOLOAD:=$(call AutoLoad,18,mxl-gpy,1) +endef + +define KernelPackage/phy-maxlinear/description + Support Maxlinear Ethernet PHYs. +endef + +$(eval $(call KernelPackage,phy-maxlinear)) + define KernelPackage/phy-microchip SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Microchip Ethernet PHY driver @@ -339,6 +385,23 @@ endef $(eval $(call KernelPackage,phy-broadcom)) +define KernelPackage/phy-bcm7xxx + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Broadcom 7xxx SOCs internal PHYs + KCONFIG:=CONFIG_BCM7XXX_PHY + DEPENDS:=+kmod-libphy +kmod-phylib-broadcom + FILES:=$(LINUX_DIR)/drivers/net/phy/bcm7xxx.ko + AUTOLOAD:=$(call AutoLoad,18,bcm7xxx,1) +endef + +define KernelPackage/phy-bcm7xxx/description + Currently supports the BCM7366, BCM7439, BCM7445, and + 40nm and 65nm generation of BCM7xxx Set Top Box SoCs. +endef + +$(eval $(call KernelPackage,phy-bcm7xxx)) + + define KernelPackage/phy-bcm84881 SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Broadcom BCM84881 PHY driver @@ -473,6 +536,22 @@ endef $(eval $(call KernelPackage,phy-realtek)) +define KernelPackage/phy-rtl8261n + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Realtek RTL8261N NBASE-T PHY driver + KCONFIG:=CONFIG_RTL8261N_PHY + DEPENDS:=+kmod-libphy + FILES:=$(LINUX_DIR)/drivers/net/phy/rtl8261n/rtl8261n.ko + AUTOLOAD:=$(call AutoLoad,18,rtl8261n,1) +endef + +define KernelPackage/phy-rtl8261n/description + Supports the Realtek 8261N NBASE-T PHY. +endef + +$(eval $(call KernelPackage,phy-rtl8261n)) + + define KernelPackage/phy-smsc SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=SMSC PHY driver @@ -505,6 +584,23 @@ endef $(eval $(call KernelPackage,phy-vitesse)) +define KernelPackage/phy-aeonsemi-as21xxx + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Aeonsemi AS21xxx 10G Ethernet PHY + DEPENDS:=+aeonsemi-as21xxx-firmware +kmod-libphy + KCONFIG:=CONFIG_AS21XXX_PHY + FILES:= \ + $(LINUX_DIR)/drivers/net/phy/as21xxx.ko + AUTOLOAD:=$(call AutoLoad,18,as21xxx) +endef + +define KernelPackage/phy-aeonsemi-as21xxx/description + Kernel modules for Aeonsemi AS21x1x 10G Ethernet PHY +endef + +$(eval $(call KernelPackage,phy-aeonsemi-as21xxx)) + + define KernelPackage/phy-airoha-en8811h SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Airoha EN8811H 2.5G Ethernet PHY @@ -552,13 +648,29 @@ endef $(eval $(call KernelPackage,dsa)) +define KernelPackage/dsa-notag + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=DSA No-op tag driver + DEPENDS:=+kmod-dsa + KCONFIG:=CONFIG_NET_DSA_TAG_NONE + FILES:=$(LINUX_DIR)/net/dsa/tag_none.ko +endef + +define KernelPackage/dsa-notag/description + Kernel module support for switches which don't tag frames over the CPU port. +endef + +$(eval $(call KernelPackage,dsa-notag)) + + define KernelPackage/dsa-b53 SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Broadcom BCM53xx managed switch DSA support - DEPENDS:=+kmod-dsa + DEPENDS:=+kmod-dsa +kmod-dsa-notag KCONFIG:=CONFIG_B53 \ CONFIG_NET_DSA_TAG_BRCM \ CONFIG_NET_DSA_TAG_BRCM_LEGACY \ + CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS \ CONFIG_NET_DSA_TAG_BRCM_PREPEND FILES:= \ $(LINUX_DIR)/drivers/net/dsa/b53/b53_common.ko \ @@ -588,32 +700,38 @@ endef $(eval $(call KernelPackage,dsa-b53-mdio)) - -define KernelPackage/dsa-tag-dsa +define KernelPackage/dsa-mv88e6060 SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Marvell DSA type DSA and EDSA taggers - DEPENDS:=+kmod-dsa - KCONFIG:= CONFIG_NET_DSA_TAG_DSA_COMMON \ - CONFIG_NET_DSA_TAG_DSA \ - CONFIG_NET_DSA_TAG_EDSA - FILES:=$(LINUX_DIR)/net/dsa/tag_dsa.ko - AUTOLOAD:=$(call AutoLoad,40,tag_dsa,1) + TITLE:=Marvell MV88E6060 DSA Switch + DEPENDS:=+kmod-dsa +kmod-phy-marvell + KCONFIG:=CONFIG_NET_DSA_TAG_TRAILER \ + CONFIG_NET_DSA_MV88E6060 + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/mv88e6060.ko \ + $(LINUX_DIR)/net/dsa/tag_trailer.ko + AUTOLOAD:=$(call AutoLoad,41,mv88e6060,1) endef -define KernelPackage/dsa-tag-dsa/description - Kernel modules for Marvell DSA and EDSA tagging +define KernelPackage/dsa-mv88e6060/description + Kernel modules for MV88E6060 DSA switches endef -$(eval $(call KernelPackage,dsa-tag-dsa)) +$(eval $(call KernelPackage,dsa-mv88e6060)) define KernelPackage/dsa-mv88e6xxx SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Marvell MV88E6XXX DSA Switch - DEPENDS:=+kmod-dsa +kmod-ptp +kmod-phy-marvell +kmod-dsa-tag-dsa - KCONFIG:=CONFIG_NET_DSA_MV88E6XXX \ + DEPENDS:=+kmod-dsa +kmod-ptp +kmod-phy-marvell + KCONFIG:= \ + CONFIG_NET_DSA_TAG_DSA_COMMON \ + CONFIG_NET_DSA_TAG_DSA \ + CONFIG_NET_DSA_TAG_EDSA \ + CONFIG_NET_DSA_MV88E6XXX \ CONFIG_NET_DSA_MV88E6XXX_LEDS=y \ CONFIG_NET_DSA_MV88E6XXX_PTP=y - FILES:=$(LINUX_DIR)/drivers/net/dsa/mv88e6xxx/mv88e6xxx.ko + FILES:= \ + $(LINUX_DIR)/net/dsa/tag_dsa.ko \ + $(LINUX_DIR)/drivers/net/dsa/mv88e6xxx/mv88e6xxx.ko AUTOLOAD:=$(call AutoLoad,41,mv88e6xxx,1) endef @@ -643,6 +761,135 @@ endef $(eval $(call KernelPackage,dsa-qca8k)) + +define KernelPackage/dsa-realtek + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Realtek common module RTL83xx DSA switch family + DEPENDS:=+kmod-dsa +kmod-phy-realtek +kmod-regmap-core @!TARGET_x86 @!TARGET_bcm47xx @!TARGET_uml + KCONFIG:= \ + CONFIG_NET_DSA_REALTEK \ + CONFIG_NET_DSA_REALTEK_MDIO=y \ + CONFIG_NET_DSA_REALTEK_SMI=y + FILES:= $(LINUX_DIR)/drivers/net/dsa/realtek/realtek_dsa.ko +endef + +define KernelPackage/dsa-realtek/description + Common kernel module for Realtek RTL83xx DSA switch family +endef + +$(eval $(call KernelPackage,dsa-realtek)) + + +define KernelPackage/dsa-rtl8366rb + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Realtek RTL8366RB switch DSA support + DEPENDS:=+kmod-dsa-realtek @!TARGET_x86 @!TARGET_bcm47xx @!TARGET_uml + KCONFIG:= \ + CONFIG_NET_DSA_REALTEK_RTL8366RB \ + CONFIG_NET_DSA_REALTEK_RTL8366RB_LEDS=y \ + CONFIG_NET_DSA_TAG_RTL4_A + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/realtek/rtl8366.ko \ + $(LINUX_DIR)/net/dsa/tag_rtl4_a.ko + AUTOLOAD:=$(call AutoLoad,42,rtl8366,1) +endef + +define KernelPackage/dsa-rtl8366rb/description + DSA based kernel modules for the Realtek RTL8366RB switch family +endef + +$(eval $(call KernelPackage,dsa-rtl8366rb)) + + +define KernelPackage/dsa-rtl8365mb + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Realtek RTL8365MB switch DSA support + DEPENDS:=+kmod-dsa-realtek @!TARGET_x86 @!TARGET_bcm47xx @!TARGET_uml + KCONFIG:= \ + CONFIG_NET_DSA_REALTEK_RTL8365MB \ + CONFIG_NET_DSA_TAG_RTL8_4 + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/realtek/rtl8365mb.ko \ + $(LINUX_DIR)/net/dsa/tag_rtl8_4.ko + AUTOLOAD:=$(call AutoLoad,42,rtl8365mb,1) +endef + +define KernelPackage/dsa-rtl8365mb/description + DSA based kernel modules for the Realtek RTL8365MB switch family +endef + +$(eval $(call KernelPackage,dsa-rtl8365mb)) + + +define KernelPackage/dsa-ks8995 + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Micrel/Kendin KS8995 Ethernet DSA Switch + DEPENDS:=+kmod-dsa +kmod-dsa-notag + FILES:= $(LINUX_DIR)/drivers/net/dsa/ks8995.ko + KCONFIG:= CONFIG_NET_DSA_KS8995 \ + CONFIG_SPI=y \ + CONFIG_SPI_MASTER=y + AUTOLOAD:=$(call AutoLoad,42,ks8995) +endef + +define KernelPackage/dsa-ks8995/description + Kernel module for Micrel/Kendin KS8995 DSA switch +endef + +$(eval $(call KernelPackage,dsa-ks8995)) + + +define KernelPackage/dsa-vsc73xx + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Vitesse VSC73XX DSA switch family support + DEPENDS:=+kmod-dsa +kmod-phy-vitesse +kmod-fixed-phy + KCONFIG:= \ + CONFIG_NET_DSA_VITESSE_VSC73XX \ + CONFIG_NET_DSA_TAG_VSC73XX_8021Q + FILES:= \ + $(LINUX_DIR)/drivers/net/dsa/vitesse-vsc73xx-core.ko \ + $(LINUX_DIR)/net/dsa/tag_vsc73xx_8021q.ko +endef + +define KernelPackage/dsa-vsc73xx/description + Kernel modules for Vitesse VSC73XX switches +endef + +$(eval $(call KernelPackage,dsa-vsc73xx)) + + +define KernelPackage/dsa-vsc73xx-spi + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Vitesse VSC73XX SPI support + DEPENDS:=+kmod-dsa-vsc73xx + KCONFIG:= CONFIG_NET_DSA_VITESSE_VSC73XX_SPI + FILES:= $(LINUX_DIR)/drivers/net/dsa/vitesse-vsc73xx-spi.ko + AUTOLOAD:=$(call AutoProbe,vitesse-vsc73xx-spi) +endef + +define KernelPackage/dsa-vsc73xx-spi/description + Kernel modules for Vitesse VSC73XX switches using SPI +endef + +$(eval $(call KernelPackage,dsa-vsc73xx-spi)) + + +define KernelPackage/dsa-vsc73xx-platform + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Vitesse VSC73XX platform support + DEPENDS:=+kmod-dsa-vsc73xx + KCONFIG:= CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM + FILES:= $(LINUX_DIR)/drivers/net/dsa/vitesse-vsc73xx-platform.ko + AUTOLOAD:=$(call AutoProbe,vitesse-vsc73xx-platform) +endef + +define KernelPackage/dsa-vsc73xx-spi/description + Kernel modules for Vitesse VSC73XX switches using platform integration +endef + +$(eval $(call KernelPackage,dsa-vsc73xx-platform)) + + define KernelPackage/swconfig SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=switch configuration API @@ -971,7 +1218,7 @@ define KernelPackage/r8169 CONFIG_R8169 \ CONFIG_R8169_LEDS=y FILES:=$(LINUX_DIR)/drivers/net/ethernet/realtek/r8169.ko - AUTOLOAD:=$(call AutoProbe,r8169) + AUTOLOAD:=$(call AutoProbe,r8169,1) endef define KernelPackage/r8169/description @@ -1039,7 +1286,7 @@ define KernelPackage/e1000e DEPENDS:=@PCIE_SUPPORT +kmod-ptp KCONFIG:=CONFIG_E1000E FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/e1000e/e1000e.ko - AUTOLOAD:=$(call AutoProbe,e1000e) + AUTOLOAD:=$(call AutoProbe,e1000e,1) MODPARAMS.e1000e:= \ IntMode=1 \ InterruptThrottleRate=4,4,4,4,4,4,4,4 @@ -1093,9 +1340,9 @@ define KernelPackage/ixgbe TITLE:=Intel(R) 82598/82599 PCI-Express 10 Gigabit Ethernet support DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +kmod-mdio-devres +kmod-libie-fwlog +kmod-libie-adminq KCONFIG:=CONFIG_IXGBE \ - CONFIG_IXGBE_VXLAN=n \ CONFIG_IXGBE_HWMON=y \ - CONFIG_IXGBE_DCA=n + CONFIG_IXGBE_DCA=n \ + CONFIG_IXGBE_DCB=y FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/ixgbe/ixgbe.ko AUTOLOAD:=$(call AutoLoad,35,ixgbe) endef @@ -1112,7 +1359,6 @@ define KernelPackage/ixgbevf TITLE:=Intel(R) 82599 Virtual Function Ethernet support DEPENDS:=@PCI_SUPPORT +kmod-ixgbe KCONFIG:=CONFIG_IXGBEVF \ - CONFIG_IXGBE_VXLAN=n \ CONFIG_IXGBE_HWMON=y \ CONFIG_IXGBE_DCA=n FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/ixgbevf/ixgbevf.ko @@ -1131,11 +1377,9 @@ define KernelPackage/i40e TITLE:=Intel(R) Ethernet Controller XL710 Family support DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-ptp +kmod-hwmon-core +kmod-libphy +kmod-libie +kmod-libie-adminq KCONFIG:=CONFIG_I40E \ - CONFIG_I40E_VXLAN=n \ - CONFIG_I40E_HWMON=y \ - CONFIG_I40E_DCA=n + CONFIG_I40E_DCB=y FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/i40e/i40e.ko - AUTOLOAD:=$(call AutoProbe,i40e) + AUTOLOAD:=$(call AutoLoad,36,i40e,1) endef define KernelPackage/i40e/description @@ -1145,6 +1389,25 @@ endef $(eval $(call KernelPackage,i40e)) +define KernelPackage/ice + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Intel(R) Ethernet Controller E810 Series support + DEPENDS:=@PCI_SUPPORT +kmod-ptp +kmod-hwmon-core +kmod-libie +kmod-libie-adminq +kmod-libie-fwlog + KCONFIG:=CONFIG_ICE \ + CONFIG_ICE_HWMON=y \ + CONFIG_ICE_HWTS=n \ + CONFIG_ICE_SWITCHDEV=y + FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/ice/ice.ko + AUTOLOAD:=$(call AutoProbe,ice) +endef + +define KernelPackage/ice/description + Kernel modules for Intel(R) Ethernet Controller E810 Series +endef + +$(eval $(call KernelPackage,ice)) + + define KernelPackage/iavf SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Intel(R) Ethernet Adaptive Virtual Function support @@ -1154,7 +1417,6 @@ define KernelPackage/iavf CONFIG_IAVF FILES:= \ $(LINUX_DIR)/drivers/net/ethernet/intel/iavf/iavf.ko - AUTOLOAD:=$(call AutoProbe,i40evf iavf) AUTOLOAD:=$(call AutoProbe,iavf) endef @@ -1472,23 +1734,6 @@ endef $(eval $(call KernelPackage,vmxnet3)) -define KernelPackage/spi-ks8995 - SUBMENU:=$(NETWORK_DEVICES_MENU) - TITLE:=Micrel/Kendin KS8995 Ethernet switch control - FILES:=$(LINUX_DIR)/drivers/net/phy/spi_ks8995.ko - KCONFIG:=CONFIG_MICREL_KS8995MA \ - CONFIG_SPI=y \ - CONFIG_SPI_MASTER=y - AUTOLOAD:=$(call AutoLoad,50,spi_ks8995) -endef - -define KernelPackage/spi-ks8995/description - Kernel module for Micrel/Kendin KS8995 ethernet switch -endef - -$(eval $(call KernelPackage,spi-ks8995)) - - define KernelPackage/ethoc SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Opencore.org ethoc driver @@ -1547,7 +1792,7 @@ define KernelPackage/bnxt-en CONFIG_BNXT \ CONFIG_BNXT_SRIOV=y \ CONFIG_BNXT_FLOWER_OFFLOAD=y \ - CONFIG_BNXT_DCB=n \ + CONFIG_BNXT_DCB=y \ CONFIG_BNXT_HWMON=y AUTOLOAD:=$(call AutoProbe,bnxt_en) endef @@ -1589,11 +1834,11 @@ define KernelPackage/mlx4-core $(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx4/mlx4_core.ko \ $(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx4/mlx4_en.ko KCONFIG:= CONFIG_MLX4_EN \ - CONFIG_MLX4_EN_DCB=n \ + CONFIG_MLX4_EN_DCB=y \ CONFIG_MLX4_CORE=y \ CONFIG_MLX4_CORE_GEN2=y \ CONFIG_MLX4_DEBUG=n - AUTOLOAD:=$(call AutoLoad,36,mlx4_core mlx4_en,1) + AUTOLOAD:=$(call AutoLoad,45,mlx4_core mlx4_en,1) endef define KernelPackage/mlx4-core/description @@ -1609,7 +1854,7 @@ define KernelPackage/mlx5-core FILES:=$(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko KCONFIG:= CONFIG_MLX5_CORE \ CONFIG_MLX5_CORE_EN=y \ - CONFIG_MLX5_CORE_EN_DCB=n \ + CONFIG_MLX5_CORE_EN_DCB=y \ CONFIG_MLX5_CORE_IPOIB=n \ CONFIG_MLX5_EN_ARFS=n \ CONFIG_MLX5_EN_IPSEC=n \ @@ -1624,7 +1869,7 @@ define KernelPackage/mlx5-core CONFIG_MLX5_TC_CT=n \ CONFIG_MLX5_TLS=n \ CONFIG_MLX5_VFIO_PCI=n - AUTOLOAD:=$(call AutoLoad,36,mlx5_core,1) + AUTOLOAD:=$(call AutoLoad,45,mlx5_core,1) endef define KernelPackage/mlx5-core/description @@ -1727,9 +1972,7 @@ define KernelPackage/mlxsw-spectrum FILES:=$(LINUX_DIR)/drivers/net/ethernet/mellanox/mlxsw/mlxsw_spectrum.ko KCONFIG:= \ CONFIG_MLXSW_SPECTRUM \ - CONFIG_MLXSW_SPECTRUM_DCB=y \ - CONFIG_NET_SWITCHDEV=y \ - CONFIG_DCB=y + CONFIG_MLXSW_SPECTRUM_DCB=y AUTOLOAD:=$(call AutoProbe,mlxsw_spectrum) endef @@ -1738,6 +1981,13 @@ define KernelPackage/mlxsw-spectrum/description Spectrum/Spectrum-2/Spectrum-3/Spectrum-4 Ethernet Switch ASICs. endef +define KernelPackage/mlxsw-spectrum/install + $(INSTALL_DIR) $(1)/etc/hotplug.d/net + $(INSTALL_DATA) \ + ./files/hotplug-mlxsw-spectrum-port-names.sh \ + $(1)/etc/hotplug.d/net/10-mlxsw-spectrum-port-names +endef + $(eval $(call KernelPackage,mlxsw-spectrum)) @@ -1796,6 +2046,16 @@ endef $(eval $(call KernelPackage,sfp)) +define KernelPackage/pcs-qcom-ipq9574 + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Qualcomm IPQ9574 PCS driver + DEPENDS:=@TARGET_qualcommbe +kmod-phylink + KCONFIG:=CONFIG_PCS_QCOM_IPQ9574 + FILES:=$(LINUX_DIR)/drivers/net/pcs/pcs-qcom-ipq9574.ko + AUTOLOAD:=$(call AutoProbe,pcs-qcom-ipq9574) +endef + +$(eval $(call KernelPackage,pcs-qcom-ipq9574)) define KernelPackage/pcs-xpcs SUBMENU:=$(NETWORK_DEVICES_MENU) @@ -1881,6 +2141,27 @@ endef $(eval $(call KernelPackage,sfc-falcon)) +define KernelPackage/sfc-siena + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=Solarflare SFN5000/6000 'Siena' based card support + DEPENDS:=@PCI_SUPPORT +kmod-mdio +kmod-lib-crc32c +kmod-i2c-algo-bit +kmod-ptp +kmod-hwmon-core + KCONFIG:= \ + CONFIG_SFC_SIENA \ + CONFIG_SFC_SIENA_MTD=y \ + CONFIG_SFC_SIENA_MCDI_MON=y \ + CONFIG_SFC_SIENA_MCDI_LOGGING=y \ + CONFIG_SFC_SIENA_SRIOV=y + FILES:=$(LINUX_DIR)/drivers/net/ethernet/sfc/siena/sfc-siena.ko + AUTOLOAD:=$(call AutoProbe,sfc-siena) +endef + +define KernelPackage/sfc-siena/description + Solarflare SFN5000/6000 'Siena' based card support +endef + +$(eval $(call KernelPackage,sfc-siena)) + + define KernelPackage/wwan SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=WWAN Driver Core diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index 86a392b5f..6431e7507 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -778,22 +778,6 @@ endef $(eval $(call KernelPackage,sched-act-sample)) -define KernelPackage/sched-act-ipt - SUBMENU:=$(NETWORK_SUPPORT_MENU) - TITLE:=IPtables targets - DEPENDS:=+kmod-ipt-core +kmod-sched-core - KCONFIG:=CONFIG_NET_ACT_IPT - FILES:=$(LINUX_DIR)/net/sched/act_ipt.ko - AUTOLOAD:=$(call AutoProbe, act_ipt) -endef - -define KernelPackage/sched-act-ipt/description - Allows to invoke iptables targets after successful classification. -endef - -$(eval $(call KernelPackage,sched-act-ipt)) - - define KernelPackage/sched-act-vlan SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Traffic VLAN manipulation diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index 0a4dfc4a6..74cbefd75 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -27,122 +27,6 @@ endef $(eval $(call KernelPackage,6lowpan)) -define KernelPackage/bluetooth - SUBMENU:=$(OTHER_MENU) - TITLE:=Bluetooth support - DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-crypto-hash +kmod-crypto-ecb +kmod-lib-crc16 +kmod-hid +kmod-crypto-cmac +kmod-regmap-core +kmod-crypto-ecdh - KCONFIG:= \ - CONFIG_BT \ - CONFIG_BT_BREDR=y \ - CONFIG_BT_DEBUGFS=n \ - CONFIG_BT_LE=y \ - CONFIG_BT_RFCOMM \ - CONFIG_BT_BNEP \ - CONFIG_BT_HCIBTUSB \ - CONFIG_BT_HCIBTUSB_BCM=n \ - CONFIG_BT_HCIBTUSB_MTK=y \ - CONFIG_BT_HCIBTUSB_RTL=y \ - CONFIG_BT_HCIUART \ - CONFIG_BT_HCIUART_3WIRE=y \ - CONFIG_BT_HCIUART_BCM=n \ - CONFIG_BT_HCIUART_INTEL=n \ - CONFIG_BT_HCIUART_H4 \ - CONFIG_BT_HCIUART_NOKIA=n \ - CONFIG_BT_HCIUART_RTL=y \ - CONFIG_BT_HIDP - $(call AddDepends/rfkill) - FILES:= \ - $(LINUX_DIR)/net/bluetooth/bluetooth.ko \ - $(LINUX_DIR)/net/bluetooth/rfcomm/rfcomm.ko \ - $(LINUX_DIR)/net/bluetooth/bnep/bnep.ko \ - $(LINUX_DIR)/net/bluetooth/hidp/hidp.ko \ - $(LINUX_DIR)/drivers/bluetooth/hci_uart.ko \ - $(LINUX_DIR)/drivers/bluetooth/btusb.ko \ - $(LINUX_DIR)/drivers/bluetooth/btintel.ko \ - $(LINUX_DIR)/drivers/bluetooth/btrtl.ko \ - $(LINUX_DIR)/drivers/bluetooth/btmtk.ko - AUTOLOAD:=$(call AutoProbe,bluetooth rfcomm bnep hidp hci_uart btusb) -endef - -define KernelPackage/bluetooth/description - Kernel support for Bluetooth devices -endef - -$(eval $(call KernelPackage,bluetooth)) - -define KernelPackage/ath3k - SUBMENU:=$(OTHER_MENU) - TITLE:=ATH3K Kernel Module support - DEPENDS:=+kmod-bluetooth +ar3k-firmware - KCONFIG:= \ - CONFIG_BT_ATH3K \ - CONFIG_BT_HCIUART_ATH3K=y - FILES:= \ - $(LINUX_DIR)/drivers/bluetooth/ath3k.ko - AUTOLOAD:=$(call AutoProbe,ath3k) -endef - -define KernelPackage/ath3k/description - Kernel support for ATH3K Module -endef - -$(eval $(call KernelPackage,ath3k)) - - -define KernelPackage/bluetooth-6lowpan - SUBMENU:=$(OTHER_MENU) - TITLE:=Bluetooth 6LoWPAN support - DEPENDS:=+kmod-6lowpan +kmod-bluetooth - KCONFIG:=CONFIG_BT_6LOWPAN - FILES:=$(LINUX_DIR)/net/bluetooth/bluetooth_6lowpan.ko - AUTOLOAD:=$(call AutoProbe,bluetooth_6lowpan) -endef - -define KernelPackage/bluetooth-6lowpan/description - Kernel support for 6LoWPAN over Bluetooth Low Energy devices -endef - -$(eval $(call KernelPackage,bluetooth-6lowpan)) - - -define KernelPackage/btmrvl - SUBMENU:=$(OTHER_MENU) - TITLE:=Marvell Bluetooth Kernel Module support - DEPENDS:=+kmod-mmc +kmod-bluetooth +mwifiex-sdio-firmware - KCONFIG:= \ - CONFIG_BT_MRVL \ - CONFIG_BT_MRVL_SDIO - FILES:= \ - $(LINUX_DIR)/drivers/bluetooth/btmrvl.ko \ - $(LINUX_DIR)/drivers/bluetooth/btmrvl_sdio.ko - AUTOLOAD:=$(call AutoProbe,btmrvl btmrvl_sdio) -endef - -define KernelPackage/btmrvl/description - Kernel support for Marvell SDIO Bluetooth Module -endef - -$(eval $(call KernelPackage,btmrvl)) - - -define KernelPackage/btsdio - SUBMENU:=$(OTHER_MENU) - TITLE:=Bluetooth HCI SDIO driver - DEPENDS:=+kmod-bluetooth +kmod-mmc - KCONFIG:= \ - CONFIG_BT_HCIBTSDIO - FILES:= \ - $(LINUX_DIR)/drivers/bluetooth/btsdio.ko - AUTOLOAD:=$(call AutoProbe,btsdio) -endef - -define KernelPackage/btsdio/description - Kernel support for Bluetooth device with SDIO interface -endef - -$(eval $(call KernelPackage,btsdio)) - - define KernelPackage/dma-buf SUBMENU:=$(OTHER_MENU) TITLE:=DMA shared buffer support @@ -271,7 +155,9 @@ $(eval $(call KernelPackage,mlx_wdt)) define KernelPackage/mlxreg SUBMENU:=$(OTHER_MENU) TITLE:=Mellanox platform register access - DEPENDS:=@TARGET_x86 +kmod-i2c-mux-mlxcpld + DEPENDS:=@TARGET_x86 \ + +kmod-i2c-mux-mlxcpld \ + +kmod-i2c-mux-reg KCONFIG:= \ CONFIG_MELLANOX_PLATFORM=y \ CONFIG_MLX_PLATFORM \ @@ -679,10 +565,9 @@ $(eval $(call KernelPackage,reed-solomon)) define KernelPackage/serial-8250 SUBMENU:=$(OTHER_MENU) TITLE:=8250 UARTs + DEPENDS:=@!TARGET_uml KCONFIG:= CONFIG_SERIAL_8250 \ CONFIG_SERIAL_8250_PCI \ - CONFIG_SERIAL_8250_NR_UARTS=16 \ - CONFIG_SERIAL_8250_RUNTIME_UARTS=16 \ CONFIG_SERIAL_8250_EXTENDED=y \ CONFIG_SERIAL_8250_MANY_PORTS=y \ CONFIG_SERIAL_8250_SHARE_IRQ=y \ @@ -700,6 +585,31 @@ define KernelPackage/serial-8250/description Kernel module for 8250 UART based serial ports endef +define KernelPackage/serial-8250/config +menu "Configuration" + depends on PACKAGE_kmod-serial-8250 + +config KERNEL_SERIAL_8250_NR_UARTS + int "Maximum number of 8250/16550 serial ports" + default "16" + help + Set this to the number of serial ports you want the driver + to support. This includes any ports discovered via ACPI or + PCI enumeration and any ports that may be added at run-time + via hot-plug, or any ISA multi-port serial cards. + +config KERNEL_SERIAL_8250_RUNTIME_UARTS + int "Number of 8250/16550 serial ports to register at runtime" + range 0 KERNEL_SERIAL_8250_NR_UARTS + default "16" + help + Set this to the maximum number of serial ports you want + the kernel to register at boot time. This can be overridden + with the module parameter "nr_uarts", or boot-time parameter + 8250.nr_uarts +endmenu +endef + $(eval $(call KernelPackage,serial-8250)) @@ -739,7 +649,7 @@ $(eval $(call KernelPackage,regmap-core)) define KernelPackage/regmap-spi SUBMENU:=$(OTHER_MENU) TITLE:=SPI register map support - DEPENDS:=+kmod-regmap-core + DEPENDS:=+kmod-regmap-core @!TARGET_uml HIDDEN:=1 KCONFIG:=CONFIG_REGMAP_SPI \ CONFIG_SPI=y @@ -1065,7 +975,7 @@ $(eval $(call KernelPackage,tpm)) define KernelPackage/tpm-tis SUBMENU:=$(OTHER_MENU) TITLE:=TPM TIS 1.2 Interface / TPM 2.0 FIFO Interface - DEPENDS:= @TARGET_x86 +kmod-tpm + DEPENDS:= @(TARGET_x86||TARGET_armsr) +kmod-tpm KCONFIG:= CONFIG_TCG_TIS FILES:= \ $(LINUX_DIR)/drivers/char/tpm/tpm_tis.ko \ @@ -1160,3 +1070,20 @@ define KernelPackage/mhi-pci-generic/description endef $(eval $(call KernelPackage,mhi-pci-generic)) + + +define KernelPackage/regulator-userspace-consumer + SUBMENU:=$(OTHER_MENU) + TITLE:=Userspace regulator consumer support + KCONFIG:=CONFIG_REGULATOR_USERSPACE_CONSUMER + FILES:=$(LINUX_DIR)/drivers/regulator/userspace-consumer.ko + AUTOLOAD:=$(call AutoLoad,10,userspace-consumer,1) +endef + +define KernelPackage/regulator-userspace-consumer/description + There are some classes of devices that are controlled entirely + from user space. Userspace consumer driver provides ability to + control power supplies for such devices. +endef + +$(eval $(call KernelPackage,regulator-userspace-consumer)) diff --git a/openwrt/patch/openwrt-6.x/modules/rtc.mk b/openwrt/patch/openwrt-6.x/modules/rtc.mk index d65608c17..852290f9d 100644 --- a/openwrt/patch/openwrt-6.x/modules/rtc.mk +++ b/openwrt/patch/openwrt-6.x/modules/rtc.mk @@ -7,6 +7,24 @@ RTC_MENU:=RTC Real-Time Clock Support +define KernelPackage/rtc-bq32k + SUBMENU:=$(RTC_MENU) + TITLE:=Texas Instruments BQ32000 RTC support + DEFAULT:=m if ALL_KMODS && RTC_SUPPORT + DEPENDS:=+kmod-i2c-core + KCONFIG:=CONFIG_RTC_DRV_BQ32K \ + CONFIG_RTC_CLASS=y + FILES:=$(LINUX_DIR)/drivers/rtc/rtc-bq32k.ko + AUTOLOAD:=$(call AutoProbe,rtc-bq32k) +endef + +define KernelPackage/rtc-bq32k/description + Kernel module for Texas Instruments BQ32000 I2C RTC. +endef + +$(eval $(call KernelPackage,rtc-bq32k)) + + define KernelPackage/rtc-ds1307 SUBMENU:=$(RTC_MENU) TITLE:=Dallas/Maxim DS1307 (and compatible) RTC support diff --git a/openwrt/patch/openwrt-6.x/modules/spi.mk b/openwrt/patch/openwrt-6.x/modules/spi.mk index 78a1c8a03..5e8ab03b1 100644 --- a/openwrt/patch/openwrt-6.x/modules/spi.mk +++ b/openwrt/patch/openwrt-6.x/modules/spi.mk @@ -73,3 +73,41 @@ define KernelPackage/spi-dev/description endef $(eval $(call KernelPackage,spi-dev)) + + +define KernelPackage/spi-dw + SUBMENU:=$(SPI_MENU) + TITLE:=DesignWare SPI controller driver (core) + KCONFIG:=\ + CONFIG_SPI=y \ + CONFIG_SPI_DESIGNWARE \ + CONFIG_SPI_DYNAMIC=y \ + CONFIG_SPI_MASTER=y + FILES:=\ + $(LINUX_DIR)/drivers/spi/spi-dw.ko + AUTOLOAD:=$(call AutoProbe,spi-dw) +endef + +define KernelPackage/spi-dw/description + This package contains the DesignWare SPI core driver. +endef + +$(eval $(call KernelPackage,spi-dw)) + + +define KernelPackage/spi-dw-mmio + SUBMENU:=$(SPI_MENU) + TITLE:=DesignWare SPI controller driver (MMIO) + DEPENDS:=+kmod-spi-dw + KCONFIG:=\ + CONFIG_SPI_DW_MMIO + FILES:=\ + $(LINUX_DIR)/drivers/spi/spi-dw-mmio.ko + AUTOLOAD:=$(call AutoProbe,spi-dw-mmio) +endef + +define KernelPackage/spi-dw-mmio/description + This package contains the DesignWare SPI MMIO driver. +endef + +$(eval $(call KernelPackage,spi-dw-mmio)) diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index 92c092c1b..cffcd329b 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -11,15 +11,24 @@ USBNET_DIR:=net/usb USBHID_DIR?=hid/usbhid USBINPUT_DIR?=input/misc +define KernelPackage/usb-common + TITLE:=USB common + HIDDEN:=1 + DEPENDS:=@(USB_SUPPORT||USB_GADGET_SUPPORT) + KCONFIG:=CONFIG_USB_COMMON + FILES:=$(LINUX_DIR)/drivers/usb/common/usb-common.ko + AUTOLOAD:=$(call AutoLoad,20,usb-common,1) +endef + +$(eval $(call KernelPackage,usb-common)) + define KernelPackage/usb-core SUBMENU:=$(USB_MENU) TITLE:=Support for USB - DEPENDS:=@USB_SUPPORT + DEPENDS:=@USB_SUPPORT +USB_SUPPORT:kmod-usb-common KCONFIG:=CONFIG_USB CONFIG_XPS_USB_HCD_XILINX=n CONFIG_USB_FHCI_HCD=n - FILES:= \ - $(LINUX_DIR)/drivers/usb/core/usbcore.ko \ - $(LINUX_DIR)/drivers/usb/common/usb-common.ko - AUTOLOAD:=$(call AutoLoad,20,usb-common usbcore,1) + FILES:=$(LINUX_DIR)/drivers/usb/core/usbcore.ko + AUTOLOAD:=$(call AutoLoad,20,usbcore,1) $(call AddDepends/nls) endef @@ -90,14 +99,15 @@ $(eval $(call KernelPackage,phy-ath79-usb)) define KernelPackage/usb-gadget + SUBMENU:=$(USB_MENU) TITLE:=USB Gadget support KCONFIG:=CONFIG_USB_GADGET HIDDEN:=1 FILES:=\ $(LINUX_DIR)/drivers/usb/gadget/udc/udc-core.ko AUTOLOAD:=$(call AutoLoad,21,udc-core,1) - DEPENDS:=@USB_GADGET_SUPPORT - $(call AddDepends/usb) + DEPENDS:=@USB_GADGET_SUPPORT +kmod-usb-common + $(call AddDepends/nls) endef define KernelPackage/usb-gadget/description @@ -106,14 +116,20 @@ endef $(eval $(call KernelPackage,usb-gadget)) + +define AddDepends/usbgadget + SUBMENU:=$(USB_MENU) + DEPENDS+=+kmod-usb-gadget $(1) +endef + + define KernelPackage/usb-lib-composite TITLE:=USB lib composite KCONFIG:=CONFIG_USB_LIBCOMPOSITE - DEPENDS:=+kmod-usb-gadget +kmod-fs-configfs HIDDEN:=1 FILES:=$(LINUX_DIR)/drivers/usb/gadget/libcomposite.ko AUTOLOAD:=$(call AutoLoad,50,libcomposite) - $(call AddDepends/usb) + $(call AddDepends/usbgadget,+kmod-fs-configfs) endef define KernelPackage/usb-lib-composite/description @@ -125,12 +141,11 @@ $(eval $(call KernelPackage,usb-lib-composite)) define KernelPackage/usb-gadget-hid TITLE:=USB HID Gadget Support KCONFIG:=CONFIG_USB_G_HID - DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite FILES:= \ $(LINUX_DIR)/drivers/usb/gadget/legacy/g_hid.ko \ $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_hid.ko AUTOLOAD:=$(call AutoLoad,52,usb_f_hid) - $(call AddDepends/usb) + $(call AddDepends/usbgadget,+kmod-usb-lib-composite) endef define KernelPackage/usb-gadget-hid/description @@ -145,9 +160,8 @@ define KernelPackage/usb-gadget-ehci-debug CONFIG_USB_G_DBGP \ CONFIG_USB_G_DBGP_SERIAL=y \ CONFIG_USB_G_DBGP_PRINTK=n - DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite +kmod-usb-gadget-serial FILES:=$(LINUX_DIR)/drivers/usb/gadget/legacy/g_dbgp.ko - $(call AddDepends/usb) + $(call AddDepends/usbgadget,+kmod-usb-lib-composite +kmod-usb-gadget-serial) endef define KernelPackage/usb-gadget-ehci-debug/description @@ -162,7 +176,6 @@ define KernelPackage/usb-gadget-eth CONFIG_USB_ETH \ CONFIG_USB_ETH_RNDIS=y \ CONFIG_USB_ETH_EEM=n - DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite FILES:= \ $(LINUX_DIR)/drivers/usb/gadget/function/u_ether.ko \ $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_ecm.ko \ @@ -170,7 +183,7 @@ define KernelPackage/usb-gadget-eth $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_rndis.ko \ $(LINUX_DIR)/drivers/usb/gadget/legacy/g_ether.ko AUTOLOAD:=$(call AutoLoad,52,usb_f_ecm) - $(call AddDepends/usb) + $(call AddDepends/usbgadget,+kmod-usb-lib-composite) endef define KernelPackage/usb-gadget-eth/description @@ -182,13 +195,11 @@ $(eval $(call KernelPackage,usb-gadget-eth)) define KernelPackage/usb-gadget-ncm TITLE:=USB Network Control Model (NCM) Gadget support KCONFIG:=CONFIG_USB_G_NCM - DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite \ - +kmod-usb-gadget-eth FILES:= \ $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_ncm.ko \ $(LINUX_DIR)/drivers/usb/gadget/legacy/g_ncm.ko AUTOLOAD:=$(call AutoLoad,52,usb_f_ncm) - $(call AddDepends/usb) + $(call AddDepends/usbgadget,+kmod-usb-lib-composite +kmod-usb-gadget-eth) endef define KernelPackage/usb-gadget-ncm/description @@ -200,7 +211,6 @@ $(eval $(call KernelPackage,usb-gadget-ncm)) define KernelPackage/usb-gadget-serial TITLE:=USB Serial Gadget support KCONFIG:=CONFIG_USB_G_SERIAL - DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite FILES:= \ $(LINUX_DIR)/drivers/usb/gadget/function/u_serial.ko \ $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_acm.ko \ @@ -208,7 +218,7 @@ define KernelPackage/usb-gadget-serial $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_serial.ko \ $(LINUX_DIR)/drivers/usb/gadget/legacy/g_serial.ko AUTOLOAD:=$(call AutoLoad,52,usb_f_acm) - $(call AddDepends/usb) + $(call AddDepends/usbgadget,+kmod-usb-lib-composite) endef define KernelPackage/usb-gadget-serial/description @@ -220,12 +230,11 @@ $(eval $(call KernelPackage,usb-gadget-serial)) define KernelPackage/usb-gadget-mass-storage TITLE:=USB Mass Storage support KCONFIG:=CONFIG_USB_MASS_STORAGE - DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite FILES:= \ $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_mass_storage.ko \ $(LINUX_DIR)/drivers/usb/gadget/legacy/g_mass_storage.ko AUTOLOAD:=$(call AutoLoad,52,usb_f_mass_storage) - $(call AddDepends/usb) + $(call AddDepends/usbgadget,+kmod-usb-lib-composite) endef define KernelPackage/usb-gadget-mass-storage/description @@ -237,10 +246,11 @@ $(eval $(call KernelPackage,usb-gadget-mass-storage)) define KernelPackage/usb-gadget-cdc-composite TITLE:= USB CDC Composite (Ethernet + ACM) KCONFIG:=CONFIG_USB_CDC_COMPOSITE - DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite \ - +kmod-usb-gadget-eth +kmod-usb-gadget-serial FILES:= $(LINUX_DIR)/drivers/usb/gadget/legacy/g_cdc.ko - $(call AddDepends/usb) + $(call AddDepends/usbgadget, \ + +kmod-usb-lib-composite \ + +kmod-usb-gadget-eth \ + +kmod-usb-gadget-serial) endef define KernelPackage/usb-gadget-cdc-composite/description @@ -460,13 +470,15 @@ $(eval $(call KernelPackage,usb-dwc2-pci)) define KernelPackage/usb-cdns + SUBMENU:=$(USB_MENU) TITLE:=Cadence USB USB controller driver - DEPENDS:=+USB_GADGET_SUPPORT:kmod-usb-gadget +kmod-usb-roles + DEPENDS:=+USB_GADGET_SUPPORT:kmod-usb-gadget \ + +USB_SUPPORT:kmod-usb-core \ + +kmod-usb-roles KCONFIG:= \ CONFIG_USB_CDNS_SUPPORT FILES:= $(LINUX_DIR)/drivers/usb/cdns3/cdns-usb-common.ko AUTOLOAD:=$(call AutoLoad,50,cdns-usb-common,1) - $(call AddDepends/usb) endef define KernelPackage/usb-cdns/description @@ -478,15 +490,15 @@ $(eval $(call KernelPackage,usb-cdns)) define KernelPackage/usb-cdns3 + SUBMENU:=$(USB_MENU) TITLE:=Cadence USB3 USB controller driver DEPENDS:=+kmod-usb-cdns KCONFIG:= \ CONFIG_USB_CDNS3 \ - CONFIG_USB_CDNS3_GADGET=y \ - CONFIG_USB_CDNS3_HOST=y + CONFIG_USB_CDNS3_GADGET=$(if $(CONFIG_USB_GADGET_SUPPORT),y,n) \ + CONFIG_USB_CDNS3_HOST=$(if $(CONFIG_USB_SUPPORT),y,n) FILES:= $(LINUX_DIR)/drivers/usb/cdns3/cdns3.ko AUTOLOAD:=$(call AutoLoad,54,cdns3,1) - $(call AddDepends/usb) endef define KernelPackage/usb-cdns3/description @@ -498,17 +510,28 @@ $(eval $(call KernelPackage,usb-cdns3)) define KernelPackage/usb-dwc3 + SUBMENU:=$(USB_MENU) TITLE:=DWC3 USB controller driver + DEPENDS:=+USB_GADGET_SUPPORT:kmod-usb-gadget \ + +USB_SUPPORT:kmod-usb-core \ + +kmod-usb-roles KCONFIG:= \ CONFIG_USB_DWC3 \ - CONFIG_USB_DWC3_HOST=y \ - CONFIG_USB_DWC3_GADGET=n \ - CONFIG_USB_DWC3_DUAL_ROLE=n \ CONFIG_USB_DWC3_DEBUG=n \ CONFIG_USB_DWC3_VERBOSE=n +ifeq ($(CONFIG_USB_SUPPORT)$(CONFIG_USB_GADGET_SUPPORT),yy) + KCONFIG+= \ + CONFIG_USB_DWC3_HOST=n \ + CONFIG_USB_DWC3_GADGET=n \ + CONFIG_USB_DWC3_DUAL_ROLE=y +else + KCONFIG+= \ + CONFIG_USB_DWC3_HOST=$(if $(CONFIG_USB_SUPPORT),y,n) \ + CONFIG_USB_DWC3_GADGET=$(if $(CONFIG_USB_GADGET_SUPPORT),y,n) \ + CONFIG_USB_DWC3_DUAL_ROLE=n +endif FILES:= $(LINUX_DIR)/drivers/usb/dwc3/dwc3.ko AUTOLOAD:=$(call AutoLoad,54,dwc3,1) - $(call AddDepends/usb) endef define KernelPackage/usb-dwc3/description @@ -538,7 +561,7 @@ $(eval $(call KernelPackage,usb-dwc3-octeon)) define KernelPackage/usb-dwc3-qcom TITLE:=DWC3 Qualcomm USB driver - DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_qualcommax) +kmod-usb-dwc3 + DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_qualcommax||TARGET_qualcommbe) +kmod-usb-dwc3 KCONFIG:= CONFIG_USB_DWC3_QCOM FILES:= $(LINUX_DIR)/drivers/usb/dwc3/dwc3-qcom.ko AUTOLOAD:=$(call AutoLoad,53,dwc3-qcom,1) @@ -1193,8 +1216,7 @@ $(eval $(call KernelPackage,usb-atm-cxacru)) define KernelPackage/usb-net TITLE:=Kernel modules for USB-to-Ethernet convertors DEPENDS:=+kmod-mii - KCONFIG:=CONFIG_USB_USBNET \ - CONFIG_USB_NET_DRIVERS + KCONFIG:=CONFIG_USB_USBNET AUTOLOAD:=$(call AutoProbe,usbnet) FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/usbnet.ko $(call AddDepends/usb) @@ -1467,11 +1489,11 @@ $(eval $(call KernelPackage,usb-net-rtl8150)) define KernelPackage/usb-net-rtl8152 TITLE:=Kernel module for USB-to-Ethernet Realtek convertors - DEPENDS:=+r8152-firmware +kmod-crypto-sha256 +kmod-usb-net-cdc-ncm + DEPENDS:=+r8152-firmware +kmod-crypto-sha256 +kmod-mii +kmod-libphy KCONFIG:=CONFIG_USB_RTL8152 FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/r8152.ko AUTOLOAD:=$(call AutoProbe,r8152) - $(call AddDepends/usb-net) + $(call AddDepends/usb) endef define KernelPackage/usb-net-rtl8152/description @@ -1752,7 +1774,7 @@ $(eval $(call KernelPackage,usbip-server)) define KernelPackage/usb-chipidea TITLE:=Host and device support for Chipidea controllers - DEPENDS:=+USB_GADGET_SUPPORT:kmod-usb-gadget @TARGET_ath79 +kmod-usb-ehci +kmod-usb-phy-nop +kmod-usb-roles + DEPENDS:=+USB_GADGET_SUPPORT:kmod-usb-gadget @TARGET_ath79 +kmod-usb-ehci +kmod-usb-phy-nop +kmod-usb-roles +kmod-phy-ath79-usb KCONFIG:= \ CONFIG_EXTCON \ CONFIG_USB_CHIPIDEA \ @@ -1823,10 +1845,8 @@ define KernelPackage/usb3 +TARGET_bcm53xx:kmod-usb-bcma \ +TARGET_bcm53xx:kmod-phy-bcm-ns-usb3 \ +TARGET_ramips_mt7621:kmod-usb-xhci-mtk \ - +TARGET_mediatek:kmod-usb-xhci-mtk \ - +TARGET_apm821xx_nand:kmod-usb-xhci-pci-renesas \ - +TARGET_lantiq_xrx200:kmod-usb-xhci-pci-renesas \ - +TARGET_mvebu_cortexa9:kmod-usb-xhci-pci-renesas + +TARGET_econet_en751221:kmod-usb-xhci-mtk \ + +TARGET_mediatek:kmod-usb-xhci-mtk KCONFIG:= \ CONFIG_USB_PCI=y \ CONFIG_USB_XHCI_PCI \ @@ -1862,11 +1882,12 @@ endef $(eval $(call KernelPackage,usb-net2280)) define KernelPackage/usb-roles + SUBMENU:=$(USB_MENU) TITLE:=USB Role Switch Library Module + DEPENDS:=@USB_SUPPORT||USB_GADGET_SUPPORT KCONFIG:=CONFIG_USB_ROLE_SWITCH HIDDEN:=1 FILES:=$(LINUX_DIR)/drivers/usb/roles/roles.ko - $(call AddDepends/usb) endef define KernelPackage/usb-roles/description @@ -1913,8 +1934,8 @@ $(eval $(call KernelPackage,usb-xhci-mtk)) define KernelPackage/usb-xhci-pci-renesas TITLE:=Support for additional Renesas xHCI controller with firmware + DEPENDS:=+kmod-usb3 KCONFIG:=CONFIG_USB_XHCI_PCI_RENESAS - HIDDEN:=1 FILES:=$(LINUX_DIR)/drivers/usb/host/xhci-pci-renesas.ko AUTOLOAD:=$(call AutoLoad,54,xhci-pci-renesas,1) $(call AddDepends/usb) diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index 3a14fc08d..f8d05103e 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -63,7 +63,7 @@ $(eval $(call KernelPackage,acpi-video)) define KernelPackage/backlight SUBMENU:=$(VIDEO_MENU) TITLE:=Backlight support - DEPENDS:=@DISPLAY_SUPPORT + DEPENDS:=@DISPLAY_SUPPORT +kmod-fb HIDDEN:=1 KCONFIG:=CONFIG_BACKLIGHT_CLASS_DEVICE \ CONFIG_BACKLIGHT_LCD_SUPPORT=y \ @@ -86,7 +86,7 @@ $(eval $(call KernelPackage,backlight)) define KernelPackage/backlight-pwm SUBMENU:=$(VIDEO_MENU) TITLE:=PWM Backlight support - DEPENDS:=+kmod-backlight + DEPENDS:=@PWM_SUPPORT +kmod-backlight KCONFIG:=CONFIG_BACKLIGHT_PWM FILES:=$(LINUX_DIR)/drivers/video/backlight/pwm_bl.ko AUTOLOAD:=$(call AutoProbe,video pwm_bl) @@ -360,17 +360,6 @@ endef $(eval $(call KernelPackage,drm-display-helper)) -define KernelPackage/drm-gem-shmem-helper - SUBMENU:=$(VIDEO_MENU) - TITLE:=GEM shmem helper functions - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm +kmod-drm-kms-helper +kmod-fb-sys-fops +kmod-fb-sys-ram - KCONFIG:=CONFIG_DRM_GEM_SHMEM_HELPER - FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_shmem_helper.ko - AUTOLOAD:=$(call AutoProbe,drm_shmem_helper) -endef - -$(eval $(call KernelPackage,drm-gem-shmem-helper)) - define KernelPackage/drm-exec SUBMENU:=$(VIDEO_MENU) HIDDEN:=1 @@ -403,6 +392,24 @@ endef $(eval $(call KernelPackage,drm-dma-helper)) + +define KernelPackage/drm-shmem-helper + SUBMENU:=$(VIDEO_MENU) + HIDDEN:=1 + TITLE:=GEM SHMEM helper functions + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper + KCONFIG:=CONFIG_DRM_GEM_SHMEM_HELPER + FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_shmem_helper.ko + AUTOLOAD:=$(call AutoProbe,drm_shmem_helper) +endef + +define KernelPackage/drm-shmem-helper/description + GEM SHMEM helper functions. +endef + +$(eval $(call KernelPackage,drm-shmem-helper)) + + define KernelPackage/drm-mipi-dbi SUBMENU:=$(VIDEO_MENU) HIDDEN:=1 @@ -419,6 +426,25 @@ endef $(eval $(call KernelPackage,drm-mipi-dbi)) + +define KernelPackage/drm-sched + SUBMENU:=$(VIDEO_MENU) + HIDDEN:=1 + TITLE:=GPU scheduler + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm + KCONFIG:=CONFIG_DRM_SCHED + FILES:=$(LINUX_DIR)/drivers/gpu/drm/scheduler/gpu-sched.ko + AUTOLOAD:=$(call AutoProbe,gpu-sched) +endef + +define KernelPackage/drm-sched/description + The GPU scheduler provides entities which allow userspace to push jobs + into software queues which are then scheduled on a hardware run queue. +endef + +$(eval $(call KernelPackage,drm-sched)) + + define KernelPackage/drm-ttm SUBMENU:=$(VIDEO_MENU) TITLE:=GPU memory management subsystem @@ -440,7 +466,7 @@ define KernelPackage/drm-ttm-helper SUBMENU:=$(VIDEO_MENU) TITLE:=Helpers for ttm-based gem objects HIDDEN:=1 - DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-ttm + DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-ttm +kmod-drm-kms-helper KCONFIG:=CONFIG_DRM_TTM_HELPER FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_ttm_helper.ko AUTOLOAD:=$(call AutoProbe,drm_ttm_helper) @@ -483,6 +509,23 @@ endef $(eval $(call KernelPackage,drm-suballoc-helper)) +define KernelPackage/drm-vram-helper + SUBMENU:=$(VIDEO_MENU) + HIDDEN:=1 + TITLE:=DRM helpers for VRAM memory management + DEPENDS:=@DISPLAY_SUPPORT \ + +kmod-drm-kms-helper +kmod-drm-ttm-helper + KCONFIG:=CONFIG_DRM_VRAM_HELPER + FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_vram_helper.ko + AUTOLOAD:=$(call AutoProbe,drm_vram_helper) +endef + +define KernelPackage/drm-vram-helper/description + DRM helpers for VRAM memory management. +endef + +$(eval $(call KernelPackage,drm-vram-helper)) + define KernelPackage/drm-amdgpu SUBMENU:=$(VIDEO_MENU) TITLE:=AMDGPU DRM support @@ -558,6 +601,20 @@ endef $(eval $(call KernelPackage,drm-i915)) +define KernelPackage/drm-ivpu + SUBMENU:=$(VIDEO_MENU) + TITLE:=Intel VPU DRM support + DEPENDS:=@TARGET_x86_64 +ivpu-firmware + KCONFIG:=CONFIG_DRM_ACCEL_IVPU + FILES:=$(LINUX_DIR)/drivers/accel/ivpu/intel_vpu.ko + AUTOLOAD:=$(call AutoProbe,intel_vpu) +endef + +define KernelPackage/drm-ivpu/description + Direct Rendering Manager (DRM) support for Intel VPU +endef + +$(eval $(call KernelPackage,drm-ivpu)) define KernelPackage/drm-imx SUBMENU:=$(VIDEO_MENU) @@ -593,7 +650,7 @@ $(eval $(call KernelPackage,drm-imx)) define KernelPackage/drm-imx-hdmi SUBMENU:=$(VIDEO_MENU) TITLE:=Freescale i.MX HDMI DRM support - DEPENDS:=+kmod-sound-core kmod-drm-imx kmod-drm-display-helper + DEPENDS:=+kmod-sound-core kmod-drm-imx +kmod-drm-display-helper KCONFIG:=CONFIG_DRM_IMX_HDMI \ CONFIG_DRM_DW_HDMI_AHB_AUDIO \ CONFIG_DRM_DW_HDMI_I2S_AUDIO @@ -610,13 +667,12 @@ endef $(eval $(call KernelPackage,drm-imx-hdmi)) + define KernelPackage/drm-imx-ldb SUBMENU:=$(VIDEO_MENU) TITLE:=Freescale i.MX LVDS DRM support - DEPENDS:=@(TARGET_imx&&TARGET_imx_cortexa9) +kmod-backlight kmod-drm-imx + DEPENDS:=@(TARGET_imx&&TARGET_imx_cortexa9) +kmod-backlight +kmod-drm-panel-simple kmod-drm-imx KCONFIG:=CONFIG_DRM_IMX_LDB \ - CONFIG_DRM_PANEL_SIMPLE \ - CONFIG_DRM_PANEL=y \ CONFIG_DRM_PANEL_SAMSUNG_LD9040=n \ CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=n \ CONFIG_DRM_PANEL_LG_LG4573=n \ @@ -625,8 +681,7 @@ define KernelPackage/drm-imx-ldb CONFIG_DRM_PANEL_S6E8AA0=n \ CONFIG_DRM_PANEL_SITRONIX_ST7789V=n FILES:= \ - $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/imx-ldb.ko \ - $(LINUX_DIR)/drivers/gpu/drm/panel/panel-simple.ko + $(LINUX_DIR)/drivers/gpu/drm/imx/ipuv3/imx-ldb.ko AUTOLOAD:=$(call AutoLoad,08,imx-ldb) endef @@ -654,31 +709,27 @@ endef $(eval $(call KernelPackage,drm-panel-mipi-dbi)) -define KernelPackage/drm-lima + +define KernelPackage/drm-panel-simple SUBMENU:=$(VIDEO_MENU) - TITLE:=Mali-4xx GPU support - DEPENDS:=@(TARGET_rockchip||TARGET_sunxi) +kmod-drm-gem-shmem-helper - KCONFIG:= \ - CONFIG_DRM_VGEM \ - CONFIG_DRM_GEM_CMA_HELPER=y \ - CONFIG_DRM_LIMA - FILES:= \ - $(LINUX_DIR)/drivers/gpu/drm/vgem/vgem.ko \ - $(LINUX_DIR)/drivers/gpu/drm/scheduler/gpu-sched.ko \ - $(LINUX_DIR)/drivers/gpu/drm/lima/lima.ko - AUTOLOAD:=$(call AutoProbe,lima vgem) + TITLE:=Simple (non-eDP) TFT panels + DEPENDS:=@USES_DEVICETREE @USES_PM +kmod-drm +kmod-backlight + KCONFIG:=CONFIG_DRM_PANEL_SIMPLE \ + CONFIG_DRM_PANEL=y + FILES:=$(LINUX_DIR)/drivers/gpu/drm/panel/panel-simple.ko + AUTOLOAD:=$(call AutoProbe,panel-simple) endef -define KernelPackage/drm-lima/description - Open-source reverse-engineered driver for Mali-4xx GPUs +define KernelPackage/drm-panel-simple/description + Generic driver for simple raw (ie. non-eDP) TFT panels. endef -$(eval $(call KernelPackage,drm-lima)) +$(eval $(call KernelPackage,drm-panel-simple)) define KernelPackage/drm-panfrost SUBMENU:=$(VIDEO_MENU) TITLE:=DRM support for ARM Mali Midgard/Bifrost GPUs - DEPENDS:=@(TARGET_rockchip||TARGET_sunxi) +kmod-drm +kmod-drm-gem-shmem-helper + DEPENDS:=@(TARGET_rockchip||TARGET_sunxi) +kmod-drm +kmod-drm-shmem-helper KCONFIG:=CONFIG_DRM_PANFROST FILES:= \ $(LINUX_DIR)/drivers/gpu/drm/panfrost/panfrost.ko \ @@ -696,7 +747,7 @@ $(eval $(call KernelPackage,drm-panfrost)) define KernelPackage/drm-panthor SUBMENU:=$(VIDEO_MENU) TITLE:=DRM support for ARM Mali CSF-based GPUs - DEPENDS:=@TARGET_rockchip +kmod-drm +kmod-drm-exec +kmod-drm-gem-shmem-helper + DEPENDS:=@TARGET_rockchip +kmod-drm +kmod-drm-exec +kmod-drm-shmem-helper KCONFIG:= \ CONFIG_DRM_GPUVM \ CONFIG_DRM_PANTHOR @@ -713,6 +764,28 @@ endef $(eval $(call KernelPackage,drm-panthor)) + +define KernelPackage/drm-panel-tc358762 + SUBMENU:=$(VIDEO_MENU) + TITLE:=TC358762 DSI/DPI bridge + DEPENDS:=+kmod-drm-kms-helper + KCONFIG:=CONFIG_DRM_TOSHIBA_TC358762 \ + CONFIG_DRM_BRIDGE=y \ + CONFIG_DRM_MIPI_DSI=y \ + CONFIG_DRM_PANEL=y + CONFIG_DRM_PANEL_BRIDGE=y + FILES:= \ + $(LINUX_DIR)/drivers/gpu/drm/bridge/tc358762.ko + AUTOLOAD:=$(call AutoProbe,tc358762) +endef + +define KernelPackage/drm-panel-tc358762/description + Toshiba TC358762 DSI/DPI bridge driver +endef + +$(eval $(call KernelPackage,drm-panel-tc358762)) + + define KernelPackage/drm-radeon SUBMENU:=$(VIDEO_MENU) TITLE:=Radeon DRM support @@ -796,6 +869,7 @@ $(eval $(call KernelPackage,video-videobuf2)) define KernelPackage/video-async TITLE:=V4L2 ASYNC support + HIDDEN:=1 KCONFIG:=CONFIG_V4L2_ASYNC FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/v4l2-async.ko $(call AddDepends/video) @@ -806,6 +880,7 @@ $(eval $(call KernelPackage,video-async)) define KernelPackage/video-fwnode TITLE:=V4L2 FWNODE support + HIDDEN:=1 KCONFIG:=CONFIG_V4L2_FWNODE FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/v4l2-fwnode.ko $(call AddDepends/video,+kmod-video-async) @@ -814,21 +889,6 @@ endef $(eval $(call KernelPackage,video-fwnode)) -define KernelPackage/video-cpia2 - TITLE:=CPIA2 video driver - DEPENDS:=@USB_SUPPORT - KCONFIG:=CONFIG_VIDEO_CPIA2 - FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/cpia2/cpia2.ko - AUTOLOAD:=$(call AutoProbe,cpia2) - $(call AddDepends/camera) -endef - -define KernelPackage/video-cpia2/description - Kernel modules for supporting CPIA2 USB based cameras -endef - -$(eval $(call KernelPackage,video-cpia2)) - define KernelPackage/video-pwc TITLE:=Philips USB webcam support diff --git a/openwrt/patch/openwrt-6.x/modules/w1.mk b/openwrt/patch/openwrt-6.x/modules/w1.mk index 9cba28da1..ba2f3d2fe 100644 --- a/openwrt/patch/openwrt-6.x/modules/w1.mk +++ b/openwrt/patch/openwrt-6.x/modules/w1.mk @@ -174,3 +174,19 @@ define KernelPackage/w1-slave-ds2413/description endef $(eval $(call KernelPackage,w1-slave-ds2413)) + + +define KernelPackage/w1-slave-ds2438 + TITLE:=DS2438 Smart Battery Monitor + KCONFIG:= \ + CONFIG_W1_SLAVE_DS2438 + FILES:=$(W1_SLAVES_DIR)/w1_ds2438.ko + AUTOLOAD:=$(call AutoProbe,w1_ds2438) + $(call AddDepends/w1) +endef + +define KernelPackage/w1-slave-ds2438/description + Kernel module for 1-wire DS2438 Smart Battery Monitor support +endef + +$(eval $(call KernelPackage,w1-slave-ds2438)) diff --git a/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch b/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch deleted file mode 100644 index a8b04ce0d..000000000 --- a/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/net/batman-adv/distributed-arp-table.c -+++ b/net/batman-adv/distributed-arp-table.c -@@ -7,7 +7,13 @@ - #include "distributed-arp-table.h" - #include "main.h" - -+#include -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) -+#include -+#else - #include -+#endif - #include - #include - #include diff --git a/openwrt/patch/packages-patches/clang/linux-atm/openwrt-fix-build-with-clang.patch b/openwrt/patch/packages-patches/clang/linux-atm/openwrt-fix-build-with-clang.patch new file mode 100644 index 000000000..07547a9ee --- /dev/null +++ b/openwrt/patch/packages-patches/clang/linux-atm/openwrt-fix-build-with-clang.patch @@ -0,0 +1,20 @@ +diff --git a/package/network/utils/linux-atm/Makefile b/package/network/utils/linux-atm/Makefile +index c48309d..bec084d 100644 +--- a/package/network/utils/linux-atm/Makefile ++++ b/package/network/utils/linux-atm/Makefile +@@ -6,7 +6,6 @@ + # + + include $(TOPDIR)/rules.mk +-include $(INCLUDE_DIR)/kernel.mk + + PKG_NAME:=linux-atm + PKG_VERSION:=2.5.2 +@@ -24,6 +23,7 @@ PKG_FIXUP:=autoreconf + PKG_FLAGS:=nonshared + + include $(INCLUDE_DIR)/package.mk ++include $(INCLUDE_DIR)/kernel.mk + + ATM_DEBUG_BINS:=aread awrite atmdiag atmdump atmswitch saaldump \ + sonetdiag svc_recv svc_send ttcp_atm diff --git a/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch deleted file mode 100644 index 2ab956227..000000000 --- a/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 3d256971a2a532c974b88418927dd3b3831c27cc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= -Date: Fri, 19 Jul 2024 20:18:31 +0000 -Subject: [PATCH] Fix cryptodev_verbosity sysctl for Linux 6.11-rc1 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There has been a long-running Linux kernel effort to get rid of the -sentinels of `struct ctl_table`. In Linux 6.11 it has been completed, -and registering a sysctl with a sentinel will fail with a dmesg error: - -> sysctl table check failed: ioctl/(null) procname is null -> sysctl table check failed: ioctl/(null) No proc_handler - -Exclude the sentinels since that version. - -See also: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f8a8b94d0698ccc56c44478169c91ca774540d9f - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9edbfe92a0a1355bae1e47c8f542ac0d39f19f8c - -Signed-off-by: Joan Bruguera Micó ---- - ioctl.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/ioctl.c -+++ b/ioctl.c -@@ -1239,7 +1239,9 @@ static struct ctl_table verbosity_ctl_di - .mode = 0644, - .proc_handler = proc_dointvec, - }, -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0)) - {}, -+#endif - }; - - static struct ctl_table verbosity_ctl_root[] = { diff --git a/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch b/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch deleted file mode 100644 index c83d49d8e..000000000 --- a/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 2669a340472e89a521ac6fbc803961124311453b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= -Date: Fri, 19 Jul 2024 20:10:32 +0000 -Subject: [PATCH] Exclude unused struct since Linux >= 6.5 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since Linux >= 6.5 we don't need `struct ctl_table verbosity_ctl_root`, -only the sysctl path, so move it to a constant and exclude the struct. - -This is just a cosmetic change, intended to make it clear that neither -the struct nor the sentinel that follows are needed on newer kernels. - -Signed-off-by: Joan Bruguera Micó ---- - ioctl.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - ---- a/ioctl.c -+++ b/ioctl.c -@@ -1231,6 +1231,7 @@ cryptodev_deregister(void) - } - - /* ====== Module init/exit ====== */ -+static const char verbosity_ctl_path[] = "ioctl"; - static struct ctl_table verbosity_ctl_dir[] = { - { - .procname = "cryptodev_verbosity", -@@ -1244,16 +1245,16 @@ static struct ctl_table verbosity_ctl_di - #endif - }; - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) - static struct ctl_table verbosity_ctl_root[] = { - { -- .procname = "ioctl", -+ .procname = verbosity_ctl_path, - .mode = 0555, --#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) - .child = verbosity_ctl_dir, --#endif - }, - {}, - }; -+#endif - static struct ctl_table_header *verbosity_sysctl_header; - static int __init init_cryptodev(void) - { -@@ -1274,7 +1275,7 @@ static int __init init_cryptodev(void) - #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) - verbosity_sysctl_header = register_sysctl_table(verbosity_ctl_root); - #else -- verbosity_sysctl_header = register_sysctl(verbosity_ctl_root->procname, verbosity_ctl_dir); -+ verbosity_sysctl_header = register_sysctl(verbosity_ctl_path, verbosity_ctl_dir); - #endif - - pr_info(PFX "driver %s loaded.\n", VERSION); diff --git a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch deleted file mode 100644 index 620905e3c..000000000 --- a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -index 9876dee..87828e0 100644 ---- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -+++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c -@@ -522,7 +522,7 @@ static int gpio_keys_button_probe(struct platform_device *pdev, - /* or the legacy (button->gpio is good) way? */ - error = devm_gpio_request_one(dev, - button->gpio, GPIOF_IN | ( -- button->active_low ? GPIOF_ACTIVE_LOW : -+ button->active_low ? GPIOD_OUT_LOW : - 0), desc); - if (error) { - dev_err_probe(dev, error, -@@ -674,7 +674,11 @@ static void gpio_keys_irq_close(struct gpio_keys_button_dev *bdev) - } - } - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 11, 0) -+static void gpio_keys_remove(struct platform_device *pdev) -+#else - static int gpio_keys_remove(struct platform_device *pdev) -+#endif - { - struct gpio_keys_button_dev *bdev = platform_get_drvdata(pdev); - -@@ -685,7 +689,9 @@ static int gpio_keys_remove(struct platform_device *pdev) - else - gpio_keys_irq_close(bdev); - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - return 0; -+#endif - } - - static struct platform_driver gpio_keys_driver = { diff --git a/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.18.patch b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.18.patch new file mode 100644 index 000000000..53ff25949 --- /dev/null +++ b/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.18.patch @@ -0,0 +1,29 @@ +diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +index d0e3723..3efbfaa 100644 +--- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c ++++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +@@ -515,7 +515,7 @@ static int gpio_keys_button_probe(struct platform_device *pdev, + /* or the legacy (button->gpio is good) way? */ + error = devm_gpio_request_one(dev, + button->gpio, GPIOF_IN | ( +- button->active_low ? GPIOF_ACTIVE_LOW : ++ button->active_low ? GPIOD_OUT_LOW : + 0), desc); + if (error) { + dev_err_probe(dev, error, +@@ -681,7 +681,6 @@ static void gpio_keys_remove(struct platform_device *pdev) + + static struct platform_driver gpio_keys_driver = { + .probe = gpio_keys_probe, +- .remove_new = gpio_keys_remove, + .driver = { + .name = "gpio-keys", + .of_match_table = of_match_ptr(gpio_keys_of_match), +@@ -690,7 +689,6 @@ static struct platform_driver gpio_keys_driver = { + + static struct platform_driver gpio_keys_polled_driver = { + .probe = gpio_keys_polled_probe, +- .remove_new = gpio_keys_remove, + .driver = { + .name = "gpio-keys-polled", + .of_match_table = of_match_ptr(gpio_keys_polled_of_match), diff --git a/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch b/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch new file mode 100644 index 000000000..5f88f5542 --- /dev/null +++ b/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch @@ -0,0 +1,38 @@ +--- a/meson.build ++++ b/meson.build +@@ -9,12 +9,13 @@ glib_dep = dependency('glib-2.0', static + m_dep = cc.find_library('m', required: false) + capng_dep = dependency('libcap-ng', required: get_option('capng')) + ncurses_dep = dependency('curses', required: get_option('ui')) ++numa_dep = cc.find_library('numa', required: get_option('numa')) + systemd_dep = dependency('libsystemd', required: get_option('systemd')) + + cdata = configuration_data() + cdata.set('HAVE_GETOPT_LONG', cc.has_function('getopt_long')) + cdata.set('HAVE_IRQBALANCEUI', ncurses_dep.found()) +-cdata.set('HAVE_NUMA_H', cc.has_header('numa.h')) ++cdata.set('HAVE_NUMA_H', cc.has_header('numa.h') and numa_dep.found()) + cdata.set('HAVE_LIBCAP_NG', capng_dep.found()) + cdata.set('HAVE_LIBSYSTEMD', systemd_dep.found()) + cdata.set_quoted('VERSION', meson.project_version()) +@@ -38,6 +39,6 @@ executable('irqbalance', + 'numa.c', + 'placement.c', + 'procinterrupts.c', +- dependencies: [ glib_dep, m_dep, capng_dep, ncurses_dep, systemd_dep ], ++ dependencies: [ glib_dep, m_dep, capng_dep, ncurses_dep, numa_dep, systemd_dep ], + install : true + ) +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -2,6 +2,10 @@ option('capng', type : 'feature', + description : 'Build with libcap-ng support', + ) + ++option('numa', type : 'feature', value: 'disabled', ++ description : 'Build with numa support', ++) ++ + option('systemd', type : 'feature', + description : 'Build with systemd support', + ) diff --git a/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch b/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch deleted file mode 100644 index 6cf58915f..000000000 --- a/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch +++ /dev/null @@ -1,74 +0,0 @@ ---- a/nat46/modules/nat46-netdev.c -+++ b/nat46/modules/nat46-netdev.c -@@ -193,7 +193,11 @@ static struct net_device *find_dev(char - return NULL; - } - -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) -+ rcu_read_lock(); -+#else - read_lock(&dev_base_lock); -+#endif - dev = first_net_device(&init_net); - while (dev) { - if((0 == strcmp(dev->name, name)) && is_nat46(dev)) { -@@ -205,7 +209,11 @@ static struct net_device *find_dev(char - } - dev = next_net_device(dev); - } -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) -+ rcu_read_unlock(); -+#else - read_unlock(&dev_base_lock); -+#endif - return out; - } - -@@ -300,7 +308,11 @@ int nat46_remove(char *devname, char *bu - - void nat64_show_all_configs(struct seq_file *m) { - struct net_device *dev; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) -+ rcu_read_lock(); -+#else - read_lock(&dev_base_lock); -+#endif - dev = first_net_device(&init_net); - while (dev) { - if(is_nat46(dev)) { -@@ -323,7 +335,11 @@ void nat64_show_all_configs(struct seq_f - } - dev = next_net_device(dev); - } -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) -+ rcu_read_unlock(); -+#else - read_unlock(&dev_base_lock); -+#endif - - } - -@@ -331,7 +347,11 @@ void nat46_destroy_all(void) { - struct net_device *dev; - struct net_device *nat46dev; - do { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) -+ rcu_read_lock(); -+#else - read_lock(&dev_base_lock); -+#endif - nat46dev = NULL; - dev = first_net_device(&init_net); - while (dev) { -@@ -340,7 +360,11 @@ void nat46_destroy_all(void) { - } - dev = next_net_device(dev); - } -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) -+ rcu_read_unlock(); -+#else - read_unlock(&dev_base_lock); -+#endif - if(nat46dev) { - nat46_netdev_destroy(nat46dev); - } diff --git a/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch b/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch deleted file mode 100644 index 1c213ea90..000000000 --- a/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/nat46/modules/nat46-netdev.c -+++ b/nat46/modules/nat46-netdev.c -@@ -110,7 +110,11 @@ static void nat46_netdev_setup(struct ne - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->mtu = 16384; /* iptables does reassembly. Rather than using ETH_DATA_LEN, let's try to get as much mileage as we can with the Linux stack */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0) - dev->features = NETIF_F_NETNS_LOCAL; -+#else -+ dev->features = dev->netns_local; -+#endif - dev->flags = IFF_NOARP | IFF_POINTOPOINT; - } - diff --git a/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch b/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch index 7101b3024..ec98eab02 100644 --- a/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch +++ b/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch @@ -1,6 +1,6 @@ --- a/nat46/modules/nat46-module.c +++ b/nat46/modules/nat46-module.c -@@ -48,7 +48,7 @@ +@@ -51,7 +51,7 @@ #define NAT46_CONTROL_PROC_NAME "control" #ifndef NAT46_VERSION @@ -9,14 +9,3 @@ #endif MODULE_LICENSE("GPL"); ---- a/nat46/modules/nat46-netdev.c -+++ b/nat46/modules/nat46-netdev.c -@@ -113,7 +113,7 @@ static void nat46_netdev_setup(struct ne - #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0) - dev->features = NETIF_F_NETNS_LOCAL; - #else -- dev->features = dev->netns_local; -+ dev->features = dev->netns_immutable; - #endif - dev->flags = IFF_NOARP | IFF_POINTOPOINT; - } diff --git a/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch b/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch deleted file mode 100644 index bc94690fe..000000000 --- a/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c -index 2e5278a..7a3cb09 100644 ---- a/kernel-module/xt_RTPENGINE.c -+++ b/kernel-module/xt_RTPENGINE.c -@@ -4017,7 +4017,7 @@ static int send_proxy_packet4(struct sk_buff *skb, struct re_address *src, struc - if (!net) - goto drop; - -- rt = ip_route_output(net, dst->u.ipv4, src->u.ipv4, tos, 0); -+ rt = ip_route_output(net, dst->u.ipv4, src->u.ipv4, tos, 0, 0); - if (IS_ERR(rt)) - goto drop; - skb_dst_drop(skb); diff --git a/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch b/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch index 29a6a80f9..40cf0fbe5 100644 --- a/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch +++ b/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch @@ -1,6 +1,6 @@ --- a/kernel-module/xt_RTPENGINE.c +++ b/kernel-module/xt_RTPENGINE.c -@@ -35,16 +35,14 @@ +@@ -35,11 +35,7 @@ #include #include #include @@ -12,14 +12,6 @@ #include "rtpengine_config.h" - MODULE_LICENSE("GPL"); --#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,13,0) -+MODULE_IMPORT_NS("CRYPTO_INTERNAL"); -+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0) - MODULE_IMPORT_NS(CRYPTO_INTERNAL); - #endif - MODULE_ALIAS("ipt_RTPENGINE"); --- a/kernel-module/xt_RTPENGINE.h +++ b/kernel-module/xt_RTPENGINE.h @@ -1,7 +1,7 @@ @@ -27,7 +19,7 @@ #define XT_RTPPROXY_H - -+#define RTPENGINE_VERSION "11.5.1.18" ++#define RTPENGINE_VERSION "11.5.1.49" #define RTPE_NUM_PAYLOAD_TYPES 32 #define RTPE_MAX_FORWARD_DESTINATIONS 32 diff --git a/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch b/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch deleted file mode 100644 index f1321bb82..000000000 --- a/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/sms_main.c -+++ b/sms_main.c -@@ -111,7 +111,7 @@ static void resetserial() - close(port); - } - --static void timeout() -+static void timeout(int signo) - { - fprintf(stderr,"No response from modem.\n"); - exit(2); diff --git a/openwrt/patch/packages-patches/ubootenv-nvram/010-fix-build-for-linux-6.18.patch b/openwrt/patch/packages-patches/ubootenv-nvram/010-fix-build-for-linux-6.18.patch new file mode 100644 index 000000000..7fe766af6 --- /dev/null +++ b/openwrt/patch/packages-patches/ubootenv-nvram/010-fix-build-for-linux-6.18.patch @@ -0,0 +1,12 @@ +diff --git a/package/kernel/ubootenv-nvram/src/ubootenv-nvram.c b/package/kernel/ubootenv-nvram/src/ubootenv-nvram.c +index ba1d797..36e3c2d 100644 +--- a/package/kernel/ubootenv-nvram/src/ubootenv-nvram.c ++++ b/package/kernel/ubootenv-nvram/src/ubootenv-nvram.c +@@ -142,7 +142,6 @@ static void ubootenv_remove(struct platform_device *pdev) + + static struct platform_driver ubootenv_driver = { + .probe = ubootenv_probe, +- .remove_new = ubootenv_remove, + .driver = { + .name = NAME, + .of_match_table = of_ubootenv_match, diff --git a/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch b/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch deleted file mode 100644 index a045c078d..000000000 --- a/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch +++ /dev/null @@ -1,33 +0,0 @@ ---- a/ubootenv-nvram.c -+++ b/ubootenv-nvram.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #define NAME "ubootenv" - -@@ -132,13 +133,21 @@ static int ubootenv_probe(struct platfor - return misc_register(&data->misc); - } - --static int ubootenv_remove(struct platform_device *pdev) -+static -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) -+int -+#else -+void -+#endif -+ubootenv_remove(struct platform_device *pdev) - { - struct ubootenv_drvdata *data = platform_get_drvdata(pdev); - - data->env = NULL; - misc_deregister(&data->misc); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - return 0; -+#endif - } - - static struct platform_driver ubootenv_driver = { diff --git a/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch b/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch deleted file mode 100644 index 15ebf12a4..000000000 --- a/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/extensions/rtsp/nf_conntrack_rtsp.c -+++ b/extensions/rtsp/nf_conntrack_rtsp.c -@@ -735,8 +735,12 @@ init(void) - } - - #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 11, 0) - strlcpy(hlpr->name, tmpname, sizeof(hlpr->name)); - #else -+ strscpy(hlpr->name, tmpname, sizeof(hlpr->name)); -+#endif -+#else - hlpr->name = tmpname; - #endif - pr_debug("port #%d: %d\n", i, ports[i]); diff --git a/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch b/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch deleted file mode 100644 index aa66aa00b..000000000 --- a/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/extensions/xt_ipp2p.c -+++ b/extensions/xt_ipp2p.c -@@ -3,7 +3,11 @@ - #include - #include - #include -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) -+#include -+#else - #include -+#endif - #include "xt_ipp2p.h" - #include "compat_xtables.h" - diff --git a/openwrt/patch/target-modify_for_aarch64_x86_64.patch b/openwrt/patch/target-modify_for_aarch64_x86_64.patch index af782b842..17d6e1630 100644 --- a/openwrt/patch/target-modify_for_aarch64_x86_64.patch +++ b/openwrt/patch/target-modify_for_aarch64_x86_64.patch @@ -1,8 +1,6 @@ -diff --git a/include/target.mk b/include/target.mk -index 02ea68b..28b3f56 100644 --- a/include/target.mk +++ b/include/target.mk -@@ -221,7 +221,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt +@@ -215,7 +215,7 @@ LINUX_RECONF_DIFF = $(SCRIPT_DIR)/kconfig.pl - '>' $(call __linux_confcmd,$(filt ifeq ($(DUMP),1) BuildTarget=$(BuildTargets/DumpCurrent) @@ -11,7 +9,7 @@ index 02ea68b..28b3f56 100644 ifneq ($(findstring mips,$(ARCH)),) ifneq ($(findstring mips64,$(ARCH)),) CPU_TYPE ?= mips64 -@@ -282,6 +282,14 @@ ifeq ($(DUMP),1) +@@ -276,6 +276,14 @@ ifeq ($(DUMP),1) CPU_CFLAGS := -O2 -pipe CPU_CFLAGS_generic:=-march=loongarch64 endif diff --git a/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch b/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch deleted file mode 100644 index 5a472860f..000000000 --- a/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0ce3488d0852c204c5b96f46cd551c6205b3d993 Mon Sep 17 00:00:00 2001 -From: Leonard de Vries -Date: Thu, 21 Sep 2023 09:40:12 +0200 -Subject: [PATCH] vim: fix renamed defaults config file - -Since vim version 9 the config file has been renamed from vimrc to defaults.vim. -The syntax also has been changed however this new version is not the default, -therefore the config doesn't need a change. - -Signed-off-by: Leonard de Vries ---- - utils/vim/Makefile | 10 +++++----- - utils/vim/files/{vimrc => defaults.vim} | 0 - utils/vim/files/{vimrc.full => defaults.vim.full} | 0 - 3 files changed, 5 insertions(+), 5 deletions(-) - rename utils/vim/files/{vimrc => defaults.vim} (100%) - rename utils/vim/files/{vimrc.full => defaults.vim.full} (100%) - -diff --git a/utils/vim/Makefile b/utils/vim/Makefile -index 7726765..a6d6dd2 100644 ---- a/utils/vim/Makefile -+++ b/utils/vim/Makefile -@@ -74,12 +74,12 @@ define Package/xxd - endef - - define Package/vim-full/conffiles --/usr/share/vim/vimrc -+/usr/share/vim/defaults.vim - /root/.vimrc - endef - - define Package/vim/conffiles --/usr/share/vim/vimrc -+/usr/share/vim/defaults.vim - /root/.vimrc - endef - -@@ -209,7 +209,7 @@ define Package/vim/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/vim_tiny $(1)/usr/bin/vim - $(INSTALL_DIR) $(1)/usr/share/vim -- $(INSTALL_CONF) ./files/vimrc $(1)/usr/share/vim/ -+ $(INSTALL_CONF) ./files/defaults.vim $(1)/usr/share/vim/ - endef - - define Package/vim-full/install -@@ -217,7 +217,7 @@ define Package/vim-full/install - $(INSTALL_BIN) $(PKG_BUILD_DIR)/vim_normal $(1)/usr/bin/vim - $(INSTALL_DIR) $(1)/usr/share/vim - $(LN) vim $(1)/usr/bin/vimdiff -- $(INSTALL_CONF) ./files/vimrc.full $(1)/usr/share/vim/vimrc -+ $(INSTALL_CONF) ./files/defaults.vim.full $(1)/usr/share/vim/defaults.vim - endef - - -@@ -227,7 +227,7 @@ define Package/vim-fuller/install - $(INSTALL_DIR) $(1)/usr/share/vim - $(LN) vim $(1)/usr/bin/vimdiff - $(CP) $(PKG_INSTALL_DIR)/usr/share/vim/vim$(VIMVER) $(1)/usr/share/vim -- $(INSTALL_CONF) ./files/vimrc.full $(1)/usr/share/vim/vimrc -+ $(INSTALL_CONF) ./files/defaults.vim.full $(1)/usr/share/vim/defaults.vim - endef - - -diff --git a/utils/vim/files/vimrc b/utils/vim/files/defaults.vim -similarity index 100% -rename from utils/vim/files/vimrc -rename to utils/vim/files/defaults.vim -diff --git a/utils/vim/files/vimrc.full b/utils/vim/files/defaults.vim.full -similarity index 100% -rename from utils/vim/files/vimrc.full -rename to utils/vim/files/defaults.vim.full --- -2.43.5 - diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 4979846de..b53c0622c 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -11,20 +11,19 @@ else fi # patch source -curl -s $mirror/openwrt/patch/generic-24.10/0001-tools-add-upx-tools.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0002-rootfs-add-upx-compression-support.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0005-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0006-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0007-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0008-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0009-kernel-add-legacy-cgroup-v1-memory-controller.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 -#curl -s $mirror/openwrt/patch/generic-24.10/0011-tools-squashfs4-enable-zstd-compression-support.patch | patch -p1 -#curl -s $mirror/openwrt/patch/generic-24.10/0012-config-include-image-add-support-for-squashfs-zstd-c.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0013-include-kernel-Always-collect-module-symvers.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-24.10/0014-include-netfilter-update-kernel-config-options-for-l.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0001-tools-add-upx-tools.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0002-rootfs-add-upx-compression-support.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0003-rootfs-add-r-w-permissions-for-UCI-configuration-fil.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0004-rootfs-Add-support-for-local-kmod-installation-sourc.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0005-kernel-Add-support-for-llvm-clang-compiler.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0006-build-kernel-add-out-of-tree-kernel-config.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0007-include-kernel-add-miss-config-for-linux-6.11.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0008-meson-add-platform-variable-to-cross-compilation-fil.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0009-tools-squashfs4-enable-lz4-zstd-compression-support.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0011-config-include-image-add-support-for-squashfs-zstd-c.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0012-include-kernel-Always-collect-module-symvers.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch | patch -p1 # add source mirror #sed -i '/"@OPENWRT": \[/a\\t\t"https://sources-cdn-openwrt.cooluc.com",' scripts/projectsmirrors.json @@ -33,10 +32,6 @@ sed -i '/"@OPENWRT": \[/a\\t\t"https://source.cooluc.com",' scripts/projectsmirr # attr no-mold [ "$ENABLE_MOLD" = "y" ] && sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile -# dwarves 1.25 -rm -rf tools/dwarves -git clone https://$github/sbwml/tools_dwarves tools/dwarves - # x86 - disable mitigations sed -i 's/noinitrd/noinitrd mitigations=off/g' target/linux/x86/image/grub-efi.cfg @@ -64,6 +59,13 @@ if [ "$ENABLE_UHTTPD" != "y" ]; then fi fi +# drop attendedsysupgrade +sed -i '/luci-app-attendedsysupgrade/d' \ + feeds/luci/collections/luci-nginx/Makefile \ + feeds/luci/collections/luci-ssl-openssl/Makefile \ + feeds/luci/collections/luci-ssl/Makefile \ + feeds/luci/collections/luci/Makefile + # Realtek driver - R8168 & R8125 & R8126 & R8152 & R8101 & r8127 rm -rf package/kernel/{r8168,r8101,r8125,r8126,r8127} git clone https://$github/sbwml/package_kernel_r8168 package/kernel/r8168 @@ -106,10 +108,10 @@ fi # fstools rm -rf package/system/fstools -git clone https://$github/sbwml/package_system_fstools -b openwrt-24.10 package/system/fstools +git clone https://$github/sbwml/package_system_fstools -b openwrt-25.12 package/system/fstools # util-linux rm -rf package/utils/util-linux -git clone https://$github/sbwml/package_utils_util-linux -b openwrt-24.10 package/utils/util-linux +git clone https://$github/sbwml/package_utils_util-linux -b openwrt-25.12 package/utils/util-linux # Shortcut Forwarding Engine git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe @@ -125,8 +127,6 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch # bcm fullcone curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch > package/network/config/firewall4/patches/999-02-firewall4-add-bcm-fullconenat-support.patch - # kernel version - curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch > package/network/config/firewall4/patches/002-fix-fw4.uc-adept-kernel-version-type-of-x.x.patch # fix flow offload curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch > package/network/config/firewall4/patches/001-fix-fw4-flow-offload.patch # add custom nft command support @@ -135,11 +135,12 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then mkdir -p package/libs/libnftnl/patches curl -s $mirror/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/0001-libnftnl-add-fullcone-expression-support.patch curl -s $mirror/openwrt/patch/firewall4/libnftnl/0002-libnftnl-add-brcm-fullcone-support.patch > package/libs/libnftnl/patches/0002-libnftnl-add-brcm-fullcone-support.patch + # fix build on rhel9 + sed -i '/^PKG_BUILD_FLAGS[[:space:]]*:/aPKG_FIXUP:=autoreconf' package/libs/libnftnl/Makefile # nftables mkdir -p package/network/utils/nftables/patches curl -s $mirror/openwrt/patch/firewall4/nftables/0001-nftables-add-fullcone-expression-support.patch > package/network/utils/nftables/patches/0001-nftables-add-fullcone-expression-support.patch curl -s $mirror/openwrt/patch/firewall4/nftables/0002-nftables-add-brcm-fullconenat-support.patch > package/network/utils/nftables/patches/0002-nftables-add-brcm-fullconenat-support.patch - curl -s $mirror/openwrt/patch/firewall4/nftables/0003-drop-rej-file.patch > package/network/utils/nftables/patches/0003-drop-rej-file.patch fi # FullCone module @@ -153,72 +154,13 @@ git clone https://$github/sbwml/package_new_natflow package/new/natflow # Patch Luci add nft_fullcone/bcm_fullcone & shortcut-fe & natflow & ipv6-nat & custom nft command option pushd feeds/luci - curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 - curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 - curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 - curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 - curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 - curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 - curl -s $mirror/openwrt/patch/firewall4/luci-24.10/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch | patch -p1 -popd - -# openssl -OPENSSL_VERSION=3.0.17 -OPENSSL_HASH=dfdd77e4ea1b57ff3a6dbde6b0bdc3f31db5ac99e7fdd4eaf9e1fbb6ec2db8ce -sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$OPENSSL_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$OPENSSL_HASH/" package/libs/openssl/Makefile - -# openssl - quictls -pushd package/libs/openssl/patches - curl -sO $mirror/openwrt/patch/openssl/quic/0001-QUIC-Add-support-for-BoringSSL-QUIC-APIs.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0002-QUIC-New-method-to-get-QUIC-secret-length.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0003-QUIC-Make-temp-secret-names-less-confusing.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0004-QUIC-Move-QUIC-transport-params-to-encrypted-extensi.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0005-QUIC-Use-proper-secrets-for-handshake.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0006-QUIC-Handle-partial-handshake-messages.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0007-QUIC-Fix-quic_transport-constructors-parsers.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0008-QUIC-Reset-init-state-in-SSL_process_quic_post_hands.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0009-QUIC-Don-t-process-an-incomplete-message.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0010-QUIC-Quick-fix-s2c-to-c2s-for-early-secret.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0011-QUIC-Add-client-early-traffic-secret-storage.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0012-QUIC-Add-OPENSSL_NO_QUIC-wrapper.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0013-QUIC-Correctly-disable-middlebox-compat.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0014-QUIC-Move-QUIC-code-out-of-tls13_change_cipher_state.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0015-QUIC-Tweeks-to-quic_change_cipher_state.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0016-QUIC-Add-support-for-more-secrets.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0017-QUIC-Fix-resumption-secret.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0018-QUIC-Handle-EndOfEarlyData-and-MaxEarlyData.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0019-QUIC-Fall-through-for-0RTT.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0020-QUIC-Some-cleanup-for-the-main-QUIC-changes.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0021-QUIC-Prevent-KeyUpdate-for-QUIC.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0022-QUIC-Test-KeyUpdate-rejection.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0023-QUIC-Buffer-all-provided-quic-data.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0024-QUIC-Enforce-consistent-encryption-level-for-handsha.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0025-QUIC-add-v1-quic_transport_parameters.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0026-QUIC-return-success-when-no-post-handshake-data.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0027-QUIC-__owur-makes-no-sense-for-void-return-values.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0028-QUIC-remove-SSL_R_BAD_DATA_LENGTH-unused.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0029-QUIC-SSLerr-ERR_raise-ERR_LIB_SSL.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0030-QUIC-Add-compile-run-time-checking-for-QUIC.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0031-QUIC-Add-early-data-support.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0032-QUIC-Make-SSL_provide_quic_data-accept-0-length-data.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0033-QUIC-Process-multiple-post-handshake-messages-in-a-s.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0034-QUIC-Fix-CI.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0035-QUIC-Break-up-header-body-processing.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0036-QUIC-Don-t-muck-with-FIPS-checksums.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0037-QUIC-Update-RFC-references.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0038-QUIC-revert-white-space-change.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0039-QUIC-use-SSL_IS_QUIC-in-more-places.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0040-QUIC-Error-when-non-empty-session_id-in-CH.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0041-QUIC-Update-SSL_clear-to-clear-quic-data.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0042-QUIC-Better-SSL_clear.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0043-QUIC-Fix-extension-test.patch - curl -sO $mirror/openwrt/patch/openssl/quic/0044-QUIC-Update-metadata-version.patch -popd - -# openssl benchmarks -pushd package/libs/openssl/patches - curl -sO $mirror/openwrt/patch/openssl/901-Revert-speed-Pass-IV-to-EVP_CipherInit_ex-for-evp-ru.patch - curl -sO $mirror/openwrt/patch/openssl/902-Revert-apps-speed.c-Fix-the-benchmarking-for-AEAD-ci.patch + curl -s $mirror/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch | patch -p1 + curl -s $mirror/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch | patch -p1 popd # openssl urandom @@ -253,18 +195,6 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then git clone https://$gitea/sbwml/packages_utils_runc feeds/packages/utils/runc fi -# cgroupfs-mount -# fix unmount hierarchical mount -pushd feeds/packages - curl -s $mirror/openwrt/patch/cgroupfs-mount/0001-fix-cgroupfs-mount.patch | patch -p1 -popd -# mount cgroup v2 hierarchy to /sys/fs/cgroup/cgroup2 -mkdir -p feeds/packages/utils/cgroupfs-mount/patches -curl -s $mirror/openwrt/patch/cgroupfs-mount/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch > feeds/packages/utils/cgroupfs-mount/patches/900-mount-cgroup-v2-hierarchy-to-sys-fs-cgroup-cgroup2.patch -curl -s $mirror/openwrt/patch/cgroupfs-mount/901-fix-cgroupfs-umount.patch > feeds/packages/utils/cgroupfs-mount/patches/901-fix-cgroupfs-umount.patch -# docker systemd support -curl -s $mirror/openwrt/patch/cgroupfs-mount/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch > feeds/packages/utils/cgroupfs-mount/patches/902-mount-sys-fs-cgroup-systemd-for-docker-systemd-suppo.patch - # procps-ng - top sed -i 's/enable-skill/enable-skill --disable-modern-top/g' feeds/packages/utils/procps-ng/Makefile diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index b8ca7ba4a..21b89d8a0 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -3,14 +3,14 @@ ################################################################# # autocore -git clone https://$github/sbwml/autocore-arm -b openwrt-24.10 package/system/autocore +git clone https://$github/sbwml/autocore-arm -b openwrt-25.12 package/system/autocore # rockchip - target - r4s/r5s only rm -rf target/linux/rockchip if [ "$(whoami)" = "sbwml" ]; then - git clone https://$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b v6.18 + git clone https://$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b v6.18 --depth=1 else - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b v6.18 + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_rockchip-6.x target/linux/rockchip -b v6.18 --depth=1 fi # bpf-headers - 6.18 @@ -25,7 +25,7 @@ curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.18/100-fix_cs5535_clocke curl -s $mirror/openwrt/patch/openwrt-6.x/x86/patches-6.18/103-pcengines_apu6_platform.patch > target/linux/x86/patches-6.18/103-pcengines_apu6_platform.patch ## x86_64 - target sed -ri "s/(KERNEL_PATCHVER:=)[^\"]*/\16.18/" target/linux/x86/Makefile -sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.6' target/linux/x86/Makefile +sed -i '/KERNEL_PATCHVER/a\KERNEL_TESTING_PATCHVER:=6.12' target/linux/x86/Makefile curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/01_leds > target/linux/x86/base-files/etc/board.d/01_leds curl -s $mirror/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network > target/linux/x86/base-files/etc/board.d/02_network @@ -34,24 +34,18 @@ rm -rf target/linux/armsr git clone https://nanopi:nanopi@$gitea/sbwml/target_linux_armsr target/linux/armsr -b v6.18 # kernel - 6.18 -curl -s $mirror/tags/kernel-6.18 > include/kernel-6.18 +curl -s $mirror/tags/kernel-6.18 > target/linux/generic/kernel-6.18 # kenrel Vermagic sed -ie 's/^\(.\).*vermagic$/\1cp $(TOPDIR)\/.vermagic $(LINUX_DIR)\/.vermagic/' include/kernel-defaults.mk -grep HASH include/kernel-6.18 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic +grep HASH target/linux/generic/kernel-6.18 | awk -F'HASH-' '{print $2}' | awk '{print $1}' | md5sum | awk '{print $1}' > .vermagic # kernel generic patches curl -s $mirror/openwrt/patch/kernel-6.18/openwrt/linux-6.18-target-linux-generic.patch | patch -p1 -local_kernel_version=$(sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p' include/kernel-6.18) -release_kernel_version=$(curl -sL https://raw.githubusercontent.com/sbwml/r4s_build_script/master/tags/kernel-6.18 | sed -n 's/^LINUX_KERNEL_HASH-\([0-9.]\+\) = .*/\1/p') -if [ "$local_kernel_version" = "$release_kernel_version" ] && [ -z "$git_password" ] && [ "$(whoami)" != "sbwml" ]; then - git clone https://$github/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.18 --depth=1 +if [ "$(whoami)" = "sbwml" ]; then + git clone https://$gitea/sbwml/target_linux_generic -b openwrt-25.12 target/linux/generic-6.18 --depth=1 else - if [ "$(whoami)" = "sbwml" ]; then - git clone https://$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.18 --depth=1 - else - git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-24.10 target/linux/generic-6.18 --depth=1 - fi + git clone https://"$git_name":"$git_password"@$gitea/sbwml/target_linux_generic -b openwrt-25.12 target/linux/generic-6.18 --depth=1 fi cp -a target/linux/generic-6.18/* target/linux/generic @@ -61,6 +55,7 @@ git checkout package/kernel/linux pushd package/kernel/linux/modules rm -f [a-z]*.mk curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/block.mk + curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/bluetooth.mk curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/can.mk curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/crypto.mk curl -Os $mirror/openwrt/patch/openwrt-6.x/modules/firewire.mk @@ -153,11 +148,6 @@ pushd target/linux/generic/hack-6.18 curl -Os $mirror/openwrt/patch/kernel-6.18/linux-rt/012-RT-0007-Revert-drm-i915-Depend-on-PREEMPT_RT.patch popd -# iproute2 - bbr3 -curl -s $mirror/openwrt/patch/iproute2/900-ss-output-TCP-BBRv3-diag-information.patch > package/network/utils/iproute2/patches/900-ss-output-TCP-BBRv3-diag-information.patch -curl -s $mirror/openwrt/patch/iproute2/901-ip-introduce-the-ecn_low-per-route-feature.patch > package/network/utils/iproute2/patches/901-ip-introduce-the-ecn_low-per-route-feature.patch -curl -s $mirror/openwrt/patch/iproute2/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch > package/network/utils/iproute2/patches/902-ss-display-ecn_low-if-tcp_info-tcpi_options-TCPI_OPT.patch - # linux-firmware rm -rf package/firmware/linux-firmware git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware/linux-firmware @@ -197,7 +187,7 @@ curl -s $mirror/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-supp git clone https://$github/sbwml/package_kernel_rtl8822cs package/kernel/rtl8822cs # RTC -if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ]; then +if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ] || [ "$platform" = "rk3576" ]; then curl -s $mirror/openwrt/patch/rtc/sysfixtime > package/base-files/files/etc/init.d/sysfixtime chmod 755 package/base-files/files/etc/init.d/sysfixtime fi diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 32963df9d..4ae62829a 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -9,7 +9,7 @@ rm -rf feeds/packages/lang/node git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages/lang/node -b packages-24.10 # default settings -git clone https://$github/sbwml/default-settings package/new/default-settings -b openwrt-24.10 +git clone https://$github/sbwml/default-settings package/new/default-settings -b openwrt-25.12 # wwan git clone https://$github/sbwml/wwan-packages package/new/wwan --depth=1 @@ -139,6 +139,7 @@ git clone https://$github/sbwml/luci-app-mentohust package/new/mentohust # custom packages rm -rf feeds/packages/utils/coremark git clone https://$github/sbwml/openwrt_pkgs package/new/custom --depth=1 +rm -rf package/new/custom/ddns-scripts-aliyun # coremark - prebuilt with gcc15 if [ "$platform" = "rk3568" ]; then curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-4-threads > package/new/custom/coremark/src/musl/coremark.aarch64 diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index e6a45a7e8..f74846ae9 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -6,13 +6,10 @@ sed -i 's/^\([[:space:]]*DEPENDS:=.*\)$/\1 @BROKEN/' package/kernel/rtl8812au-ct/Makefile # cryptodev-linux -mkdir -p package/kernel/cryptodev-linux/patches -curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch > package/kernel/cryptodev-linux/patches/0005-Fix-cryptodev_verbosity-sysctl-for-Linux-6.11-rc1.patch -curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.12/0006-Exclude-unused-struct-since-Linux-6.5.patch > package/kernel/cryptodev-linux/patches/0006-Exclude-unused-struct-since-Linux-6.5.patch curl -s $mirror/openwrt/patch/packages-patches/cryptodev-linux/6.18/900-fix-linux-6.18.patch > package/kernel/cryptodev-linux/patches/900-fix-linux-6.18.patch # gpio-button-hotplug -curl -s $mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.12.patch | patch -p1 +curl -s $mirror/openwrt/patch/packages-patches/gpio-button-hotplug/fix-linux-6.18.patch | patch -p1 # gpio-nct5104d curl -s $mirror/openwrt/patch/packages-patches/gpio-nct5104d/fix-linux-6.18.patch | patch -p1 @@ -41,20 +38,16 @@ popd # nat46 mkdir -p package/kernel/nat46/patches -curl -s $mirror/openwrt/patch/packages-patches/nat46/100-fix-build-with-kernel-6.9.patch > package/kernel/nat46/patches/100-fix-build-with-kernel-6.9.patch -curl -s $mirror/openwrt/patch/packages-patches/nat46/101-fix-build-with-kernel-6.12.patch > package/kernel/nat46/patches/101-fix-build-with-kernel-6.12.patch curl -s $mirror/openwrt/patch/packages-patches/nat46/102-fix-build-with-kernel-6.18.patch > package/kernel/nat46/patches/102-fix-build-with-kernel-6.18.patch # openvswitch sed -i '/ovs_kmod_openvswitch_depends/a\\t\ \ +kmod-sched-act-sample \\' feeds/packages/net/openvswitch/Makefile # rtpengine -curl -s $mirror/openwrt/patch/packages-patches/rtpengine/900-fix-linux-6.12-11.5.1.18.patch > feeds/telephony/net/rtpengine/patches/900-fix-linux-6.12-11.5.1.18.patch curl -s $mirror/openwrt/patch/packages-patches/rtpengine/901-fix-build-for-linux-6.18.patch > feeds/telephony/net/rtpengine/patches/901-fix-build-for-linux-6.18.patch -# ubootenv-nvram - 6.12 -mkdir -p package/kernel/ubootenv-nvram/patches -curl -s $mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-make-ubootenv_remove-return-void-for-linux-6.12.patch > package/kernel/ubootenv-nvram/patches/010-make-ubootenv_remove-return-void-for-linux-6.12.patch +# ubootenv-nvram - 6.18 +curl -s $mirror/openwrt/patch/packages-patches/ubootenv-nvram/010-fix-build-for-linux-6.18.patch | patch -p1 # usb-serial-xr_usb_serial_common: remove package # Now that we have packaged the upstream driver[1] and only board[2] that @@ -67,10 +60,6 @@ rm -rf feeds/packages/kernel/v4l2loopback mkdir -p feeds/packages/kernel/v4l2loopback curl -s $mirror/openwrt/patch/packages-patches/v4l2loopback/Makefile > feeds/packages/kernel/v4l2loopback/Makefile -# xtables-addons -curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/301-fix-build-with-linux-6.12.patch > feeds/packages/net/xtables-addons/patches/301-fix-build-with-linux-6.12.patch -curl -s $mirror/openwrt/patch/packages-patches/xtables-addons/302-fix-build-for-linux-6.12rc2.patch > feeds/packages/net/xtables-addons/patches/302-fix-build-for-linux-6.12rc2.patch - # telephony pushd feeds/telephony # dahdi-linux @@ -78,14 +67,11 @@ pushd feeds/telephony git clone https://$github/sbwml/feeds_telephony_libs_dahdi-linux libs/dahdi-linux -b v6.18 popd -# routing - batman-adv fix build with linux-6.12 -curl -s $mirror/openwrt/patch/packages-patches/batman-adv/901-fix-linux-6.12rc2-builds.patch > feeds/routing/batman-adv/patches/901-fix-linux-6.12rc2-builds.patch - # clang if [ "$KERNEL_CLANG_LTO" = "y" ]; then # xtables-addons module rm -rf feeds/packages/net/xtables-addons - git clone https://$github/sbwml/kmod_packages_net_xtables-addons feeds/packages/net/xtables-addons -b v6.18 + git clone https://$github/sbwml/kmod_packages_net_xtables-addons feeds/packages/net/xtables-addons -b openwrt-25.12 # netatop sed -i 's/$(MAKE)/$(KERNEL_MAKE)/g' feeds/packages/admin/netatop/Makefile curl -s $mirror/openwrt/patch/packages-patches/clang/netatop/900-fix-build-with-clang.patch > feeds/packages/admin/netatop/patches/900-fix-build-with-clang.patch diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 70d0b7bad..9dffb5f48 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,14 +1,20 @@ #!/bin/bash -# 24.10 xcrypt -if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then - git clone https://github.com/openwrt/openwrt -b openwrt-25.12 --depth=1 openwrt-25.12 - mv openwrt-25.12/package/libs/xcrypt package/libs - rm -rf openwrt-25.12 +if [ "$KERNEL_CLANG_LTO" = "y" ]; then + # linux-atm + curl -s $mirror/openwrt/patch/packages-patches/clang/linux-atm/openwrt-fix-build-with-clang.patch | patch -p1 +fi + +if [ "$ENABLE_MOLD" = "y" ]; then + # attr + sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile fi # apk-tools -curl -s $mirror/openwrt/patch/apk-tools/9999-hack-for-linux-pre-releases.patch > package/system/apk/patches/9999-hack-for-linux-pre-releases.patch +curl -s $mirror/openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch > package/system/apk/patches/999-hack-for-linux-pre-releases.patch + +# irqbalance +curl -s $mirror/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch > feeds/packages/utils/irqbalance/patches/900-meson-add-numa-option.patch # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile @@ -20,54 +26,24 @@ sed -i '/USE_QUIC_OPENSSL_COMPAT/d' feeds/packages/net/haproxy/Makefile rm -rf package/network/utils/xdp-tools git clone https://$github/sbwml/package_network_utils_xdp-tools package/network/utils/xdp-tools -# fix gcc14 -if [ "$USE_GCC14" = y ] || [ "$USE_GCC15" = y ]; then - # linux-atm - rm -rf package/network/utils/linux-atm - git clone https://$github/sbwml/package_network_utils_linux-atm package/network/utils/linux-atm - # glibc - # Added the compiler flag -Wno-implicit-function-declaration to suppress - # warnings about implicit function declarations during the build process. - # This change addresses build issues in environments where some functions - # are used without prior declaration. - if [ "$ENABLE_GLIBC" = "y" ]; then - # perl - sed -i "/Target perl/i\TARGET_CFLAGS_PERL += -Wno-implicit-function-declaration -Wno-int-conversion\n" feeds/packages/lang/perl/Makefile - sed -i '/HOST_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/lang/perl/Makefile - # lucihttp - sed -i "/TARGET_CFLAGS/i\TARGET_CFLAGS += -Wno-implicit-function-declaration" feeds/luci/contrib/package/lucihttp/Makefile - # rpcd - sed -i "/TARGET_LDFLAGS/i\TARGET_CFLAGS += -Wno-implicit-function-declaration" package/system/rpcd/Makefile - # ucode-mod-lua - sed -i "/Build\/Configure/i\TARGET_CFLAGS += -Wno-implicit-function-declaration" feeds/luci/contrib/package/ucode-mod-lua/Makefile - # luci-base - sed -i "s/-DNDEBUG/-DNDEBUG -Wno-implicit-function-declaration/g" feeds/luci/modules/luci-base/src/Makefile - # uhttpd - sed -i "/Package\/uhttpd\/install/i\TARGET_CFLAGS += -Wno-implicit-function-declaration\n" package/network/services/uhttpd/Makefile - # shadow - sed -i '/TARGET_LDFLAGS/d' feeds/packages/utils/shadow/Makefile - sed -i 's/libxcrypt/openssl/g' feeds/packages/utils/shadow/Makefile - fi -fi +# ksmbd luci +sed -i 's/0666/0644/g;s/0777/0755/g' feeds/luci/applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js -# fix gcc-15 -if [ "$USE_GCC15" = y ]; then - sed -i '/TARGET_CFLAGS/ s/$/ -Wno-error=unterminated-string-initialization/' package/libs/mbedtls/Makefile - # elfutils - curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/elfutils/901-backends-fix-string-initialization-error-on-gcc15.patch > package/libs/elfutils/patches/901-backends-fix-string-initialization-error-on-gcc15.patch - # libwebsockets - mkdir -p feeds/packages/libs/libwebsockets/patches - curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/libwebsockets/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libwebsockets/patches/901-fix-string-initialization-error-on-gcc15.patch - # libxcrypt - mkdir -p feeds/packages/libs/libxcrypt/patches - curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15/libxcrypt/901-fix-string-initialization-error-on-gcc15.patch > feeds/packages/libs/libxcrypt/patches/901-fix-string-initialization-error-on-gcc15.patch -fi +# ksmbd tools +sed -i 's/0666/0644/g;s/0777/0755/g' feeds/packages/net/ksmbd-tools/files/ksmbd.config.example +sed -i 's/bind interfaces only = yes/bind interfaces only = no/g' feeds/packages/net/ksmbd-tools/files/ksmbd.conf.template -# fix gcc-15.0.1 C23 +# perf +curl -s $mirror/openwrt/patch/openwrt-6.x/musl/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch > toolchain/musl/patches/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch +curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Makefile + +# kselftests-bpf +curl -s $mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package/devel/kselftests-bpf/Makefile + +####################################### + +# fix gcc-15.0.1 gnu17 if [ "$USE_GCC15" = y ]; then - # gmp - mkdir -p package/libs/gmp/patches - curl -s $mirror/openwrt/patch/openwrt-6.x/gcc-15-c23/gmp/001-fix-build-with-gcc-15.patch > package/libs/gmp/patches/001-fix-build-with-gcc-15.patch # libtirpc sed -i '/TARGET_CFLAGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/libtirpc/Makefile # libsepol @@ -94,12 +70,8 @@ if [ "$USE_GCC15" = y ]; then sed -i '/MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' package/libs/libselinux/Makefile # avahi sed -i '/TARGET_CFLAGS +=/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/avahi/Makefile - # bash - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/bash/Makefile # xl2tpd sed -i '/ifneq (0,0)/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/xl2tpd/Makefile - # dnsmasq - sed -i '/MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' package/network/services/dnsmasq/Makefile # bluez sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/bluez/Makefile # e2fsprogs @@ -127,26 +99,3 @@ if [ "$USE_GCC15" = y ]; then # jq sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/jq/Makefile fi - -# ksmbd luci -sed -i 's/0666/0644/g;s/0777/0755/g' feeds/luci/applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js - -# ksmbd tools -sed -i 's/0666/0644/g;s/0777/0755/g' feeds/packages/net/ksmbd-tools/files/ksmbd.config.example -sed -i 's/bind interfaces only = yes/bind interfaces only = no/g' feeds/packages/net/ksmbd-tools/files/ksmbd.conf.template - -# vim - fix E1187: Failed to source defaults.vim -pushd feeds/packages - curl -s $mirror/openwrt/patch/vim/0001-vim-fix-renamed-defaults-config-file.patch | patch -p1 -popd - -# perf -curl -s $mirror/openwrt/patch/openwrt-6.x/musl/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch > toolchain/musl/patches/990-add-typedefs-for-Elf64_Relr-and-Elf32_Relr.patch -curl -s $mirror/openwrt/patch/openwrt-6.x/perf/Makefile > package/devel/perf/Makefile - -# kselftests-bpf -curl -s $mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package/devel/kselftests-bpf/Makefile - -# sms-tools -mkdir -p feeds/packages/utils/sms-tool/patches -curl -s $mirror/openwrt/patch/packages-patches/sms-tools/900-fix-incompatible-pointer-type-error-for-signal-function.patch > feeds/packages/utils/sms-tool/patches/900-fix-incompatible-pointer-type-error-for-signal-function.patch diff --git a/tags/openwrt-tag.sh b/tags/openwrt-tag.sh index 0f7e8c7db..779ffda28 100755 --- a/tags/openwrt-tag.sh +++ b/tags/openwrt-tag.sh @@ -8,5 +8,5 @@ else cat tags.json | jq . > jq.json 2>&1 fi -grep name jq.json | grep v24 | head -1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g' | sed 's/v//g' > v24 +grep name jq.json | grep v25 | head -1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g' | sed 's/v//g' > v25 rm -f tags.json jq.json diff --git a/tags/v24 b/tags/v24 deleted file mode 100644 index c1a8e0edf..000000000 --- a/tags/v24 +++ /dev/null @@ -1 +0,0 @@ -24.10.5 diff --git a/tags/v25 b/tags/v25 new file mode 100644 index 000000000..0c62572d7 --- /dev/null +++ b/tags/v25 @@ -0,0 +1 @@ +25.12.0-rc1 From 90e81ff222f95dae0da40e1087bb61acbf5dad00 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 28 Dec 2025 13:30:59 +0800 Subject: [PATCH 327/425] golang: update to 1.26.x Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 4ae62829a..6af5f77f7 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -1,8 +1,8 @@ #!/bin/bash -e -# golang 1.25 +# golang 1.26 rm -rf feeds/packages/lang/golang -git clone https://$github/sbwml/packages_lang_golang -b 25.x feeds/packages/lang/golang +git clone https://$github/sbwml/packages_lang_golang -b 26.x feeds/packages/lang/golang # node - prebuilt rm -rf feeds/packages/lang/node From 5ae931ff33bfff9a06b081f1df53599707103d18 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 28 Dec 2025 13:36:03 +0800 Subject: [PATCH 328/425] build.sh: Add iStoreOS style Signed-off-by: sbwml --- README.md | 17 ++++++++++------- openwrt/build.sh | 7 +++++++ openwrt/scripts/02-prepare_package.sh | 5 ++++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 532105b7b..2b2ea05f6 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,14 @@ export BUILD_FAST=y export MINIMAL_BUILD=y ``` +### 构建 iStoreOS 样式 +##### 包含 iStoreOS 的商店、状态页 +##### 只需在构建固件前执行以下命令即可构建 iStoreOS 样式 + +``` +export ENABLE_ISTORE=y +``` + ### 更改 LAN IP 地址 ##### 自定义默认 LAN IP 地址 ##### 只需在构建固件前执行以下命令即可覆盖默认 LAN 地址(默认:10.0.0.1) @@ -232,13 +240,8 @@ bash <(curl -sS https://init2.cooluc.com/build.sh) dev x86_64 ```diff # script url - if [ "$isCN" = "CN" ]; then -- export mirror=https://init.cooluc.com -+ export mirror=https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master - else -- export mirror=https://init2.cooluc.com -+ export mirror=https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master - fi +-export mirror=https://init.cooluc.com ++export mirror=https://raw.githubusercontent.com/你的用户名/r4s_build_script/refs/heads/master ``` ### 三、在本地 Linux 执行基于你自己仓库的构建脚本,即可编译所需固件 diff --git a/openwrt/build.sh b/openwrt/build.sh index ee7fbd418..44ac74353 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -205,6 +205,7 @@ print_status "BUILD_FAST" "$BUILD_FAST" print_status "ENABLE_CCACHE" "$ENABLE_CCACHE" print_status "MINIMAL_BUILD" "$MINIMAL_BUILD" print_status "STD_BUILD" "$STD_BUILD" +print_status "ENABLE_ISTORE" "$ENABLE_ISTORE" print_status "KERNEL_CLANG_LTO" "$KERNEL_CLANG_LTO" "$GREEN_COLOR" "$YELLOW_COLOR" "\n" # clean old files @@ -350,6 +351,12 @@ export ENABLE_LTO=$ENABLE_LTO echo 'CONFIG_PACKAGE_numactl=y' >> .config } +# istore +[ "$ENABLE_ISTORE" = "y" ] && { + echo 'CONFIG_PACKAGE_luci-app-store=y' >> .config + echo 'CONFIG_PACKAGE_luci-app-quickstart=y' >> .config +} + # mold [ "$ENABLE_MOLD" = "y" ] && echo 'CONFIG_USE_MOLD=y' >> .config diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 6af5f77f7..83fbf4687 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -14,6 +14,9 @@ git clone https://$github/sbwml/default-settings package/new/default-settings -b # wwan git clone https://$github/sbwml/wwan-packages package/new/wwan --depth=1 +# istore +git clone https://github.com/sbwml/package_new_istore package/new/istore --depth=1 + # luci-app-filemanager rm -rf feeds/luci/applications/luci-app-filemanager git clone https://$github/sbwml/luci-app-filemanager package/new/luci-app-filemanager @@ -118,7 +121,7 @@ git clone https://$github/UnblockNeteaseMusic/luci-app-unblockneteasemusic packa sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new/luci-app-unblockneteasemusic/root/usr/share/luci/menu.d/luci-app-unblockneteasemusic.json # Theme -git clone https://$github/sbwml/luci-theme-argon package/new/luci-theme-argon --depth=1 +git clone https://$github/sbwml/luci-theme-argon -b openwrt-25.12 package/new/luci-theme-argon --depth=1 # Mosdns git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 From c92ae86020c5f14c43e6da98b42c5a04df5b9438 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 29 Dec 2025 12:50:12 +0800 Subject: [PATCH 329/425] config-common/std: add luci-app-bandix Signed-off-by: sbwml --- openwrt/25-config-common | 1 + openwrt/25-config-std-common | 1 + openwrt/scripts/02-prepare_package.sh | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index 8fc323dc9..ffd9ec461 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -83,6 +83,7 @@ CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y CONFIG_PACKAGE_luci-app-aria2=y CONFIG_PACKAGE_luci-app-autoreboot=y +CONFIG_PACKAGE_luci-app-bandix=y CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index 366b01e88..2995e6ea2 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -69,6 +69,7 @@ CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y CONFIG_PACKAGE_luci-app-autoreboot=y +CONFIG_PACKAGE_luci-app-bandix=y CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 83fbf4687..97d73da4d 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -14,8 +14,12 @@ git clone https://$github/sbwml/default-settings package/new/default-settings -b # wwan git clone https://$github/sbwml/wwan-packages package/new/wwan --depth=1 +# bandix +git clone https://$github/timsaya/openwrt-bandix package/new/bandix --depth=1 +git clone https://$github/timsaya/luci-app-bandix package/new/luci-app-bandix --depth=1 + # istore -git clone https://github.com/sbwml/package_new_istore package/new/istore --depth=1 +git clone https://$github/sbwml/package_new_istore package/new/istore --depth=1 # luci-app-filemanager rm -rf feeds/luci/applications/luci-app-filemanager From 57093fe8b2d83518b82b75f25f3d4304315aa92f Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 29 Dec 2025 18:23:34 +0800 Subject: [PATCH 330/425] nat6: switch to openwrt-25.12 branch Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index b53c0622c..cf48564f1 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -147,7 +147,7 @@ fi git clone https://$gitea/sbwml/nft-fullcone package/new/nft-fullcone # IPv6 NAT -git clone https://$github/sbwml/packages_new_nat6 package/new/nat6 +git clone https://$github/sbwml/packages_new_nat6 package/new/nat6 -b openwrt-25.12 # natflow git clone https://$github/sbwml/package_new_natflow package/new/natflow From a970afd518c5507c9228a1ac67740da46a193387 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 29 Dec 2025 20:47:45 +0800 Subject: [PATCH 331/425] config-common: drop luci-app-bandix * remove package due to poor ARM performance Signed-off-by: sbwml --- openwrt/25-config-common | 2 +- openwrt/25-config-std-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index ffd9ec461..da9b7b933 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -83,7 +83,7 @@ CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y CONFIG_PACKAGE_luci-app-aria2=y CONFIG_PACKAGE_luci-app-autoreboot=y -CONFIG_PACKAGE_luci-app-bandix=y +# CONFIG_PACKAGE_luci-app-bandix is not set CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index 2995e6ea2..925a93d5f 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -69,7 +69,7 @@ CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y CONFIG_PACKAGE_luci-app-autoreboot=y -CONFIG_PACKAGE_luci-app-bandix=y +# CONFIG_PACKAGE_luci-app-bandix is not set CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y From a5f55e07dea2fb991a455f0d3a5e23d5423d9c72 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 30 Dec 2025 20:23:07 +0800 Subject: [PATCH 332/425] build.sh: add ota support to std build Signed-off-by: sbwml --- openwrt/build.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openwrt/build.sh b/openwrt/build.sh index 44ac74353..fb1451cba 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -321,6 +321,7 @@ if [ "$MINIMAL_BUILD" = "y" ]; then echo 'VERSION_TYPE="minimal"' >> package/base-files/files/usr/lib/os-release elif [ "$STD_BUILD" = "y" ]; then curl -s $mirror/openwrt/25-config-std-common >> .config + echo 'VERSION_TYPE="standard"' >> package/base-files/files/usr/lib/os-release else curl -s $mirror/openwrt/25-config-common >> .config [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config @@ -501,6 +502,8 @@ if [ "$platform" = "x86_64" ]; then mkdir -p ota if [ "$MINIMAL_BUILD" = "y" ]; then OTA_URL="https://dev.cooluc.com/minimal/x86_64" + elif [ "$STD_BUILD" = "y" ]; then + OTA_URL="https://dev.cooluc.com/standard/x86_64" else OTA_URL="https://dev.cooluc.com/release/x86_64" fi @@ -549,6 +552,8 @@ elif [ "$platform" = "armv8" ]; then mkdir -p ota if [ "$MINIMAL_BUILD" = "y" ]; then OTA_URL="https://dev.cooluc.com/minimal/armv8" + elif [ "$STD_BUILD" = "y" ]; then + OTA_URL="https://dev.cooluc.com/standard/armv8" else OTA_URL="https://dev.cooluc.com/release/armv8" fi @@ -592,6 +597,8 @@ else mkdir -p ota if [ "$MINIMAL_BUILD" = "y" ]; then OTA_URL="https://dev.cooluc.com/minimal/$model" + elif [ "$STD_BUILD" = "y" ]; then + OTA_URL="https://dev.cooluc.com/standard/$model" else OTA_URL="https://dev.cooluc.com/release/$model" fi From c2101e80ea1ad33a458bd84c55f7bcaf6a23aac0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 30 Dec 2025 20:23:59 +0800 Subject: [PATCH 333/425] odhcp6c: fix work for openwrt-25.12.0-rc1 Signed-off-by: sbwml --- ...-update-to-25.12-Git-HEAD-2025-12-29.patch | 68 +++++++++++++++++++ openwrt/scripts/05-fix-source.sh | 5 ++ 2 files changed, 73 insertions(+) create mode 100644 openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch diff --git a/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch b/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch new file mode 100644 index 000000000..3af58bb70 --- /dev/null +++ b/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch @@ -0,0 +1,68 @@ +From 948b1b564dcf0afa84882cb79691951d41ff51a5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Mon, 29 Dec 2025 18:25:47 +0100 +Subject: [PATCH] odhcp6c: update to 25.12 Git HEAD (2025-12-29) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +699cc61568b6 dhcpv6: omit IA_NA on Request +8774d3c0ec9c dhcpv6: dhcpv6_send: convert whitespaces to tabs +11abe3790431 ra: convert if block to switch +c05b803d38e9 odhcp6c: do cleanup at exit +6aa4e491a869 config: fix potential memory leaks in error paths +235cdc97d73b all: add log helpers +6e3272d609d3 dhcpv6: clarifying comments +04aea4e3f870 dhcpv6: offload FQDN construction to init_dhcpv6 +449ce8374275 dhcpv6: migrate dhcpv6_response_is_valid to switch case + +https://github.com/openwrt/odhcp6c/compare/5ab3203875ad...699cc61568b6 + +Signed-off-by: Álvaro Fernández Rojas +--- + package/network/ipv6/odhcp6c/Makefile | 6 +++--- + package/network/ipv6/odhcp6c/files/dhcpv6.sh | 4 ++-- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/package/network/ipv6/odhcp6c/Makefile b/package/network/ipv6/odhcp6c/Makefile +index 952831e47a..9741046cfe 100644 +--- a/package/network/ipv6/odhcp6c/Makefile ++++ b/package/network/ipv6/odhcp6c/Makefile +@@ -12,9 +12,9 @@ PKG_RELEASE:=1 + + PKG_SOURCE_PROTO:=git + PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcp6c.git +-PKG_SOURCE_DATE:=2025-12-18 +-PKG_SOURCE_VERSION:=5ab3203875ad938ea85f6d0ceebdff113c355656 +-PKG_MIRROR_HASH:=4de69fe364be2d302329cdc86d4d93820e73c82f00d788a536cf947076a4ded3 ++PKG_SOURCE_DATE:=2025-12-29 ++PKG_SOURCE_VERSION:=699cc61568b6816783d17d57dda4ef7851198528 ++PKG_MIRROR_HASH:=e8a42c429ed83660ccc04d69e3bcbf0056d8e96e08caff0f14518150b89ec352 + + PKG_MAINTAINER:=Álvaro Fernández Rojas + PKG_LICENSE:=GPL-2.0 +diff --git a/package/network/ipv6/odhcp6c/files/dhcpv6.sh b/package/network/ipv6/odhcp6c/files/dhcpv6.sh +index 59a6021c5c..d59e988991 100755 +--- a/package/network/ipv6/odhcp6c/files/dhcpv6.sh ++++ b/package/network/ipv6/odhcp6c/files/dhcpv6.sh +@@ -42,7 +42,7 @@ proto_dhcpv6_init_config() { + proto_config_add_boolean sourcefilter + proto_config_add_boolean keep_ra_dnslifetime + proto_config_add_int "ra_holdoff" +- proto_config_add_boolean verbose ++ proto_config_add_int 'verbose:range(0, 7)' + proto_config_add_boolean dynamic + } + +@@ -116,7 +116,7 @@ proto_dhcpv6_setup() { + + [ -n "$ra_holdoff" ] && append opts "-m$ra_holdoff" + +- [ "$verbose" = "1" ] && append opts "-v" ++ [ -n "$verbose" ] && append opts "-l$verbose" + + json_for_each_item proto_dhcpv6_add_sendopts sendopts opts + +-- +2.43.5 + diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 9dffb5f48..738e7a3ac 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,5 +1,10 @@ #!/bin/bash +# odhcp6c - fix for openwrt-25.12.0-rc1 +if [ "$branch" = "25.12.0-rc1" ]; then + curl -s $mirror/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch | patch -p1 +fi + if [ "$KERNEL_CLANG_LTO" = "y" ]; then # linux-atm curl -s $mirror/openwrt/patch/packages-patches/clang/linux-atm/openwrt-fix-build-with-clang.patch | patch -p1 From 122d93d28387eebff62510580cedf5f61e5124ed Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 30 Dec 2025 21:25:49 +0800 Subject: [PATCH 334/425] fix c2101e80 Signed-off-by: sbwml --- openwrt/scripts/05-fix-source.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 738e7a3ac..37efba2ff 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,7 +1,7 @@ #!/bin/bash -# odhcp6c - fix for openwrt-25.12.0-rc1 -if [ "$branch" = "25.12.0-rc1" ]; then +# odhcp6c - fix for openwrt-v25.12.0-rc1 +if [ "$branch" = "v25.12.0-rc1" ]; then curl -s $mirror/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch | patch -p1 fi From 32b93385486898211a1b15b5dbd14845fb0937e9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 6 Jan 2026 12:21:19 +0800 Subject: [PATCH 335/425] linux-6.18: bump to 6.18.3 Signed-off-by: sbwml --- .../999-hack-for-linux-pre-releases.patch | 23 ------------------- ...den-app-limited-rate-sample-detectio.patch | 2 +- ...napshot-packets-in-flight-at-transmi.patch | 2 +- ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 2 +- ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 2 +- ...djust-skb-tx.in_flight-upon-merge-in.patch | 2 +- ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 2 +- ...ecord-app-limited-status-of-TLP-repa.patch | 2 +- ...nform-CC-module-of-losses-repaired-b.patch | 2 +- ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 8 +++---- ...-linux-kernel-to-support-shortcut-fe.patch | 16 ++++++------- openwrt/patch/openwrt-6.x/perf/Makefile | 12 ++++++---- openwrt/scripts/05-fix-source.sh | 13 +++++------ tags/kernel-6.18 | 4 ++-- 14 files changed, 36 insertions(+), 56 deletions(-) delete mode 100644 openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch diff --git a/openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch b/openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch deleted file mode 100644 index 2355c9a86..000000000 --- a/openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/src/apk_adb.c -+++ b/src/apk_adb.c -@@ -194,7 +194,6 @@ static struct adb_scalar_schema scalar_name = { - - static adb_val_t version_fromstring(struct adb *db, apk_blob_t val) - { -- if (!apk_version_validate(val)) return ADB_ERROR(APKE_PKGVERSION_FORMAT); - return adb_w_blob(db, val); - } - -@@ -355,12 +354,6 @@ static int dependency_fromstring(struct adb_obj *obj, apk_blob_t bdep) - apk_blob_t bname, bver; - int op; - -- if (apk_dep_parse(bdep, &bname, &op, &bver) != 0) goto fail; -- if ((op & APK_DEPMASK_CHECKSUM) != APK_DEPMASK_CHECKSUM && -- !apk_version_validate(bver)) goto fail; -- -- if (apk_blob_spn(bname, APK_CTYPE_DEPENDENCY_NAME, NULL, NULL)) goto fail; -- - adb_wo_blob(obj, ADBI_DEP_NAME, bname); - if (op != APK_DEPMASK_ANY) { - adb_wo_blob(obj, ADBI_DEP_VERSION, bver); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index c3c4cad79..ac7b44451 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -32,7 +32,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4035,6 +4035,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4042,6 +4042,7 @@ static int tcp_ack(struct sock *sk, cons prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; rs.prior_in_flight = tcp_packets_in_flight(tp); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index efd8b5c4a..6bdb31735 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -56,7 +56,7 @@ Signed-off-by: Alexandre Frade struct rate_sample *rs); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2926,6 +2926,7 @@ static bool tcp_write_xmit(struct sock * +@@ -2937,6 +2937,7 @@ static bool tcp_write_xmit(struct sock * skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); tcp_init_tso_segs(skb, mss_now); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index 4effc6e48..77b5ed7a5 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -28,7 +28,7 @@ Signed-off-by: Alexandre Frade struct tcp_congestion_ops { --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4133,6 +4133,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4140,6 +4140,7 @@ static int tcp_ack(struct sock *sk, cons lost = tp->lost - lost; /* freshly marked lost */ rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index 60e303797..59d457bcb 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1282,7 +1282,12 @@ static void tcp_verify_retransmit_hint(s +@@ -1289,7 +1289,12 @@ static void tcp_verify_retransmit_hint(s */ static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) { diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch index c23eaa407..d8ccc70e5 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch @@ -39,7 +39,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1652,6 +1652,17 @@ static bool tcp_shifted_skb(struct sock +@@ -1659,6 +1659,17 @@ static bool tcp_shifted_skb(struct sock WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); tcp_skb_pcount_add(skb, -pcount); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 482fdaabe..995d27ef4 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5902,13 +5902,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5909,13 +5909,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch index 3a917dfb2..7624a8084 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade u8 accecn_minlen:2,/* Minimum length of AccECN option sent */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -3162,6 +3162,7 @@ void tcp_send_loss_probe(struct sock *sk +@@ -3173,6 +3173,7 @@ void tcp_send_loss_probe(struct sock *sk if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index a4139dee0..204395fff 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3915,6 +3915,7 @@ static void tcp_process_tlp_ack(struct s +@@ -3922,6 +3922,7 @@ static void tcp_process_tlp_ack(struct s /* ACK advances: there was a loss, so reduce cwnd. Reset * tlp_high_seq in tcp_init_cwnd_reduction() */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index 2bea4fabf..1c20db9a5 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3898,7 +3898,8 @@ static int tcp_replace_ts_recent(struct +@@ -3905,7 +3905,8 @@ static int tcp_replace_ts_recent(struct /* This routine deals with acks during a TLP episode and ends an episode by * resetting tlp_high_seq. Ref: TLP algorithm in RFC8985 */ @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade { struct tcp_sock *tp = tcp_sk(sk); -@@ -3926,6 +3927,11 @@ static void tcp_process_tlp_ack(struct s +@@ -3933,6 +3934,11 @@ static void tcp_process_tlp_ack(struct s FLAG_NOT_DUP | FLAG_DATA_SACKED))) { /* Pure dupack: original and TLP probe arrived; no loss */ tp->tlp_high_seq = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade } } -@@ -4125,7 +4131,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4132,7 +4138,7 @@ static int tcp_ack(struct sock *sk, cons tcp_in_ack_event(sk, flag); if (tp->tlp_high_seq) @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade if (tcp_ack_is_dubious(sk, flag)) { if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4176,7 +4182,7 @@ no_queue: +@@ -4183,7 +4189,7 @@ no_queue: tcp_ack_probe(sk); if (tp->tlp_high_seq) diff --git a/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 8646f4811..96fd6569b 100644 --- a/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -17,7 +17,7 @@ Signed-off-by: Xiaoping Fan --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h -@@ -69,6 +69,9 @@ void brioctl_set(int (*hook)(struct net +@@ -70,6 +70,9 @@ void brioctl_set(int (*hook)(struct net void __user *uarg)); int br_ioctl_call(struct net *net, unsigned int cmd, void __user *uarg); @@ -52,7 +52,7 @@ Signed-off-by: Xiaoping Fan const struct nf_ct_event_notifier *nb); --- a/net/Kconfig +++ b/net/Kconfig -@@ -520,6 +520,9 @@ config FAILOVER +@@ -526,6 +526,9 @@ config FAILOVER migration of VMs with direct attached VFs by failing over to the paravirtual datapath when the VF is unplugged. @@ -64,7 +64,7 @@ Signed-off-by: Xiaoping Fan select DIMLIB --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c -@@ -765,6 +765,26 @@ void br_port_flags_change(struct net_bri +@@ -766,6 +766,26 @@ void br_port_flags_change(struct net_bri br_recalculate_neigh_suppress_enabled(br); } @@ -109,9 +109,9 @@ Signed-off-by: Xiaoping Fan + } +#endif - len = skb->len; - trace_net_dev_start_xmit(skb, dev); -@@ -5809,6 +5818,11 @@ void netdev_rx_handler_unregister(struct + #ifdef CONFIG_ETHERNET_PACKET_MANGLE + if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) +@@ -5814,6 +5823,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5858,6 +5872,10 @@ static int __netif_receive_skb_core(stru +@@ -5863,6 +5877,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5902,6 +5920,16 @@ another_round: +@@ -5907,6 +5925,16 @@ another_round: goto out; } diff --git a/openwrt/patch/openwrt-6.x/perf/Makefile b/openwrt/patch/openwrt-6.x/perf/Makefile index 1fc6915e6..4eeb9813d 100644 --- a/openwrt/patch/openwrt-6.x/perf/Makefile +++ b/openwrt/patch/openwrt-6.x/perf/Makefile @@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=perf PKG_VERSION:=$(LINUX_VERSION) -PKG_RELEASE:=5 +PKG_RELEASE:=7 PKG_BUILD_FLAGS:=no-mips16 no-lto PKG_BUILD_PARALLEL:=1 @@ -30,8 +30,8 @@ define Package/perf DEPENDS:= +libelf +libdw +PACKAGE_libunwind:libunwind +libpthread +librt +objdump @!IN_SDK @KERNEL_PERF_EVENTS \ +PACKAGE_libbfd:libbfd +PACKAGE_libopcodes:libopcodes +libtraceevent TITLE:=Linux performance monitoring tool - VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE) - URL:=http://www.kernel.org + VERSION:=$(LINUX_VERSION)-r$(PKG_RELEASE) + URL:=https://www.kernel.org endef define Package/perf/description @@ -50,12 +50,16 @@ MAKE_FLAGS = \ NO_LZMA=1 \ NO_BACKTRACE=1 \ NO_LIBNUMA=1 \ + NO_SLANG=1 \ NO_GTK2=1 \ NO_LIBAUDIT=1 \ NO_LIBCRYPTO=1 \ NO_LIBUNWIND=1 \ NO_LIBZSTD=1 \ NO_LIBCAP=1 \ + NO_JEVENTS=1 \ + NO_SHELLCHECK=1 \ + BUILD_BPF_SKEL= \ CROSS_COMPILE="$(TARGET_CROSS)" \ CC="$(TARGET_CC)" \ LD="$(TARGET_CROSS)ld" \ @@ -71,7 +75,7 @@ MAKE_FLAGS = \ O=$(PKG_BUILD_DIR) \ prefix=/usr -ifeq ($(LINUX_KARCH),powerpc) +ifneq ($(filter $(LINUX_KARCH),powerpc mips),) MAKE_FLAGS += NO_AUXTRACE=1 endif diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 37efba2ff..e16e4c6b8 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,9 +1,11 @@ #!/bin/bash -# odhcp6c - fix for openwrt-v25.12.0-rc1 -if [ "$branch" = "v25.12.0-rc1" ]; then - curl -s $mirror/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch | patch -p1 -fi +# odhcp6c-2025-10 +rm -rf package/network/ipv6/odhcp6c +git clone https://$gitea/sbwml/package_network_ipv6_odhcp6c package/network/ipv6/odhcp6c +#if [ "$branch" = "v25.12.0-rc1" ]; then +# curl -s $mirror/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch | patch -p1 +#fi if [ "$KERNEL_CLANG_LTO" = "y" ]; then # linux-atm @@ -15,9 +17,6 @@ if [ "$ENABLE_MOLD" = "y" ]; then sed -i '/PKG_BUILD_PARALLEL/aPKG_BUILD_FLAGS:=no-mold' feeds/packages/utils/attr/Makefile fi -# apk-tools -curl -s $mirror/openwrt/patch/apk-tools/999-hack-for-linux-pre-releases.patch > package/system/apk/patches/999-hack-for-linux-pre-releases.patch - # irqbalance curl -s $mirror/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch > feeds/packages/utils/irqbalance/patches/900-meson-add-numa-option.patch diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 7540006ec..5cb79fa45 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .2 -LINUX_KERNEL_HASH-6.18.2 = 558c6bbab749492b34f99827fe807b0039a744693c21d3a7e03b3a48edaab96a +LINUX_VERSION-6.18 = .3 +LINUX_KERNEL_HASH-6.18.3 = 7a8879167b89c4bae077d6f39c4f2130769f05dbdad2aad914adab9afb7d7f9a From 2dd02ab0378744f4d34eb6ce9a7d4a4d1f77ed0d Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 7 Jan 2026 12:36:09 +0800 Subject: [PATCH 336/425] nginx: switch to openwrt-25.12 branch Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index cf48564f1..6ef77afa1 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -211,7 +211,7 @@ git clone https://$gitea/sbwml/luci-app-upnp feeds/luci/applications/luci-app-up # nginx - latest version rm -rf feeds/packages/net/nginx -git clone https://$github/sbwml/feeds_packages_net_nginx feeds/packages/net/nginx -b openwrt-24.10 +git clone https://$github/sbwml/feeds_packages_net_nginx feeds/packages/net/nginx -b openwrt-25.12 sed -i 's/procd_set_param stdout 1/procd_set_param stdout 0/g;s/procd_set_param stderr 1/procd_set_param stderr 0/g' feeds/packages/net/nginx/files/nginx.init # nginx - ubus From 9bbf92c5f304791e5cfd57f6b39e226e0304b955 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 7 Jan 2026 12:36:36 +0800 Subject: [PATCH 337/425] x86: disable r8126 & r8127 for now Signed-off-by: sbwml --- openwrt/25-config-musl-x86 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/25-config-musl-x86 b/openwrt/25-config-musl-x86 index 09eee43fb..edecb50e1 100644 --- a/openwrt/25-config-musl-x86 +++ b/openwrt/25-config-musl-x86 @@ -37,8 +37,8 @@ CONFIG_PACKAGE_kmod-ngbe=y CONFIG_PACKAGE_kmod-nvme=y CONFIG_PACKAGE_kmod-r8101=y CONFIG_PACKAGE_kmod-r8125=y -CONFIG_PACKAGE_kmod-r8126=y -CONFIG_PACKAGE_kmod-r8127=y +# CONFIG_PACKAGE_kmod-r8126 is not set +# CONFIG_PACKAGE_kmod-r8127 is not set CONFIG_PACKAGE_kmod-r8168=y # CONFIG_PACKAGE_kmod-r8169 is not set CONFIG_PACKAGE_kmod-txgbe=y From c225c03ccc16a4d20137358f8bd136ecf513325b Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 8 Jan 2026 18:02:44 +0800 Subject: [PATCH 338/425] Revert "x86: disable r8126 & r8127 for now" This reverts commit 9bbf92c5f304791e5cfd57f6b39e226e0304b955. --- openwrt/25-config-musl-x86 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/25-config-musl-x86 b/openwrt/25-config-musl-x86 index edecb50e1..09eee43fb 100644 --- a/openwrt/25-config-musl-x86 +++ b/openwrt/25-config-musl-x86 @@ -37,8 +37,8 @@ CONFIG_PACKAGE_kmod-ngbe=y CONFIG_PACKAGE_kmod-nvme=y CONFIG_PACKAGE_kmod-r8101=y CONFIG_PACKAGE_kmod-r8125=y -# CONFIG_PACKAGE_kmod-r8126 is not set -# CONFIG_PACKAGE_kmod-r8127 is not set +CONFIG_PACKAGE_kmod-r8126=y +CONFIG_PACKAGE_kmod-r8127=y CONFIG_PACKAGE_kmod-r8168=y # CONFIG_PACKAGE_kmod-r8169 is not set CONFIG_PACKAGE_kmod-txgbe=y From eb84e601f36ad1e4d63965eefdfb06921916deb2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 8 Jan 2026 18:03:06 +0800 Subject: [PATCH 339/425] OpenWrt 25.12.0-rc2 Signed-off-by: sbwml --- tags/v25 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v25 b/tags/v25 index 0c62572d7..72dcf815a 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.0-rc1 +25.12.0-rc2 From 7cef86ad7adaa903befebcb3485fa2bc47efd795 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 11 Jan 2026 12:45:00 +0800 Subject: [PATCH 340/425] linux-6.18: bump to 6.18.4 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 5cb79fa45..7a4ea4f09 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .3 -LINUX_KERNEL_HASH-6.18.3 = 7a8879167b89c4bae077d6f39c4f2130769f05dbdad2aad914adab9afb7d7f9a +LINUX_VERSION-6.18 = .4 +LINUX_KERNEL_HASH-6.18.4 = f850139ca5f79c1bf6bb8b32f92e212aadca97bdaef8a83a7cf4ac4d6a525fab From a6eb366669982e67d2d0e830ad76c984e2f2b3bb Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 18 Jan 2026 13:59:09 +0800 Subject: [PATCH 341/425] linux-6.18: bump to 6.18.6 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- tags/kernel-tag.sh | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 7a4ea4f09..a57f887b5 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .4 -LINUX_KERNEL_HASH-6.18.4 = f850139ca5f79c1bf6bb8b32f92e212aadca97bdaef8a83a7cf4ac4d6a525fab +LINUX_VERSION-6.18 = .6 +LINUX_KERNEL_HASH-6.18.6 = 472497197b2f68d4dbf1bc32cc6dc669ca220ff4c0eb0dc39a9cff9a88f9a31b diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index b2762e968..58d80547a 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -4,11 +4,28 @@ set -e ROOT="./" -# LTS -KERNEL_VERSION=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "stable") | .version' | tail -n1` -KERNEL_HASH=`curl -s https://raw.githubusercontent.com/andreoss/kernel-overlay/refs/heads/master/sources.json | jq -r '.[] | select(.package.name == "stable") | .checksum' | tail -n1` -TAG=`echo $KERNEL_VERSION | awk -F"." '{print $3}'` +# 获取所有 stable 版本中最新的 6.18.x +KERNEL_VERSION=$(curl -s https://www.kernel.org/releases.json \ + | jq -r '.releases[] | select(.moniker=="stable") | .version' \ + | grep '^6\.18\.' \ + | sort -V \ + | tail -n1) -[ -z $TAG ] && TAG="" || TAG=.$TAG +# 从自建镜像获取对应 tar.xz 的 SHA256 +KERNEL_HASH=$(curl -s https://us.cooluc.com/kernel/v6.x/sha256sums.asc \ + | grep "linux-$KERNEL_VERSION.tar.xz" \ + | awk '{print $1}') + +# 如果没有匹配到 SHA256,立即退出 +if [ -z "$KERNEL_HASH" ]; then + echo "Error: SHA256 for linux-$KERNEL_VERSION.tar.xz not found. Mirror may not be synced." + exit 1 +fi + +# 提取 TAG(第三段版本号) +TAG=$(echo "$KERNEL_VERSION" | awk -F"." '{print $3}') +[ -z "$TAG" ] && TAG="" || TAG=".$TAG" + +# 输出到文件 echo "LINUX_VERSION-6.18 = $TAG -LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > $ROOT/kernel-6.18 +LINUX_KERNEL_HASH-$KERNEL_VERSION = $KERNEL_HASH" > "$ROOT/kernel-6.18" From dff35b7abef0fa1a9766a14fffe85b1a327185b9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 18 Jan 2026 14:08:56 +0800 Subject: [PATCH 342/425] config: add video decoder driver for nanopi-r76s * h.264/hevc Signed-off-by: sbwml --- openwrt/25-config-musl-r76s | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openwrt/25-config-musl-r76s b/openwrt/25-config-musl-r76s index c00172533..be6600842 100644 --- a/openwrt/25-config-musl-r76s +++ b/openwrt/25-config-musl-r76s @@ -23,14 +23,17 @@ CONFIG_TARGET_ROOTFS_PARTSIZE=944 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set -# SDIO Wireless / Bluetooth +### SDIO Wireless / Bluetooth CONFIG_PACKAGE_kmod-bluetooth=y CONFIG_PACKAGE_kmod-rtw88-8822cs=y CONFIG_PACKAGE_rtl8822cs-firmware=y -### Video Support +### HDMI CONFIG_PACKAGE_kmod-drm-rockchip=y CONFIG_PACKAGE_kmod-drm-panfrost=y +### Video Decoder +CONFIG_PACKAGE_kmod-rkvdec + ### Rocket NPU CONFIG_PACKAGE_kmod-rocket-rockchip=y From a977b22bd866649135e99d4550e3d0a4dc642c6a Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 18 Jan 2026 19:44:43 +0800 Subject: [PATCH 343/425] fix 25-config-musl-r76s Signed-off-by: sbwml --- openwrt/25-config-musl-r76s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/25-config-musl-r76s b/openwrt/25-config-musl-r76s index be6600842..4f8cfbb66 100644 --- a/openwrt/25-config-musl-r76s +++ b/openwrt/25-config-musl-r76s @@ -33,7 +33,7 @@ CONFIG_PACKAGE_kmod-drm-rockchip=y CONFIG_PACKAGE_kmod-drm-panfrost=y ### Video Decoder -CONFIG_PACKAGE_kmod-rkvdec +CONFIG_PACKAGE_kmod-rkvdec=y ### Rocket NPU CONFIG_PACKAGE_kmod-rocket-rockchip=y From 47844c32709d5e06a178b6cc60cb2109f0d498ad Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 25 Jan 2026 21:14:32 +0800 Subject: [PATCH 344/425] linux-6.18: bump to 6.18.7 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index a57f887b5..7d75318b4 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .6 -LINUX_KERNEL_HASH-6.18.6 = 472497197b2f68d4dbf1bc32cc6dc669ca220ff4c0eb0dc39a9cff9a88f9a31b +LINUX_VERSION-6.18 = .7 +LINUX_KERNEL_HASH-6.18.7 = b726a4d15cf9ae06219b56d87820776e34d89fbc137e55fb54a9b9c3015b8f1e From 220327fe562f42fc630eb812f6945699002cb01c Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 25 Jan 2026 21:20:52 +0800 Subject: [PATCH 345/425] luci-app-package-manager: support installing uploaded APK without signature Add a new "install-upload" action that runs apk with `--allow-untrusted` for locally uploaded packages. Signed-off-by: sbwml --- ...-manager-support-installing-uploaded.patch | 54 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 5 ++ 2 files changed, 59 insertions(+) create mode 100644 openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch diff --git a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch new file mode 100644 index 000000000..23cc76a50 --- /dev/null +++ b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch @@ -0,0 +1,54 @@ +From 8a57210e3b7c6aae95788b3b4a8cbabad0dd7912 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 25 Jan 2026 21:06:05 +0800 +Subject: [PATCH] luci-app-package-manager: support installing uploaded APK + without signature + +Add a new "install-upload" action that runs apk with +--allow-untrusted for locally uploaded packages. + +Signed-off-by: sbwml +--- + .../htdocs/luci-static/resources/view/package-manager.js | 2 +- + .../root/usr/libexec/package-manager-call | 5 ++++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js +index 8a70b4bd29..ced8785dcc 100644 +--- a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js ++++ b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js +@@ -1084,7 +1084,7 @@ function handleUpload(ev) + }, _('Cancel')), ' ', + E('div', { + 'class': 'btn cbi-button-action', +- 'data-command': 'install', ++ 'data-command': 'install-upload', + 'data-package': path, + 'click': function(ev) { + handlePkg(ev).finally(function() { +diff --git a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call +index 3a4175783a..7fa58f9060 100755 +--- a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call ++++ b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call +@@ -27,7 +27,7 @@ case "$action" in + find "${lists_dir:-/usr/lib/opkg/lists}" -type f '!' -name '*.sig' | xargs -r gzip -cd + fi + ;; +- install|update|upgrade|remove) ++ install|install-upload|update|upgrade|remove) + ( + cmd="$ipkg_bin" + +@@ -37,6 +37,9 @@ case "$action" in + install) + action="add" + ;; ++ install-upload) ++ action="add --allow-untrusted" ++ ;; + update) + action="update" + ;; +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 6ef77afa1..7a4736ab3 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -265,6 +265,11 @@ sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/l # luci-compat - remove extra line breaks from description sed -i '/
/d' feeds/luci/modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm +# luci-app-package-manager +pushd feeds/luci + curl -s $mirror/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch | patch -p1 +popd + # urngd - 2020-01-21 rm -rf package/system/urngd git clone https://$github/sbwml/package_system_urngd package/system/urngd From 223e97ca0cf61606012f4ed60044d81f82593b75 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 25 Jan 2026 21:21:45 +0800 Subject: [PATCH 346/425] OpenWrt 25.12.0-rc3 Signed-off-by: sbwml --- tags/v25 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v25 b/tags/v25 index 72dcf815a..effa1ce5b 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.0-rc2 +25.12.0-rc3 From 6a7949c31926049e19772ac682c844c91ed12c34 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 7 Feb 2026 22:49:48 +0800 Subject: [PATCH 347/425] linux-6.18: bump to 6.18.9 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 7d75318b4..472874950 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .7 -LINUX_KERNEL_HASH-6.18.7 = b726a4d15cf9ae06219b56d87820776e34d89fbc137e55fb54a9b9c3015b8f1e +LINUX_VERSION-6.18 = .9 +LINUX_KERNEL_HASH-6.18.9 = 030115ff8fb4cb536d8449dc40ebc3e314e86ba1b316a6ae21091a11cc930578 From e96836c662f3149535bdfa7bdd895d4011fb50b1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 7 Feb 2026 22:49:56 +0800 Subject: [PATCH 348/425] irqbalance: fix build on snapshot Signed-off-by: sbwml --- .../901-meson-disable-numa-option-by-default.patch | 11 +++++++++++ openwrt/scripts/05-fix-source.sh | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 openwrt/patch/packages-patches/irqbalance/901-meson-disable-numa-option-by-default.patch diff --git a/openwrt/patch/packages-patches/irqbalance/901-meson-disable-numa-option-by-default.patch b/openwrt/patch/packages-patches/irqbalance/901-meson-disable-numa-option-by-default.patch new file mode 100644 index 000000000..73a6efaa0 --- /dev/null +++ b/openwrt/patch/packages-patches/irqbalance/901-meson-disable-numa-option-by-default.patch @@ -0,0 +1,11 @@ +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -2,7 +2,7 @@ option('capng', type : 'feature', + description : 'Build with libcap-ng support', + ) + +-option('numa', type : 'feature', value: 'enabled', ++option('numa', type : 'feature', value: 'disabled', + description : 'Build with numa support', + ) + diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index e16e4c6b8..f760fc42e 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -18,7 +18,11 @@ if [ "$ENABLE_MOLD" = "y" ]; then fi # irqbalance -curl -s $mirror/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch > feeds/packages/utils/irqbalance/patches/900-meson-add-numa-option.patch +if [ "$version" = "rc2" ]; then + curl -s $mirror/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch > feeds/packages/utils/irqbalance/patches/900-meson-add-numa-option.patch +else + curl -s $mirror/openwrt/patch/packages-patches/irqbalance/901-meson-disable-numa-option-by-default.patch > feeds/packages/utils/irqbalance/patches/901-meson-disable-numa-option-by-default.patch +fi # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile From 44125e89de647f9d13377b45f7bd1d204ed73006 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Feb 2026 18:04:19 +0800 Subject: [PATCH 349/425] docker: Update to version 29.2.1 Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 14 ++++++-------- openwrt/scripts/02-prepare_package.sh | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 7a4736ab3..d18239f09 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -186,14 +186,12 @@ git clone https://$github/sbwml/feeds_packages_net_curl feeds/packages/net/curl # Docker rm -rf feeds/luci/applications/luci-app-dockerman -git clone https://$gitea/sbwml/luci-app-dockerman -b nft feeds/luci/applications/luci-app-dockerman -if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then - rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} - git clone https://$gitea/sbwml/packages_utils_docker feeds/packages/utils/docker - git clone https://$gitea/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd - git clone https://$gitea/sbwml/packages_utils_containerd feeds/packages/utils/containerd - git clone https://$gitea/sbwml/packages_utils_runc feeds/packages/utils/runc -fi +git clone https://$github/sbwml/luci-app-dockerman feeds/luci/applications/luci-app-dockerman +rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} +git clone https://$github/sbwml/packages_utils_docker feeds/packages/utils/docker +git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd +git clone https://$github/sbwml/packages_utils_containerd feeds/packages/utils/containerd +git clone https://$github/sbwml/packages_utils_runc feeds/packages/utils/runc # procps-ng - top sed -i 's/enable-skill/enable-skill --disable-modern-top/g' feeds/packages/utils/procps-ng/Makefile diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 97d73da4d..873de1317 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -69,8 +69,8 @@ pushd feeds/luci popd # samba4 - bump version -rm -rf feeds/packages/net/samba4 -git clone https://$github/sbwml/feeds_packages_net_samba4 feeds/packages/net/samba4 +#rm -rf feeds/packages/net/samba4 +#git clone https://$github/sbwml/feeds_packages_net_samba4 feeds/packages/net/samba4 # enable multi-channel sed -i '/workgroup/a \\n\t## enable multi-channel' feeds/packages/net/samba4/files/smb.conf.template sed -i '/enable multi-channel/a \\tserver multi channel support = yes' feeds/packages/net/samba4/files/smb.conf.template From 426d427f6bf8756c28b01b8417301ee15e590a13 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Feb 2026 18:07:46 +0800 Subject: [PATCH 350/425] coremark: rebuild with GCC15.2.0 -Ofast & 16 threads Signed-off-by: sbwml --- openwrt/patch/coremark/README.md | 2 +- .../coremark/coremark.aarch64-16-threads | Bin 65540 -> 67616 bytes .../patch/coremark/coremark.aarch64-4-threads | Bin 65540 -> 0 bytes .../patch/coremark/coremark.aarch64-6-threads | Bin 65540 -> 0 bytes openwrt/scripts/02-prepare_package.sh | 10 +--------- 5 files changed, 2 insertions(+), 10 deletions(-) mode change 100755 => 100644 openwrt/patch/coremark/coremark.aarch64-16-threads delete mode 100755 openwrt/patch/coremark/coremark.aarch64-4-threads delete mode 100755 openwrt/patch/coremark/coremark.aarch64-6-threads diff --git a/openwrt/patch/coremark/README.md b/openwrt/patch/coremark/README.md index f692ccdc8..4a1e7421c 100644 --- a/openwrt/patch/coremark/README.md +++ b/openwrt/patch/coremark/README.md @@ -1 +1 @@ -# CoreMark (aarch64) prebuilt with GCC15 +# CoreMark (aarch64) prebuilt with GCC15.2.0 diff --git a/openwrt/patch/coremark/coremark.aarch64-16-threads b/openwrt/patch/coremark/coremark.aarch64-16-threads old mode 100755 new mode 100644 index 8342442fec297fa9237f93b865846197404d5312..982a2c1d2178c2bf30179952a7fdda5b26bd2667 GIT binary patch literal 67616 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 literal 65540 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 E2Z49xfdBvi diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 873de1317..bbf33b17d 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -148,15 +148,7 @@ rm -rf feeds/packages/utils/coremark git clone https://$github/sbwml/openwrt_pkgs package/new/custom --depth=1 rm -rf package/new/custom/ddns-scripts-aliyun # coremark - prebuilt with gcc15 -if [ "$platform" = "rk3568" ]; then - curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-4-threads > package/new/custom/coremark/src/musl/coremark.aarch64 -elif [ "$platform" = "rk3576" ]; then - curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-16-threads > package/new/custom/coremark/src/musl/coremark.aarch64 -elif [ "$platform" = "rk3399" ]; then - curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-6-threads > package/new/custom/coremark/src/musl/coremark.aarch64 -elif [ "$platform" = "armv8" ]; then - curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-16-threads > package/new/custom/coremark/src/musl/coremark.aarch64 -fi +curl -s $mirror/openwrt/patch/coremark/coremark.aarch64-16-threads > package/new/custom/coremark/src/musl/coremark.aarch64 # luci-compat - fix translation sed -i 's/<%:Up%>/<%:Move up%>/g' feeds/luci/modules/luci-compat/luasrc/view/cbi/tblsection.htm From 374eadb27245988e51f1dafba056ead7733d2b64 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 9 Feb 2026 20:27:28 +0800 Subject: [PATCH 351/425] OpenWrt 25.12.0-rc4 Signed-off-by: sbwml --- tags/v25 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v25 b/tags/v25 index effa1ce5b..6071b26c5 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.0-rc3 +25.12.0-rc4 From ccff9d8a02f87d31bc868c4502cd8933121fac18 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 11 Feb 2026 01:18:18 +0800 Subject: [PATCH 352/425] luci-app-package-manager: fix `install-upload` acl permission Signed-off-by: sbwml --- ...-manager-support-installing-uploaded.patch | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch index 23cc76a50..896ad379a 100644 --- a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch +++ b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch @@ -1,20 +1,18 @@ -From 8a57210e3b7c6aae95788b3b4a8cbabad0dd7912 Mon Sep 17 00:00:00 2001 +From 6430d15ff19b9885b3aedb5b228b0c3a5652ef29 Mon Sep 17 00:00:00 2001 From: sbwml -Date: Sun, 25 Jan 2026 21:06:05 +0800 +Date: Wed, 11 Feb 2026 01:11:00 +0800 Subject: [PATCH] luci-app-package-manager: support installing uploaded APK without signature -Add a new "install-upload" action that runs apk with ---allow-untrusted for locally uploaded packages. - Signed-off-by: sbwml --- .../htdocs/luci-static/resources/view/package-manager.js | 2 +- .../root/usr/libexec/package-manager-call | 5 ++++- - 2 files changed, 5 insertions(+), 2 deletions(-) + .../root/usr/share/rpcd/acl.d/luci-app-package-manager.json | 1 + + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js -index 8a70b4bd29..ced8785dcc 100644 +index 8a70b4b..ced8785 100644 --- a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js +++ b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js @@ -1084,7 +1084,7 @@ function handleUpload(ev) @@ -27,7 +25,7 @@ index 8a70b4bd29..ced8785dcc 100644 'click': function(ev) { handlePkg(ev).finally(function() { diff --git a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call -index 3a4175783a..7fa58f9060 100755 +index 3a41757..7fa58f9 100755 --- a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call +++ b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call @@ -27,7 +27,7 @@ case "$action" in @@ -49,6 +47,18 @@ index 3a4175783a..7fa58f9060 100755 update) action="update" ;; +diff --git a/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json b/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json +index 8d55186..31eb0b6 100644 +--- a/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json ++++ b/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json +@@ -20,6 +20,7 @@ + "file": { + "/usr/libexec/package-manager-call install": [ "exec" ], + "/usr/libexec/package-manager-call install *": [ "exec" ], ++ "/usr/libexec/package-manager-call install-upload": [ "exec" ], + "/usr/libexec/package-manager-call remove *": [ "exec" ], + "/usr/libexec/package-manager-call update": [ "exec" ], + "/usr/libexec/package-manager-call upgrade": [ "exec" ], -- 2.43.5 From cf98fb970f258ba76b334b0f239abe7fb43e80e2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 15 Feb 2026 21:53:09 +0800 Subject: [PATCH 353/425] apk: disable hsts Signed-off-by: sbwml --- .../apk/9000-io_url_wget-disbale-hsts.patch | 25 +++++++++++++++++++ openwrt/scripts/00-prepare_base.sh | 4 +++ 2 files changed, 29 insertions(+) create mode 100644 openwrt/patch/apk/9000-io_url_wget-disbale-hsts.patch diff --git a/openwrt/patch/apk/9000-io_url_wget-disbale-hsts.patch b/openwrt/patch/apk/9000-io_url_wget-disbale-hsts.patch new file mode 100644 index 000000000..9250c5e80 --- /dev/null +++ b/openwrt/patch/apk/9000-io_url_wget-disbale-hsts.patch @@ -0,0 +1,25 @@ +From f53b64feb573f286cdd6bc8cd2a5601caf82cdef Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Sun, 15 Feb 2026 21:48:33 +0800 +Subject: [PATCH] io_url_wget: disbale hsts + +Signed-off-by: sbwml +--- + src/io_url_wget.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/io_url_wget.c b/src/io_url_wget.c +index 2d5cd4a..28a0851 100644 +--- a/src/io_url_wget.c ++++ b/src/io_url_wget.c +@@ -21,6 +21,7 @@ struct apk_istream *apk_io_url_istream(const char *url, time_t since) + + argv[i++] = "wget"; + argv[i++] = "-q"; ++ argv[i++] = "--no-hsts"; + argv[i++] = "-T"; + argv[i++] = wget_timeout; + if (wget_no_check_certificate) argv[i++] = "--no-check-certificate"; +-- +2.43.5 + diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index d18239f09..7e0b63108 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -223,6 +223,10 @@ curl -s $mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/ # netifd curl -s $mirror/openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.patch | patch -p1 +# apk +mkdir -p package/system/apk/patches +curl -s $mirror/openwrt/patch/apk/9000-io_url_wget-disbale-hsts.patch > package/system/opkg/patches/9000-io_url_wget-disbale-hsts.patch + # opkg mkdir -p package/system/opkg/patches curl -s $mirror/openwrt/patch/opkg/900-opkg-download-disable-hsts.patch > package/system/opkg/patches/900-opkg-download-disable-hsts.patch From 05e5dd576e3d92a58d60b0016f982b6ad04285d7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 15 Feb 2026 21:53:36 +0800 Subject: [PATCH 354/425] linux-6.18: bump to 6.18.10 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 472874950..acc50f088 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .9 -LINUX_KERNEL_HASH-6.18.9 = 030115ff8fb4cb536d8449dc40ebc3e314e86ba1b316a6ae21091a11cc930578 +LINUX_VERSION-6.18 = .10 +LINUX_KERNEL_HASH-6.18.10 = d6d377161741ada2fab28eed69143277634a2aeb5e3883e50c031588ede48ede From 7589abcfd5b85cfc3eb1e3a81c8d366505b0ccc1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 16 Feb 2026 20:02:31 +0800 Subject: [PATCH 355/425] firewall4: disable fullcone nat by default Signed-off-by: sbwml --- .../999-01-firewall4-add-fullcone-support.patch | 2 +- .../999-02-firewall4-add-bcm-fullconenat-support.patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch index 1ca27c189..ace8764a0 100644 --- a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch +++ b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch @@ -25,7 +25,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. option forward REJECT # Uncomment this line to disable ipv6 rules # option disable_ipv6 1 -+ option fullcone 1 ++ option fullcone 0 config zone option name lan diff --git a/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch b/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch index a054ec4a5..f8ad58671 100644 --- a/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch +++ b/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch @@ -3,7 +3,7 @@ @@ -6,6 +6,9 @@ config defaults # Uncomment this line to disable ipv6 rules # option disable_ipv6 1 - option fullcone 1 + option fullcone 0 +# 0 - use nft_fullcone originated from Chion82 +# 1 - use bcm fullconenat from broadcom ASUS Merlin + option brcmfullcone 0 From ee87217906afa4149cd22030c1e942ab4627e8b0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 16 Feb 2026 20:03:03 +0800 Subject: [PATCH 356/425] linux-6.18: bump to 6.18.11 Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/crypto.mk | 339 +++++++++++++++++--- tags/kernel-6.18 | 4 +- 2 files changed, 296 insertions(+), 47 deletions(-) diff --git a/openwrt/patch/openwrt-6.x/modules/crypto.mk b/openwrt/patch/openwrt-6.x/modules/crypto.mk index 6f814ab00..45d39de35 100644 --- a/openwrt/patch/openwrt-6.x/modules/crypto.mk +++ b/openwrt/patch/openwrt-6.x/modules/crypto.mk @@ -116,7 +116,7 @@ $(eval $(call KernelPackage,crypto-ccm)) define KernelPackage/crypto-chacha20poly1305 TITLE:=ChaCha20-Poly1305 AEAD support, RFC7539 (used by strongSwan IPsec VPN) - DEPENDS:=+kmod-crypto-aead +kmod-crypto-manager +kmod-crypto-lib-poly1305 + DEPENDS:=+kmod-crypto-aead +kmod-crypto-manager +!LINUX_6_12:kmod-crypto-lib-poly1305 KCONFIG:=CONFIG_CRYPTO_CHACHA20POLY1305 FILES:=$(LINUX_DIR)/crypto/chacha20poly1305.ko AUTOLOAD:=$(call AutoLoad,09,chacha20poly1305) @@ -143,8 +143,9 @@ define KernelPackage/crypto-crc32 DEPENDS:=+kmod-crypto-hash KCONFIG:=CONFIG_CRYPTO_CRC32 HIDDEN:=1 - FILES:=$(LINUX_DIR)/crypto/crc32c-cryptoapi.ko - AUTOLOAD:=$(call AutoLoad,04,crc32c-cryptoapi,1) + FILES:=$(LINUX_DIR)/crypto/crc32_generic.ko@lt6.18 \ + $(LINUX_DIR)/crypto/crc32-cryptoapi.ko@ge6.18 + AUTOLOAD:=$(call AutoLoad,04,LINUX_6_12:crc32_generic !LINUX_6_12:crc32-cryptoapi,1) $(call AddDepends/crypto) endef @@ -155,8 +156,9 @@ define KernelPackage/crypto-crc32c TITLE:=CRC32c CRC module DEPENDS:=+kmod-crypto-hash KCONFIG:=CONFIG_CRYPTO_CRC32C - FILES:=$(LINUX_DIR)/crypto/crc32c-cryptoapi.ko - AUTOLOAD:=$(call AutoLoad,04,crc32c-cryptoapi,1) + FILES:=$(LINUX_DIR)/crypto/crc32c_generic.ko@lt6.18 \ + $(LINUX_DIR)/crypto/crc32c-cryptoapi.ko@ge6.18 + AUTOLOAD:=$(call AutoLoad,04,LINUX_6_12:crc32c_generic !LINUX_6_12:crc32c-cryptoapi,1) $(call AddDepends/crypto) endef @@ -251,6 +253,7 @@ $(eval $(call KernelPackage,crypto-echainiv)) define KernelPackage/crypto-engine TITLE:=Crypto engine + HIDDEN:=1 KCONFIG:=CONFIG_CRYPTO_ENGINE FILES:=$(LINUX_DIR)/crypto/crypto_engine.ko AUTOLOAD:=$(call AutoLoad,09,crypto_engine) @@ -520,7 +523,7 @@ $(eval $(call KernelPackage,crypto-hw-talitos)) define KernelPackage/crypto-hw-eip93 TITLE:=MTK EIP93 crypto module - DEPENDS:=@TARGET_ramips_mt7621 \ + DEPENDS:=@(TARGET_ramips_mt7621||TARGET_airoha) \ +kmod-crypto-authenc \ +kmod-crypto-des \ +kmod-crypto-md5 \ @@ -529,23 +532,28 @@ define KernelPackage/crypto-hw-eip93 KCONFIG:= \ CONFIG_CRYPTO_HW=y \ CONFIG_CRYPTO_DEV_EIP93 \ - CONFIG_CRYPTO_DEV_EIP93_AES=y \ - CONFIG_CRYPTO_DEV_EIP93_DES=y \ - CONFIG_CRYPTO_DEV_EIP93_AEAD=y \ + CONFIG_CRYPTO_DEV_EIP93_AES=y@lt6.18 \ + CONFIG_CRYPTO_DEV_EIP93_DES=y@lt6.18 \ + CONFIG_CRYPTO_DEV_EIP93_AEAD=y@lt6.18 \ CONFIG_CRYPTO_DEV_EIP93_GENERIC_SW_MAX_LEN=256 \ CONFIG_CRYPTO_DEV_EIP93_AES_128_SW_MAX_LEN=512 - FILES:=$(LINUX_DIR)/drivers/crypto/mtk-eip93/crypto-hw-eip93.ko + FILES:=$(LINUX_DIR)/drivers/crypto/mtk-eip93/crypto-hw-eip93.ko@lt6.18 \ + $(LINUX_DIR)/drivers/crypto/inside-secure/eip93/crypto-hw-eip93.ko@ge6.18 AUTOLOAD:=$(call AutoLoad,09,crypto-hw-eip93) $(call AddDepends/crypto) endef define KernelPackage/crypto-hw-eip93/description Kernel module to enable EIP-93 Crypto engine as found -in the Mediatek MT7621 SoC. +in Mediatek MT7621 and Airoha SoCs. It enables DES/3DES/AES ECB/CBC/CTR and IPSEC offload with authenc(hmac(sha1/sha256), aes/cbc/rfc3686) endef +define KernelPackage/crypto-hw-eip93/airoha + FILES:=$(LINUX_DIR)/drivers/crypto/inside-secure/eip93/crypto-hw-eip93.ko +endef + $(eval $(call KernelPackage,crypto-hw-eip93)) define KernelPackage/crypto-kpp @@ -566,6 +574,44 @@ define KernelPackage/crypto-lib-chacha20 $(call AddDepends/crypto) endef +ifeq ($(KERNEL_PATCHVER),6.12) +ifndef CONFIG_TARGET_uml +define KernelPackage/crypto-lib-chacha20/x86_64 + KCONFIG+=CONFIG_CRYPTO_CHACHA20_X86_64 + FILES+=$(LINUX_DIR)/arch/x86/crypto/chacha-x86_64.ko +endef +endif + +# Note that a non-neon fallback implementation is available on arm32 when +# NEON is not supported, hence all arm targets can utilize lib-chacha20/arm +define KernelPackage/crypto-lib-chacha20/arm + KCONFIG+=CONFIG_CRYPTO_CHACHA20_NEON + FILES:=$(LINUX_DIR)/arch/arm/crypto/chacha-neon.ko +endef + +KernelPackage/crypto-lib-chacha20/armeb=$(KernelPackage/crypto-lib-chacha20/arm) + +define KernelPackage/crypto-lib-chacha20/aarch64 + KCONFIG+=CONFIG_CRYPTO_CHACHA20_NEON + FILES+=$(LINUX_DIR)/arch/arm64/crypto/chacha-neon.ko +endef + +define KernelPackage/crypto-lib-chacha20/mips32r2 + KCONFIG+=CONFIG_CRYPTO_CHACHA_MIPS + FILES:=$(LINUX_DIR)/arch/mips/crypto/chacha-mips.ko +endef + +ifeq ($(CONFIG_CPU_MIPS32_R2),y) + KernelPackage/crypto-lib-chacha20/$(ARCH)=\ + $(KernelPackage/crypto-lib-chacha20/mips32r2) +endif + +ifdef KernelPackage/crypto-lib-chacha20/$(ARCH) + KernelPackage/crypto-lib-chacha20/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-lib-chacha20/$(ARCH)) +endif +endif + $(eval $(call KernelPackage,crypto-lib-chacha20)) @@ -585,14 +631,35 @@ define KernelPackage/crypto-lib-curve25519 KCONFIG:=CONFIG_CRYPTO_LIB_CURVE25519 HIDDEN:=1 FILES:= \ - $(LINUX_DIR)/lib/crypto/libcurve25519.ko - $(call AddDepends/crypto,+PACKAGE_kmod-crypto-kpp:kmod-crypto-kpp) + $(LINUX_DIR)/lib/crypto/libcurve25519.ko \ + $(LINUX_DIR)/lib/crypto/libcurve25519-generic.ko@lt6.18 + $(call AddDepends/crypto,+kmod-crypto-kpp) +endef + +ifeq ($(KERNEL_PATCHVER),6.12) +ifndef CONFIG_TARGET_uml +define KernelPackage/crypto-lib-curve25519/x86_64 + KCONFIG+=CONFIG_CRYPTO_CURVE25519_X86 + FILES+=$(LINUX_DIR)/arch/x86/crypto/curve25519-x86_64.ko endef +endif -define KernelPackage/crypto-lib-curve25519/config - imply PACKAGE_kmod-crypto-kpp +define KernelPackage/crypto-lib-curve25519/arm-neon + KCONFIG+=CONFIG_CRYPTO_CURVE25519_NEON + FILES+=$(LINUX_DIR)/arch/arm/crypto/curve25519-neon.ko endef +ifeq ($(ARCH)-$(CONFIG_KERNEL_MODE_NEON),arm-y) + KernelPackage/crypto-lib-curve25519/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-lib-curve25519/arm-neon) +endif + +ifdef KernelPackage/crypto-lib-curve25519/$(ARCH) + KernelPackage/crypto-lib-curve25519/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-lib-curve25519/$(ARCH)) +endif +endif + $(eval $(call KernelPackage,crypto-lib-curve25519)) @@ -601,9 +668,44 @@ define KernelPackage/crypto-lib-poly1305 KCONFIG:=CONFIG_CRYPTO_LIB_POLY1305 HIDDEN:=1 FILES:=$(LINUX_DIR)/lib/crypto/libpoly1305.ko - $(call AddDepends/crypto) + $(call AddDepends/crypto,+kmod-crypto-hash) +endef + +ifeq ($(KERNEL_PATCHVER),6.12) +ifndef CONFIG_TARGET_uml +define KernelPackage/crypto-lib-poly1305/x86_64 + KCONFIG+=CONFIG_CRYPTO_POLY1305_X86_64 + FILES+=$(LINUX_DIR)/arch/x86/crypto/poly1305-x86_64.ko +endef +endif + +define KernelPackage/crypto-lib-poly1305/arm + KCONFIG+=CONFIG_CRYPTO_POLY1305_ARM + FILES:=$(LINUX_DIR)/arch/arm/crypto/poly1305-arm.ko +endef + +KernelPackage/crypto-lib-poly1305/armeb=$(KernelPackage/crypto-lib-poly1305/arm) + +define KernelPackage/crypto-lib-poly1305/aarch64 + KCONFIG+=CONFIG_CRYPTO_POLY1305_NEON + FILES:=$(LINUX_DIR)/arch/arm64/crypto/poly1305-neon.ko +endef + +define KernelPackage/crypto-lib-poly1305/mips + KCONFIG+=CONFIG_CRYPTO_POLY1305_MIPS + FILES:=$(LINUX_DIR)/arch/mips/crypto/poly1305-mips.ko endef +KernelPackage/crypto-lib-poly1305/mipsel=$(KernelPackage/crypto-lib-poly1305/mips) +KernelPackage/crypto-lib-poly1305/mips64=$(KernelPackage/crypto-lib-poly1305/mips) +KernelPackage/crypto-lib-poly1305/mips64el=$(KernelPackage/crypto-lib-poly1305/mips) + +ifdef KernelPackage/crypto-lib-poly1305/$(ARCH) + KernelPackage/crypto-lib-poly1305/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-lib-poly1305/$(ARCH)) +endif +endif + $(eval $(call KernelPackage,crypto-lib-poly1305)) @@ -640,13 +742,27 @@ define KernelPackage/crypto-md5 CONFIG_CRYPTO_MD5 \ CONFIG_CRYPTO_MD5_OCTEON \ CONFIG_CRYPTO_MD5_PPC - FILES:= \ - $(LINUX_DIR)/crypto/md5.ko \ - $(LINUX_DIR)/lib/crypto/libmd5.ko - AUTOLOAD:=$(call AutoLoad,09,md5) + FILES:=$(LINUX_DIR)/crypto/md5.ko \ + $(LINUX_DIR)/lib/crypto/libmd5.ko@ge6.18 + AUTOLOAD:=$(call AutoLoad,09,md5 !LINUX_6_12:libmd5) $(call AddDepends/crypto) endef +define KernelPackage/crypto-md5/octeon + FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-md5.ko + AUTOLOAD+=$(call AutoLoad,09,octeon-md5) +endef + +define KernelPackage/crypto-md5/powerpc + FILES+=$(LINUX_DIR)/arch/powerpc/crypto/md5-ppc.ko + AUTOLOAD+=$(call AutoLoad,09,md5-ppc) +endef + +ifdef KernelPackage/crypto-md5/$(ARCH) + KernelPackage/crypto-md5/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-md5/$(ARCH)) +endif + $(eval $(call KernelPackage,crypto-md5)) @@ -727,6 +843,7 @@ ifndef CONFIG_TARGET_x86_64 endef endif +ifndef CONFIG_TARGET_uml define KernelPackage/crypto-misc/x86_64 FILES+= \ $(LINUX_DIR)/arch/x86/crypto/camellia-x86_64.ko \ @@ -746,6 +863,7 @@ define KernelPackage/crypto-misc/x86_64 cast6-avx-x86_64 twofish-x86_64 twofish-x86_64-3way \ twofish-avx-x86_64 blowfish-x86_64 serpent-avx-x86_64 serpent-avx2) endef +endif ifdef KernelPackage/crypto-misc/$(ARCH) KernelPackage/crypto-misc/$(CRYPTO_TARGET)=\ @@ -857,17 +975,71 @@ define KernelPackage/crypto-sha1 DEPENDS:=+kmod-crypto-hash KCONFIG:= \ CONFIG_CRYPTO_SHA1 \ - CONFIG_CRYPTO_SHA1_ARM \ - CONFIG_CRYPTO_SHA1_ARM_NEON \ - CONFIG_CRYPTO_SHA1_ARM64_CE \ - CONFIG_CRYPTO_SHA1_OCTEON \ - CONFIG_CRYPTO_SHA1_PPC_SPE \ - CONFIG_CRYPTO_SHA1_SSSE3 - FILES:=$(LINUX_DIR)/crypto/sha1.ko - AUTOLOAD:=$(call AutoLoad,09,sha1) + CONFIG_CRYPTO_SHA1_ARM@lt6.18 \ + CONFIG_CRYPTO_SHA1_ARM_NEON@lt6.18 \ + CONFIG_CRYPTO_SHA1_ARM64_CE@lt6.18 \ + CONFIG_CRYPTO_SHA1_OCTEON@lt6.18 \ + CONFIG_CRYPTO_SHA1_PPC_SPE@lt6.18 \ + CONFIG_CRYPTO_SHA1_SSSE3@lt6.18 + FILES:=$(LINUX_DIR)/crypto/sha1_generic.ko@lt6.18 \ + $(LINUX_DIR)/crypto/sha1.ko@ge6.18 + AUTOLOAD:=$(call AutoLoad,09,LINUX_6_12:sha1_generic !LINUX_6_12:sha1) $(call AddDepends/crypto) endef +ifeq ($(KERNEL_PATCHVER),6.12) +define KernelPackage/crypto-sha1/arm + FILES+=$(LINUX_DIR)/arch/arm/crypto/sha1-arm.ko + AUTOLOAD+=$(call AutoLoad,09,sha1-arm) +endef + +define KernelPackage/crypto-sha1/arm-neon + $(call KernelPackage/crypto-sha1/arm) + FILES+=$(LINUX_DIR)/arch/arm/crypto/sha1-arm-neon.ko + AUTOLOAD+=$(call AutoLoad,09,sha1-arm-neon) +endef + +define KernelPackage/crypto-sha1/aarch64-ce + FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha1-ce.ko + AUTOLOAD+=$(call AutoLoad,09,sha1-ce) +endef + +KernelPackage/crypto-sha1/imx/cortexa7=$(KernelPackage/crypto-sha1/arm-neon) +KernelPackage/crypto-sha1/imx/cortexa9=$(KernelPackage/crypto-sha1/arm-neon) +KernelPackage/crypto-sha1/ipq40xx=$(KernelPackage/crypto-sha1/arm-neon) +KernelPackage/crypto-sha1/mediatek/filogic=$(KernelPackage/crypto-sha1/aarch64-ce) +KernelPackage/crypto-sha1/mediatek/mt7622=$(KernelPackage/crypto-sha1/aarch64-ce) +KernelPackage/crypto-sha1/mvebu/cortexa9=$(KernelPackage/crypto-sha1/arm-neon) +KernelPackage/crypto-sha1/mvebu/cortexa53=$(KernelPackage/crypto-sha1/aarch64-ce) +KernelPackage/crypto-sha1/mvebu/cortexa72=$(KernelPackage/crypto-sha1/aarch64-ce) +KernelPackage/crypto-sha1/qualcommax=$(KernelPackage/crypto-sha1/aarch64-ce) +KernelPackage/crypto-sha1/rockchip/armv8=$(KernelPackage/crypto-sha1/aarch64-ce) + +define KernelPackage/crypto-sha1/octeon + FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha1.ko + AUTOLOAD+=$(call AutoLoad,09,octeon-sha1) +endef + +KernelPackage/crypto-sha1/tegra=$(KernelPackage/crypto-sha1/arm) + +define KernelPackage/crypto-sha1/mpc85xx + FILES+=$(LINUX_DIR)/arch/powerpc/crypto/sha1-ppc-spe.ko + AUTOLOAD+=$(call AutoLoad,09,sha1-ppc-spe) +endef + +ifndef CONFIG_TARGET_uml +define KernelPackage/crypto-sha1/x86_64 + FILES+=$(LINUX_DIR)/arch/x86/crypto/sha1-ssse3.ko + AUTOLOAD+=$(call AutoLoad,09,sha1-ssse3) +endef +endif + +ifdef KernelPackage/crypto-sha1/$(ARCH) + KernelPackage/crypto-sha1/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-sha1/$(ARCH)) +endif +endif + $(eval $(call KernelPackage,crypto-sha1)) @@ -888,20 +1060,61 @@ define KernelPackage/crypto-sha256 DEPENDS:=+kmod-crypto-hash KCONFIG:= \ CONFIG_CRYPTO_SHA256 \ - CONFIG_CRYPTO_LIB_SHA256_GENERIC=y \ - CRYPTO_CRYPTO_LIB_SHA256_ARCH=y \ - CONFIG_CRYPTO_SHA256_OCTEON \ - CONFIG_CRYPTO_SHA256_PPC_SPE \ - CONFIG_CRYPTO_SHA256_ARM64 \ - CONFIG_CRYPTO_SHA2_ARM64_CE \ - CONFIG_CRYPTO_SHA256_SSSE3 + CONFIG_CRYPTO_SHA256_OCTEON@lt6.18 \ + CONFIG_CRYPTO_SHA256_PPC_SPE@lt6.18 \ + CONFIG_CRYPTO_SHA256_ARM64@lt6.18 \ + CONFIG_CRYPTO_SHA2_ARM64_CE@lt6.18 \ + CONFIG_CRYPTO_SHA256_SSSE3@lt6.18 FILES:= \ - $(LINUX_DIR)/crypto/sha256.ko \ + $(LINUX_DIR)/crypto/sha256_generic.ko@lt6.18 \ + $(LINUX_DIR)/crypto/sha256.ko@ge6.18 \ $(LINUX_DIR)/lib/crypto/libsha256.ko - AUTOLOAD:=$(call AutoLoad,09,sha256_generic) + AUTOLOAD:=$(call AutoLoad,09,LINUX_6_12:sha256_generic !LINUX_6_12:sha256) $(call AddDepends/crypto) endef +ifeq ($(KERNEL_PATCHVER),6.12) +define KernelPackage/crypto-sha256/aarch64 + FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha256-arm64.ko + AUTOLOAD+=$(call AutoLoad,09,sha256-arm64) +endef + +define KernelPackage/crypto-sha256/aarch64-ce + $(call KernelPackage/crypto-sha256/aarch64) + FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha2-ce.ko + AUTOLOAD+=$(call AutoLoad,09,sha2-ce) +endef + +define KernelPackage/crypto-sha256/octeon + FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha256.ko + AUTOLOAD+=$(call AutoLoad,09,octeon-sha256) +endef + +define KernelPackage/crypto-sha256/mpc85xx + FILES+=$(LINUX_DIR)/arch/powerpc/crypto/sha256-ppc-spe.ko + AUTOLOAD+=$(call AutoLoad,09,sha256-ppc-spe) +endef + +ifndef CONFIG_TARGET_uml +define KernelPackage/crypto-sha256/x86_64 + FILES+=$(LINUX_DIR)/arch/x86/crypto/sha256-ssse3.ko + AUTOLOAD+=$(call AutoLoad,09,sha256-ssse3) +endef +endif + +KernelPackage/crypto-sha256/mediatek/filogic=$(KernelPackage/crypto-sha256/aarch64-ce) +KernelPackage/crypto-sha256/mediatek/mt7622=$(KernelPackage/crypto-sha256/aarch64-ce) +KernelPackage/crypto-sha256/mvebu/cortexa53=$(KernelPackage/crypto-sha256/aarch64-ce) +KernelPackage/crypto-sha256/mvebu/cortexa72=$(KernelPackage/crypto-sha256/aarch64-ce) +KernelPackage/crypto-sha256/qualcommax=$(KernelPackage/crypto-sha256/aarch64-ce) +KernelPackage/crypto-sha256/rockchip/armv8=$(KernelPackage/crypto-sha256/aarch64-ce) + +ifdef KernelPackage/crypto-sha256/$(ARCH) + KernelPackage/crypto-sha256/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-sha256/$(ARCH)) +endif +endif + $(eval $(call KernelPackage,crypto-sha256)) @@ -910,17 +1123,53 @@ define KernelPackage/crypto-sha512 DEPENDS:=+kmod-crypto-hash KCONFIG:= \ CONFIG_CRYPTO_SHA512 \ - CONFIG_CRYPTO_SHA512_ARM \ - CONFIG_CRYPTO_SHA512_ARM64 \ - CONFIG_CRYPTO_SHA512_OCTEON \ - CONFIG_CRYPTO_SHA512_SSSE3 - FILES:= \ - $(LINUX_DIR)/crypto/sha512.ko \ - $(LINUX_DIR)/lib/crypto/libsha512.ko - AUTOLOAD:=$(call AutoLoad,09,sha512) + CONFIG_CRYPTO_SHA512_ARM@lt6.18 \ + CONFIG_CRYPTO_SHA512_ARM64@lt6.18 \ + CONFIG_CRYPTO_SHA512_OCTEON@lt6.18 \ + CONFIG_CRYPTO_SHA512_SSSE3@lt6.18 + FILES:=$(LINUX_DIR)/crypto/sha512_generic.ko@lt6.18 \ + $(LINUX_DIR)/crypto/sha512.ko@ge6.18 \ + $(LINUX_DIR)/lib/crypto/libsha512.ko@ge6.18 + AUTOLOAD:=$(call AutoLoad,09,LINUX_6_12:sha512_generic !LINUX_6_12:sha512) $(call AddDepends/crypto) endef +ifeq ($(KERNEL_PATCHVER),6.12) +define KernelPackage/crypto-sha512/arm + FILES+=$(LINUX_DIR)/arch/arm/crypto/sha512-arm.ko + AUTOLOAD+=$(call AutoLoad,09,sha512-arm) +endef + +define KernelPackage/crypto-sha512/aarch64 + FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha512-arm64.ko + AUTOLOAD+=$(call AutoLoad,09,sha512-arm64) +endef + +KernelPackage/crypto-sha512/imx/cortexa7=$(KernelPackage/crypto-sha512/arm) +KernelPackage/crypto-sha512/imx/cortexa9=$(KernelPackage/crypto-sha512/arm) +KernelPackage/crypto-sha512/ipq40xx=$(KernelPackage/crypto-sha512/arm) +KernelPackage/crypto-sha512/mvebu/cortexa9=$(KernelPackage/crypto-sha512/arm) + +define KernelPackage/crypto-sha512/octeon + FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha512.ko + AUTOLOAD+=$(call AutoLoad,09,octeon-sha512) +endef + +KernelPackage/crypto-sha512/tegra=$(KernelPackage/crypto-sha512/arm) + +ifndef CONFIG_TARGET_uml +define KernelPackage/crypto-sha512/x86_64 + FILES+=$(LINUX_DIR)/arch/x86/crypto/sha512-ssse3.ko + AUTOLOAD+=$(call AutoLoad,09,sha512-ssse3) +endef +endif + +ifdef KernelPackage/crypto-sha512/$(ARCH) + KernelPackage/crypto-sha512/$(CRYPTO_TARGET)=\ + $(KernelPackage/crypto-sha512/$(ARCH)) +endif +endif + $(eval $(call KernelPackage,crypto-sha512)) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index acc50f088..7f147ab45 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .10 -LINUX_KERNEL_HASH-6.18.10 = d6d377161741ada2fab28eed69143277634a2aeb5e3883e50c031588ede48ede +LINUX_VERSION-6.18 = .11 +LINUX_KERNEL_HASH-6.18.11 = 38af38924010279322df1d923e10a5a544f74eb2636ca0dd8df5c039f4613af7 From 417209d74b769b72f74a53cd1238288f75e625f3 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 16 Feb 2026 21:29:07 +0800 Subject: [PATCH 357/425] apk: fix patch path Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 7e0b63108..642ce3d6b 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -225,7 +225,7 @@ curl -s $mirror/openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.pa # apk mkdir -p package/system/apk/patches -curl -s $mirror/openwrt/patch/apk/9000-io_url_wget-disbale-hsts.patch > package/system/opkg/patches/9000-io_url_wget-disbale-hsts.patch +curl -s $mirror/openwrt/patch/apk/9000-io_url_wget-disbale-hsts.patch > package/system/apk/patches/9000-io_url_wget-disbale-hsts.patch # opkg mkdir -p package/system/opkg/patches From 38a24f89ffa710e85759d3f0026c7574cda76263 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 17 Feb 2026 19:21:23 +0800 Subject: [PATCH 358/425] linux-6.18: bump to 6.18.12 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 7f147ab45..4dc5e3580 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .11 -LINUX_KERNEL_HASH-6.18.11 = 38af38924010279322df1d923e10a5a544f74eb2636ca0dd8df5c039f4613af7 +LINUX_VERSION-6.18 = .12 +LINUX_KERNEL_HASH-6.18.12 = e003294ad4c2c2ac5bb77fbb8259511134f51d987b3212516832dc4b0c83f1ea From f649dbb928d762df9aaba5d6ab10afd85ecd7ea8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 19 Feb 2026 13:34:50 +0800 Subject: [PATCH 359/425] OpenWrt 25.12.0-rc5 Signed-off-by: sbwml --- ...unconditionally-allow-ct-status-dnat.patch | 31 ------------------- openwrt/scripts/00-prepare_base.sh | 4 +-- tags/v25 | 2 +- 3 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch diff --git a/openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch b/openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch deleted file mode 100644 index e7e484c27..000000000 --- a/openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 38423fae4ba0f116ae7b5853b1c459202fe2c9a4 Mon Sep 17 00:00:00 2001 -From: Stijn Tintel -Date: Tue, 22 Mar 2022 21:20:40 +0200 -Subject: [PATCH] test: unconditionally allow ct status dnat - ---- - root/usr/share/firewall4/templates/ruleset.uc | 4 ---- - 1 file changed, 4 deletions(-) - ---- a/root/usr/share/firewall4/templates/ruleset.uc -+++ b/root/usr/share/firewall4/templates/ruleset.uc -@@ -224,9 +224,7 @@ table inet fw4 { - {% for (let rule in fw4.rules(`input_${zone.name}`)): %} - {%+ include("rule.uc", { fw4, zone, rule }) %} - {% endfor %} --{% if (zone.dflags.dnat): %} - ct status dnat accept comment "!fw4: Accept port redirections" --{% endif %} - {% fw4.includes('chain-append', `input_${zone.name}`) %} - jump {{ zone.input }}_from_{{ zone.name }} - } -@@ -245,9 +243,7 @@ table inet fw4 { - {% for (let rule in fw4.rules(`forward_${zone.name}`)): %} - {%+ include("rule.uc", { fw4, zone, rule }) %} - {% endfor %} --{% if (zone.dflags.dnat): %} - ct status dnat accept comment "!fw4: Accept port forwards" --{% endif %} - {% fw4.includes('chain-append', `forward_${zone.name}`) %} - jump {{ zone.forward }}_to_{{ zone.name }} - {% if (fw4.forward_policy() != "accept" && (zone.log & 1)): %} diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 642ce3d6b..400d0b76a 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -79,7 +79,7 @@ git clone https://$github/sbwml/package_kernel_r8127 package/kernel/r8127 curl -s $mirror/openwrt/patch/target-modify_for_aarch64_x86_64.patch | patch -p1 # libubox -sed -i '/TARGET_CFLAGS/ s/$/ -Os/' package/libs/libubox/Makefile +sed -i '/TARGET_CFLAGS/ s/$/ -O2/' package/libs/libubox/Makefile # DPDK & NUMACTL mkdir -p package/new/{dpdk/patches,numactl} @@ -121,8 +121,6 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then # firewall4 sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/network/config/firewall4/Makefile mkdir -p package/network/config/firewall4/patches - # fix ct status dnat - curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/990-unconditionally-allow-ct-status-dnat.patch > package/network/config/firewall4/patches/990-unconditionally-allow-ct-status-dnat.patch # fullcone curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch # bcm fullcone diff --git a/tags/v25 b/tags/v25 index 6071b26c5..925018892 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.0-rc4 +25.12.0-rc5 From c51b1c928c413e306372e1562ed0b982254171c1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 19 Feb 2026 19:43:16 +0800 Subject: [PATCH 360/425] mt76: update to Git HEAD (2026-01-28) Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 12 +- ...rtimer_setup-in-mt76x02u-beacon-init.patch | 31 ++ .../102-fix-build-with-linux-6.18.patch | 490 ------------------ openwrt/scripts/01-prepare_base-mainline.sh | 2 +- 4 files changed, 41 insertions(+), 494 deletions(-) create mode 100644 openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch delete mode 100644 openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 82be30c47..39057b8c2 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2025-10-20 -PKG_SOURCE_VERSION:=c63db0fcadb88680b35bec202b5142cfd016c10f -PKG_MIRROR_HASH:=38c3c84f5c58b6967283acf524412f6e13628d50add6f09d539f1239fb02b486 +PKG_SOURCE_DATE:=2026-01-28 +PKG_SOURCE_VERSION:=b2fe7f1463526572f01731db8440c10e393fd09f +PKG_MIRROR_HASH:=ea2408d5bfa331598bd0f2fb40516ecbd718d3903a4f43ca0a2d1fc66e8fb6b6 PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 @@ -495,6 +495,12 @@ ifdef CONFIG_PACKAGE_kmod-mt7921e endif ifdef CONFIG_PACKAGE_kmod-mt7996e PKG_MAKE_FLAGS += CONFIG_MT7996E=m + ifdef CONFIG_TARGET_airoha_an7581 + PKG_MAKE_FLAGS += CONFIG_MT76_NPU=y + PKG_MAKE_FLAGS += CONFIG_MT7996_NPU=y + NOSTDINC_FLAGS += -DCONFIG_MT76_NPU + NOSTDINC_FLAGS += -DCONFIG_MT7996_NPU + endif endif ifdef CONFIG_PACKAGE_kmod-mt7925-common PKG_MAKE_FLAGS += CONFIG_MT7925_COMMON=m diff --git a/openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch b/openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch new file mode 100644 index 000000000..91c648778 --- /dev/null +++ b/openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch @@ -0,0 +1,31 @@ +From a95e567eb0e06d460dee234f9c845fbfb215ab11 Mon Sep 17 00:00:00 2001 +From: Mieczyslaw Nalewaj +Date: Thu, 29 Jan 2026 16:36:25 +0100 +Subject: [PATCH] wifi: mt76: use hrtimer_setup() in mt76x02u beacon init + +Replace the two-step hrtimer initialization pattern with a single +consolidated call to hrtimer_setup(). +The legacy approach of calling hrtimer_init() followed by manual +assignment to timer.function is deprecated. The new hrtimer_setup() +helper atomically initializes the timer and assigns the callback +function in one operation, eliminating the race-prone intermediate +state where the timer is initialized but lacks a handler. + +Signed-off-by: Mieczyslaw Nalewaj +--- + mt76x02_usb_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/mt76x02_usb_core.c ++++ b/mt76x02_usb_core.c +@@ -264,8 +264,8 @@ void mt76x02u_init_beacon_config(struct + }; + dev->beacon_ops = &beacon_ops; + +- hrtimer_init(&dev->pre_tbtt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +- dev->pre_tbtt_timer.function = mt76x02u_pre_tbtt_interrupt; ++ hrtimer_setup(&dev->pre_tbtt_timer, mt76x02u_pre_tbtt_interrupt, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); + INIT_WORK(&dev->pre_tbtt_work, mt76x02u_pre_tbtt_work); + + mt76x02_init_beacon_config(dev); diff --git a/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch b/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch deleted file mode 100644 index fda80690b..000000000 --- a/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch +++ /dev/null @@ -1,490 +0,0 @@ ---- a/mac80211.c -+++ b/mac80211.c -@@ -1932,7 +1932,8 @@ void mt76_sw_scan_complete(struct ieee80 - } - EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); - --int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) -+int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, -+ u32 *rx_ant) - { - struct mt76_phy *phy = hw->priv; - struct mt76_dev *dev = phy->dev; ---- a/mt76.h -+++ b/mt76.h -@@ -1577,7 +1577,8 @@ int mt76_get_sar_power(struct mt76_phy * - void mt76_csa_check(struct mt76_dev *dev); - void mt76_csa_finish(struct mt76_dev *dev); - --int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); -+int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, -+ u32 *rx_ant); - int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); - void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id); - int mt76_get_rate(struct mt76_dev *dev, ---- a/mt7603/main.c -+++ b/mt7603/main.c -@@ -216,7 +216,7 @@ static int mt7603_set_sar_specs(struct i - } - - static int --mt7603_config(struct ieee80211_hw *hw, u32 changed) -+mt7603_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - struct mt7603_dev *dev = hw->priv; - int ret = 0; -@@ -657,7 +657,8 @@ mt7603_sta_rate_tbl_update(struct ieee80 - } - - static void --mt7603_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) -+mt7603_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, -+ s16 coverage_class) - { - struct mt7603_dev *dev = hw->priv; - ---- a/mt7615/main.c -+++ b/mt7615/main.c -@@ -97,7 +97,7 @@ static void mt7615_stop(struct ieee80211 - struct mt7615_phy *phy = mt7615_hw_phy(hw); - - cancel_delayed_work_sync(&phy->mt76->mac_work); -- del_timer_sync(&phy->roc_timer); -+ timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - - cancel_delayed_work_sync(&dev->pm.ps_work); -@@ -420,7 +420,7 @@ static int mt7615_set_sar_specs(struct i - return mt76_update_channel(phy->mt76); - } - --static int mt7615_config(struct ieee80211_hw *hw, u32 changed) -+static int mt7615_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - struct mt7615_dev *dev = mt7615_hw_dev(hw); - struct mt7615_phy *phy = mt7615_hw_phy(hw); -@@ -784,7 +784,8 @@ static void mt7615_tx(struct ieee80211_h - mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); - } - --static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) -+static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, -+ u32 val) - { - struct mt7615_dev *dev = mt7615_hw_dev(hw); - struct mt7615_phy *phy = mt7615_hw_phy(hw); -@@ -972,7 +973,8 @@ mt7615_offset_tsf(struct ieee80211_hw *h - } - - static void --mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) -+mt7615_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, -+ s16 coverage_class) - { - struct mt7615_phy *phy = mt7615_hw_phy(hw); - struct mt7615_dev *dev = phy->dev; -@@ -984,7 +986,8 @@ mt7615_set_coverage_class(struct ieee802 - } - - static int --mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) -+mt7615_set_antenna(struct ieee80211_hw *hw, int radio_idx, -+ u32 tx_ant, u32 rx_ant) - { - struct mt7615_dev *dev = mt7615_hw_dev(hw); - struct mt7615_phy *phy = mt7615_hw_phy(hw); -@@ -1043,7 +1046,7 @@ void mt7615_roc_work(struct work_struct - - void mt7615_roc_timer(struct timer_list *timer) - { -- struct mt7615_phy *phy = from_timer(phy, timer, roc_timer); -+ struct mt7615_phy *phy = timer_container_of(phy, timer, roc_timer); - - ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); - } -@@ -1194,7 +1197,7 @@ static int mt7615_cancel_remain_on_chann - if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - return 0; - -- del_timer_sync(&phy->roc_timer); -+ timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - - mt7615_mutex_acquire(phy->dev); ---- a/mt7615/pci_mac.c -+++ b/mt7615/pci_mac.c -@@ -220,12 +220,12 @@ void mt7615_mac_reset_work(struct work_s - set_bit(MT76_MCU_RESET, &dev->mphy.state); - wake_up(&dev->mt76.mcu.wait); - cancel_delayed_work_sync(&dev->mphy.mac_work); -- del_timer_sync(&dev->phy.roc_timer); -+ timer_delete_sync(&dev->phy.roc_timer); - cancel_work_sync(&dev->phy.roc_work); - if (phy2) { - set_bit(MT76_RESET, &phy2->mt76->state); - cancel_delayed_work_sync(&phy2->mt76->mac_work); -- del_timer_sync(&phy2->roc_timer); -+ timer_delete_sync(&phy2->roc_timer); - cancel_work_sync(&phy2->roc_work); - } - ---- a/mt7615/usb.c -+++ b/mt7615/usb.c -@@ -85,7 +85,7 @@ static void mt7663u_stop(struct ieee8021 - struct mt7615_dev *dev = hw->priv; - - clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); -- del_timer_sync(&phy->roc_timer); -+ timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - cancel_delayed_work_sync(&phy->scan_work); - cancel_delayed_work_sync(&phy->mt76->mac_work); ---- a/mt76x0/main.c -+++ b/mt76x0/main.c -@@ -57,7 +57,7 @@ out: - } - EXPORT_SYMBOL_GPL(mt76x0_set_sar_specs); - --int mt76x0_config(struct ieee80211_hw *hw, u32 changed) -+int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - struct mt76x02_dev *dev = hw->priv; - ---- a/mt76x0/mt76x0.h -+++ b/mt76x0/mt76x0.h -@@ -48,7 +48,7 @@ void mt76x0_chip_onoff(struct mt76x02_de - - void mt76x0_mac_stop(struct mt76x02_dev *dev); - --int mt76x0_config(struct ieee80211_hw *hw, u32 changed); -+int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed); - int mt76x0_set_channel(struct mt76_phy *mphy); - int mt76x0_set_sar_specs(struct ieee80211_hw *hw, - const struct cfg80211_sar_specs *sar); ---- a/mt76x02.h -+++ b/mt76x02.h -@@ -183,8 +183,8 @@ void mt76x02_wdt_work(struct work_struct - void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); - void mt76x02_set_tx_ackto(struct mt76x02_dev *dev); - void mt76x02_set_coverage_class(struct ieee80211_hw *hw, -- s16 coverage_class); --int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val); -+ int radio_idx, s16 coverage_class); -+int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val); - void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); - bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update); - void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, ---- a/mt76x02_usb_core.c -+++ b/mt76x02_usb_core.c -@@ -264,8 +264,7 @@ void mt76x02u_init_beacon_config(struct - }; - dev->beacon_ops = &beacon_ops; - -- hrtimer_init(&dev->pre_tbtt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -- dev->pre_tbtt_timer.function = mt76x02u_pre_tbtt_interrupt; -+ hrtimer_setup(&dev->pre_tbtt_timer, mt76x02u_pre_tbtt_interrupt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - INIT_WORK(&dev->pre_tbtt_work, mt76x02u_pre_tbtt_work); - - mt76x02_init_beacon_config(dev); ---- a/mt76x02_util.c -+++ b/mt76x02_util.c -@@ -548,7 +548,7 @@ void mt76x02_set_tx_ackto(struct mt76x02 - EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto); - - void mt76x02_set_coverage_class(struct ieee80211_hw *hw, -- s16 coverage_class) -+ int radio_idx, s16 coverage_class) - { - struct mt76x02_dev *dev = hw->priv; - -@@ -559,7 +559,7 @@ void mt76x02_set_coverage_class(struct i - } - EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class); - --int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) -+int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val) - { - struct mt76x02_dev *dev = hw->priv; - ---- a/mt76x2/pci_main.c -+++ b/mt76x2/pci_main.c -@@ -54,7 +54,7 @@ int mt76x2e_set_channel(struct mt76_phy - } - - static int --mt76x2_config(struct ieee80211_hw *hw, u32 changed) -+mt76x2_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - struct mt76x02_dev *dev = hw->priv; - -@@ -99,8 +99,8 @@ mt76x2_flush(struct ieee80211_hw *hw, st - { - } - --static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, -- u32 rx_ant) -+static int mt76x2_set_antenna(struct ieee80211_hw *hw, int radio_idx, -+ u32 tx_ant, u32 rx_ant) - { - struct mt76x02_dev *dev = hw->priv; - ---- a/mt76x2/usb_main.c -+++ b/mt76x2/usb_main.c -@@ -50,7 +50,7 @@ int mt76x2u_set_channel(struct mt76_phy - } - - static int --mt76x2u_config(struct ieee80211_hw *hw, u32 changed) -+mt76x2u_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - struct mt76x02_dev *dev = hw->priv; - int err = 0; ---- a/mt7915/main.c -+++ b/mt7915/main.c -@@ -449,7 +449,8 @@ out: - return err; - } - --static int mt7915_config(struct ieee80211_hw *hw, u32 changed) -+static int mt7915_config(struct ieee80211_hw *hw, int radio_idx, -+ u32 changed) - { - struct mt7915_dev *dev = mt7915_hw_dev(hw); - struct mt7915_phy *phy = mt7915_hw_phy(hw); -@@ -913,7 +914,8 @@ static void mt7915_tx(struct ieee80211_h - mt76_tx(mphy, control->sta, wcid, skb); - } - --static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) -+static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, -+ u32 val) - { - struct mt7915_dev *dev = mt7915_hw_dev(hw); - struct mt7915_phy *phy = mt7915_hw_phy(hw); -@@ -1109,7 +1111,8 @@ mt7915_offset_tsf(struct ieee80211_hw *h - } - - static void --mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) -+mt7915_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, -+ s16 coverage_class) - { - struct mt7915_phy *phy = mt7915_hw_phy(hw); - struct mt7915_dev *dev = phy->dev; -@@ -1121,7 +1124,7 @@ mt7915_set_coverage_class(struct ieee802 - } - - static int --mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) -+mt7915_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_ant) - { - struct mt7915_dev *dev = mt7915_hw_dev(hw); - struct mt7915_phy *phy = mt7915_hw_phy(hw); -@@ -1699,7 +1702,7 @@ mt7915_twt_teardown_request(struct ieee8 - } - - static int --mt7915_set_frag_threshold(struct ieee80211_hw *hw, u32 val) -+mt7915_set_frag_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val) - { - return 0; - } ---- a/mt7921/main.c -+++ b/mt7921/main.c -@@ -371,7 +371,7 @@ void mt7921_roc_abort_sync(struct mt792x - { - struct mt792x_phy *phy = &dev->phy; - -- del_timer_sync(&phy->roc_timer); -+ timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - ieee80211_iterate_interfaces(mt76_hw(dev), -@@ -402,7 +402,7 @@ static int mt7921_abort_roc(struct mt792 - { - int err = 0; - -- del_timer_sync(&phy->roc_timer); -+ timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - - mt792x_mutex_acquire(phy->dev); -@@ -626,7 +626,7 @@ void mt7921_set_runtime_pm(struct mt792x - mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); - } - --static int mt7921_config(struct ieee80211_hw *hw, u32 changed) -+static int mt7921_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt792x_phy *phy = mt792x_hw_phy(hw); -@@ -915,7 +915,8 @@ void mt7921_mac_sta_remove(struct mt76_d - } - EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove); - --static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, u32 val) -+static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, -+ u32 val) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - -@@ -1096,7 +1097,8 @@ mt7921_stop_sched_scan(struct ieee80211_ - } - - static int --mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) -+mt7921_set_antenna(struct ieee80211_hw *hw, int radio_idx, -+ u32 tx_ant, u32 rx_ant) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt792x_phy *phy = mt792x_hw_phy(hw); -@@ -1492,7 +1494,7 @@ static void mt7921_abort_channel_switch( - { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - -- del_timer_sync(&mvif->csa_timer); -+ timer_delete_sync(&mvif->csa_timer); - cancel_work_sync(&mvif->csa_work); - } - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -449,7 +449,7 @@ void mt7925_roc_abort_sync(struct mt792x - { - struct mt792x_phy *phy = &dev->phy; - -- del_timer_sync(&phy->roc_timer); -+ timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - ieee80211_iterate_interfaces(mt76_hw(dev), -@@ -481,7 +481,7 @@ static int mt7925_abort_roc(struct mt792 - { - int err = 0; - -- del_timer_sync(&phy->roc_timer); -+ timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - - mt792x_mutex_acquire(phy->dev); -@@ -750,7 +750,7 @@ void mt7925_set_runtime_pm(struct mt792x - mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); - } - --static int mt7925_config(struct ieee80211_hw *hw, u32 changed) -+static int mt7925_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - int ret = 0; -@@ -1211,7 +1211,8 @@ void mt7925_mac_sta_remove(struct mt76_d - } - EXPORT_SYMBOL_GPL(mt7925_mac_sta_remove); - --static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, u32 val) -+static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, -+ u32 val) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - -@@ -1453,7 +1454,8 @@ mt7925_stop_sched_scan(struct ieee80211_ - } - - static int --mt7925_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) -+mt7925_set_antenna(struct ieee80211_hw *hw, int radio_idx, -+ u32 tx_ant, u32 rx_ant) - { - struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt792x_phy *phy = mt792x_hw_phy(hw); ---- a/mt792x.h -+++ b/mt792x.h -@@ -411,7 +411,8 @@ void mt792x_sta_statistics(struct ieee80 - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct station_info *sinfo); --void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class); -+void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, -+ s16 coverage_class); - void mt792x_dma_cleanup(struct mt792x_dev *dev); - int mt792x_dma_enable(struct mt792x_dev *dev); - int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force); ---- a/mt792x_core.c -+++ b/mt792x_core.c -@@ -305,7 +305,7 @@ EXPORT_SYMBOL_GPL(mt792x_tx_worker); - - void mt792x_roc_timer(struct timer_list *timer) - { -- struct mt792x_phy *phy = from_timer(phy, timer, roc_timer); -+ struct mt792x_phy *phy = timer_container_of(phy, timer, roc_timer); - - ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); - } -@@ -313,7 +313,7 @@ EXPORT_SYMBOL_GPL(mt792x_roc_timer); - - void mt792x_csa_timer(struct timer_list *timer) - { -- struct mt792x_vif *mvif = from_timer(mvif, timer, csa_timer); -+ struct mt792x_vif *mvif = timer_container_of(mvif, timer, csa_timer); - - ieee80211_queue_work(mvif->phy->mt76->hw, &mvif->csa_work); - } -@@ -362,7 +362,7 @@ void mt792x_unassign_vif_chanctx(struct - mutex_unlock(&dev->mt76.mutex); - - if (vif->bss_conf.csa_active) { -- del_timer_sync(&mvif->csa_timer); -+ timer_delete_sync(&mvif->csa_timer); - cancel_work_sync(&mvif->csa_work); - } - } -@@ -601,7 +601,8 @@ void mt792x_sta_statistics(struct ieee80 - } - EXPORT_SYMBOL_GPL(mt792x_sta_statistics); - --void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) -+void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, -+ s16 coverage_class) - { - struct mt792x_phy *phy = mt792x_hw_phy(hw); - struct mt792x_dev *dev = phy->dev; ---- a/mt7996/main.c -+++ b/mt7996/main.c -@@ -655,7 +655,7 @@ static int mt7996_set_key(struct ieee802 - return err; - } - --static int mt7996_config(struct ieee80211_hw *hw, u32 changed) -+static int mt7996_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) - { - return 0; - } -@@ -1371,7 +1371,8 @@ unlock: - rcu_read_unlock(); - } - --static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) -+static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, -+ u32 val) - { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - int i, ret = 0; -@@ -1591,7 +1592,8 @@ unlock: - } - - static void --mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) -+mt7996_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, -+ s16 coverage_class) - { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy; -@@ -1605,7 +1607,8 @@ mt7996_set_coverage_class(struct ieee802 - } - - static int --mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) -+mt7996_set_antenna(struct ieee80211_hw *hw, int radio_idx, -+ u32 tx_ant, u32 rx_ant) - { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - int i; diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 21b89d8a0..0b7f9d60c 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -156,8 +156,8 @@ git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile +curl -s $mirror/openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch > package/kernel/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch -curl -s $mirror/openwrt/patch/mt76/patches/102-fix-build-with-linux-6.18.patch > package/kernel/mt76/patches/102-fix-build-with-linux-6.18.patch # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch From 4569f7d9fef8a84f746a5767a43a04f6500f11b8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 20 Feb 2026 08:34:39 +0800 Subject: [PATCH 361/425] linux-6.18: bump to 6.18.13 & fix irqbalance build Signed-off-by: sbwml --- .../900-meson-add-numa-option.patch | 38 ------------------- openwrt/scripts/05-fix-source.sh | 6 +-- tags/kernel-6.18 | 4 +- 3 files changed, 3 insertions(+), 45 deletions(-) delete mode 100644 openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch diff --git a/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch b/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch deleted file mode 100644 index 5f88f5542..000000000 --- a/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch +++ /dev/null @@ -1,38 +0,0 @@ ---- a/meson.build -+++ b/meson.build -@@ -9,12 +9,13 @@ glib_dep = dependency('glib-2.0', static - m_dep = cc.find_library('m', required: false) - capng_dep = dependency('libcap-ng', required: get_option('capng')) - ncurses_dep = dependency('curses', required: get_option('ui')) -+numa_dep = cc.find_library('numa', required: get_option('numa')) - systemd_dep = dependency('libsystemd', required: get_option('systemd')) - - cdata = configuration_data() - cdata.set('HAVE_GETOPT_LONG', cc.has_function('getopt_long')) - cdata.set('HAVE_IRQBALANCEUI', ncurses_dep.found()) --cdata.set('HAVE_NUMA_H', cc.has_header('numa.h')) -+cdata.set('HAVE_NUMA_H', cc.has_header('numa.h') and numa_dep.found()) - cdata.set('HAVE_LIBCAP_NG', capng_dep.found()) - cdata.set('HAVE_LIBSYSTEMD', systemd_dep.found()) - cdata.set_quoted('VERSION', meson.project_version()) -@@ -38,6 +39,6 @@ executable('irqbalance', - 'numa.c', - 'placement.c', - 'procinterrupts.c', -- dependencies: [ glib_dep, m_dep, capng_dep, ncurses_dep, systemd_dep ], -+ dependencies: [ glib_dep, m_dep, capng_dep, ncurses_dep, numa_dep, systemd_dep ], - install : true - ) ---- a/meson_options.txt -+++ b/meson_options.txt -@@ -2,6 +2,10 @@ option('capng', type : 'feature', - description : 'Build with libcap-ng support', - ) - -+option('numa', type : 'feature', value: 'disabled', -+ description : 'Build with numa support', -+) -+ - option('systemd', type : 'feature', - description : 'Build with systemd support', - ) diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index f760fc42e..d49f32b77 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -18,11 +18,7 @@ if [ "$ENABLE_MOLD" = "y" ]; then fi # irqbalance -if [ "$version" = "rc2" ]; then - curl -s $mirror/openwrt/patch/packages-patches/irqbalance/900-meson-add-numa-option.patch > feeds/packages/utils/irqbalance/patches/900-meson-add-numa-option.patch -else - curl -s $mirror/openwrt/patch/packages-patches/irqbalance/901-meson-disable-numa-option-by-default.patch > feeds/packages/utils/irqbalance/patches/901-meson-disable-numa-option-by-default.patch -fi +curl -s $mirror/openwrt/patch/packages-patches/irqbalance/901-meson-disable-numa-option-by-default.patch > feeds/packages/utils/irqbalance/patches/901-meson-disable-numa-option-by-default.patch # libsodium - fix build with lto (GNU BUG - 89147) sed -i "/CONFIGURE_ARGS/i\TARGET_CFLAGS += -ffat-lto-objects\n" feeds/packages/libs/libsodium/Makefile diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 4dc5e3580..d39dc2280 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .12 -LINUX_KERNEL_HASH-6.18.12 = e003294ad4c2c2ac5bb77fbb8259511134f51d987b3212516832dc4b0c83f1ea +LINUX_VERSION-6.18 = .13 +LINUX_KERNEL_HASH-6.18.13 = ed2c3c55fd38e6836c094fce356f2567f9516130b73354a29857960368c5687f From 95591f80c43e89c5ece6a8ab17aceff7dff4ed42 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 21 Feb 2026 08:41:55 +0800 Subject: [PATCH 362/425] add luci-lib-docker package (docker api - lua) Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 400d0b76a..1358d8331 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -185,6 +185,7 @@ git clone https://$github/sbwml/feeds_packages_net_curl feeds/packages/net/curl # Docker rm -rf feeds/luci/applications/luci-app-dockerman git clone https://$github/sbwml/luci-app-dockerman feeds/luci/applications/luci-app-dockerman +git clone https://$github/sbwml/luci-lib-docker package/new/luci-lib-docker rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} git clone https://$github/sbwml/packages_utils_docker feeds/packages/utils/docker git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd From 6340133d9737ddf64251ec57bc2b513f29079016 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 22 Feb 2026 12:06:08 +0800 Subject: [PATCH 363/425] luci-app-dockerman: update to JS version Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 1358d8331..213b3a949 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -184,8 +184,7 @@ git clone https://$github/sbwml/feeds_packages_net_curl feeds/packages/net/curl # Docker rm -rf feeds/luci/applications/luci-app-dockerman -git clone https://$github/sbwml/luci-app-dockerman feeds/luci/applications/luci-app-dockerman -git clone https://$github/sbwml/luci-lib-docker package/new/luci-lib-docker +git clone https://$github/sbwml/luci-app-dockerman -b openwrt-25.12 feeds/luci/applications/luci-app-dockerman rm -rf feeds/packages/utils/{docker,dockerd,containerd,runc} git clone https://$github/sbwml/packages_utils_docker feeds/packages/utils/docker git clone https://$github/sbwml/packages_utils_dockerd feeds/packages/utils/dockerd From ac3bff7092c4aaf75aaecd346c8af16fd405203a Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 27 Feb 2026 20:21:48 +0800 Subject: [PATCH 364/425] linux-6.18: bump to 6.18.14 Signed-off-by: sbwml --- ...snapshot-packets-in-flight-at-transmi.patch | 4 ++-- ...count-packets-lost-over-TCP-rate-samp.patch | 2 +- ...export-FLAG_ECE-in-rate_sample.is_ece.patch | 2 +- ...introduce-ca_ops-skb_marked_lost-CC-m.patch | 2 +- ...adjust-skb-tx.in_flight-upon-split-in.patch | 2 +- ...-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 18 +++++++++--------- ...ralize-TSO-sizing-in-TCP-CC-module-AP.patch | 2 +- ...t_ack_mode-1-skip-rwin-check-in-tcp_f.patch | 4 ++-- ...introduce-is_acking_tlp_retrans_seq-i.patch | 2 +- ...er-route-feature-RTAX_FEATURE_ECN_LOW.patch | 6 +++--- ...update-TCP-bbr-congestion-control-mod.patch | 2 +- ..._OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 2 +- ...2-scheduler-add-entropy-sampling-hook.patch | 2 +- ...h-linux-kernel-to-support-shortcut-fe.patch | 10 +++++----- ...983-add-bcm-fullcone-nft_masq-support.patch | 2 +- .../patch/openwrt-6.x/modules/netdevices.mk | 5 ++++- tags/kernel-6.18 | 4 ++-- tags/kernel-tag.sh | 2 +- 18 files changed, 38 insertions(+), 35 deletions(-) diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index 6bdb31735..70be17ed8 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -38,7 +38,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1217,6 +1221,7 @@ struct rate_sample { +@@ -1225,6 +1229,7 @@ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ @@ -46,7 +46,7 @@ Signed-off-by: Alexandre Frade s32 delivered; /* number of packets delivered over interval */ s32 delivered_ce; /* number of packets delivered w/ CE marks*/ long interval_us; /* time for tp->delivered to incr "delivered" */ -@@ -1339,6 +1344,7 @@ static inline void tcp_ca_event(struct s +@@ -1368,6 +1373,7 @@ static inline void tcp_ca_event(struct s void tcp_set_ca_state(struct sock *sk, const u8 ca_state); /* From tcp_rate.c */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch index ff11135ed..4e7898bec 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1219,11 +1220,13 @@ struct ack_sample { +@@ -1227,11 +1228,13 @@ struct ack_sample { */ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index 77b5ed7a5..64bed7e5b 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -18,7 +18,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1238,6 +1238,7 @@ struct rate_sample { +@@ -1246,6 +1246,7 @@ struct rate_sample { bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ bool is_ack_delayed; /* is this (likely) a delayed ACK? */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index 59d457bcb..a34b6e5d7 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -30,7 +30,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1265,6 +1265,9 @@ struct tcp_congestion_ops { +@@ -1273,6 +1273,9 @@ struct tcp_congestion_ops { /* override sysctl_tcp_min_tso_segs */ u32 (*min_tso_segs)(struct sock *sk); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch index 803d24214..f6b6059df 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1364,6 +1364,21 @@ static inline bool tcp_skb_sent_after(u6 +@@ -1393,6 +1393,21 @@ static inline bool tcp_skb_sent_after(u6 return t1 > t2 || (t1 == t2 && after(seq1, seq2)); } diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch index 9d4f39bd6..29748a6d6 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch @@ -23,20 +23,20 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1200,7 +1200,11 @@ enum tcp_ca_ack_event_flags { - #define TCP_CONG_NON_RESTRICTED BIT(0) - /* Requires ECN/ECT set on all packets */ - #define TCP_CONG_NEEDS_ECN BIT(1) --#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN) +@@ -1206,9 +1206,11 @@ enum tcp_ca_ack_event_flags { + #define TCP_CONG_ECT_1_NEGOTIATION BIT(3) + /* Cannot fallback to RFC3168 during AccECN negotiation */ + #define TCP_CONG_NO_FALLBACK_RFC3168 BIT(4) +/* Wants notification of CE events (CA_EVENT_ECN_IS_CE, CA_EVENT_ECN_NO_CE). */ +#define TCP_CONG_WANTS_CE_EVENTS BIT(2) -+#define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | \ -+ TCP_CONG_NEEDS_ECN | \ -+ TCP_CONG_WANTS_CE_EVENTS) + #define TCP_CONG_MASK (TCP_CONG_NON_RESTRICTED | TCP_CONG_NEEDS_ECN | \ + TCP_CONG_NEEDS_ACCECN | TCP_CONG_ECT_1_NEGOTIATION | \ +- TCP_CONG_NO_FALLBACK_RFC3168) ++ TCP_CONG_NO_FALLBACK_RFC3168 | TCP_CONG_WANTS_CE_EVENTS) union tcp_cc_info; -@@ -1332,6 +1336,14 @@ static inline char *tcp_ca_get_name_by_k +@@ -1340,6 +1342,14 @@ static inline char *tcp_ca_get_name_by_k } #endif diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch index 213c32aad..7ed2df88b 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1266,8 +1266,8 @@ struct tcp_congestion_ops { +@@ -1272,8 +1272,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 995d27ef4..990a657e8 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade /* RX read-mostly hotpath cache lines */ --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -3469,6 +3469,7 @@ int tcp_disconnect(struct sock *sk, int +@@ -3470,6 +3470,7 @@ int tcp_disconnect(struct sock *sk, int tp->rx_opt.dsack = 0; tp->rx_opt.num_sacks = 0; tp->rcv_ooopack = 0; @@ -43,7 +43,7 @@ Signed-off-by: Alexandre Frade /* Clean up fastopen related fields */ --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c -@@ -237,6 +237,7 @@ void tcp_init_congestion_control(struct +@@ -238,6 +238,7 @@ void tcp_init_congestion_control(struct struct inet_connection_sock *icsk = inet_csk(sk); tcp_sk(sk)->prior_ssthresh = 0; diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index 1c20db9a5..0cc31447e 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -21,7 +21,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1242,6 +1242,7 @@ struct rate_sample { +@@ -1248,6 +1248,7 @@ struct rate_sample { u32 last_end_seq; /* end_seq of most recently ACKed packet */ bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch index 48a2fd7ac..81a3b27d4 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch @@ -77,7 +77,7 @@ Signed-off-by: Alexandre Frade __u8 proto; --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c -@@ -500,6 +500,8 @@ void tcp_ca_openreq_child(struct sock *s +@@ -501,6 +501,8 @@ void tcp_ca_openreq_child(struct sock *s u32 ca_key = dst_metric(dst, RTAX_CC_ALGO); bool ca_got_dst = false; @@ -88,7 +88,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp_ecn.h +++ b/include/net/tcp_ecn.h -@@ -583,10 +583,9 @@ static inline void tcp_ecn_send_syn(stru +@@ -613,10 +613,9 @@ static inline void tcp_ecn_send_syn(stru use_ecn = tcp_ecn == TCP_ECN_IN_ECN_OUT_ECN || tcp_ecn == TCP_ECN_IN_ACCECN_OUT_ECN || tcp_ca_needs_ecn(sk) || bpf_needs_ecn || use_accecn; @@ -100,7 +100,7 @@ Signed-off-by: Alexandre Frade if (dst && dst_feature(dst, RTAX_FEATURE_ECN)) use_ecn = true; } -@@ -604,6 +603,9 @@ static inline void tcp_ecn_send_syn(stru +@@ -634,6 +633,9 @@ static inline void tcp_ecn_send_syn(stru tp->syn_ect_snt = inet_sk(sk)->tos & INET_ECN_MASK; } else { tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch index b978b0c99..5d20ed5b2 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -153,7 +153,7 @@ Signed-off-by: Alexandre Frade #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -2588,7 +2588,7 @@ struct tcp_plb_state { +@@ -2615,7 +2615,7 @@ struct tcp_plb_state { u8 consec_cong_rounds:5, /* consecutive congested rounds */ unused:3; u32 pause_until; /* jiffies32 when PLB can resume rerouting */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch index bc4f45753..f59dd8091 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade * Sender's congestion state indicating normal or abnormal situations --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -4227,6 +4227,8 @@ void tcp_get_info(struct sock *sk, struc +@@ -4228,6 +4228,8 @@ void tcp_get_info(struct sock *sk, struc info->tcpi_options |= TCPI_OPT_ECN; if (tp->ecn_flags & TCP_ECN_SEEN) info->tcpi_options |= TCPI_OPT_ECN_SEEN; diff --git a/openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch index 26d88df94..b7f20562f 100644 --- a/openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch +++ b/openwrt/patch/kernel-6.18/lrng/011-LRNG-0012-scheduler-add-entropy-sampling-hook.patch @@ -24,7 +24,7 @@ Signed-off-by: Stephan Mueller #include #include #include -@@ -3641,6 +3642,8 @@ ttwu_stat(struct task_struct *p, int cpu +@@ -3646,6 +3647,8 @@ ttwu_stat(struct task_struct *p, int cpu { struct rq *rq; diff --git a/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 96fd6569b..8bc7cac0f 100644 --- a/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -52,7 +52,7 @@ Signed-off-by: Xiaoping Fan const struct nf_ct_event_notifier *nb); --- a/net/Kconfig +++ b/net/Kconfig -@@ -526,6 +526,9 @@ config FAILOVER +@@ -529,6 +529,9 @@ config FAILOVER migration of VMs with direct attached VFs by failing over to the paravirtual datapath when the VF is unplugged. @@ -93,7 +93,7 @@ Signed-off-by: Xiaoping Fan struct net_bridge_port *p; --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -3837,8 +3837,17 @@ static int xmit_one(struct sk_buff *skb, +@@ -3850,8 +3850,17 @@ static int xmit_one(struct sk_buff *skb, unsigned int len; int rc; @@ -111,7 +111,7 @@ Signed-off-by: Xiaoping Fan #ifdef CONFIG_ETHERNET_PACKET_MANGLE if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) -@@ -5814,6 +5823,11 @@ void netdev_rx_handler_unregister(struct +@@ -5827,6 +5836,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5863,6 +5877,10 @@ static int __netif_receive_skb_core(stru +@@ -5876,6 +5890,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5907,6 +5925,16 @@ another_round: +@@ -5920,6 +5938,16 @@ another_round: goto out; } diff --git a/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch index 5182d3a6f..e9b3418e7 100644 --- a/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -30,7 +30,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -11628,6 +11628,24 @@ static int nft_validate_register_load(en +@@ -11716,6 +11716,24 @@ static int nft_validate_register_load(en return 0; } diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index b104b657d..18052cbd7 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -155,8 +155,11 @@ define KernelPackage/libphy SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=PHY library KCONFIG:=CONFIG_PHYLIB \ + CONFIG_MDIO_BUS \ CONFIG_PHYLIB_LEDS=y - FILES:=$(LINUX_DIR)/drivers/net/phy/libphy.ko + FILES:= \ + $(LINUX_DIR)/drivers/net/phy/libphy.ko \ + $(LINUX_DIR)/drivers/net/phy/mdio-bus.ko AUTOLOAD:=$(call AutoLoad,15,libphy,1) endef diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index d39dc2280..2d909eb44 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .13 -LINUX_KERNEL_HASH-6.18.13 = ed2c3c55fd38e6836c094fce356f2567f9516130b73354a29857960368c5687f +LINUX_VERSION-6.18 = .14 +LINUX_KERNEL_HASH-6.18.14 = 8d1934a72a185f1be6b56e3ad8ea31fd9a381ffec0346c69f06c90d776da7cb8 diff --git a/tags/kernel-tag.sh b/tags/kernel-tag.sh index 58d80547a..e508e360c 100755 --- a/tags/kernel-tag.sh +++ b/tags/kernel-tag.sh @@ -6,7 +6,7 @@ ROOT="./" # 获取所有 stable 版本中最新的 6.18.x KERNEL_VERSION=$(curl -s https://www.kernel.org/releases.json \ - | jq -r '.releases[] | select(.moniker=="stable") | .version' \ + | jq -r '.releases[] | select(.moniker=="longterm") | .version' \ | grep '^6\.18\.' \ | sort -V \ | tail -n1) From 050595a50e628f8d9b88517425325a4e7455d96e Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 27 Feb 2026 20:22:37 +0800 Subject: [PATCH 365/425] config: clean up Signed-off-by: sbwml --- openwrt/25-config-common | 1 - openwrt/25-config-minimal-common | 1 - 2 files changed, 2 deletions(-) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index da9b7b933..1d0cd4413 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -207,7 +207,6 @@ CONFIG_PACKAGE_kmod-usb2-pci=y CONFIG_PACKAGE_kmod-usb2=y CONFIG_PACKAGE_kmod-usb3=y CONFIG_PACKAGE_kmod-veth=y -CONFIG_PACKAGE_kmod-xdp-sockets-diag=y ### Kernel Modules - out-of-tree driver CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y diff --git a/openwrt/25-config-minimal-common b/openwrt/25-config-minimal-common index 4f9215f2b..cf7b5b741 100644 --- a/openwrt/25-config-minimal-common +++ b/openwrt/25-config-minimal-common @@ -130,7 +130,6 @@ CONFIG_PACKAGE_kmod-usb2-pci=y CONFIG_PACKAGE_kmod-usb2=y CONFIG_PACKAGE_kmod-usb3=y CONFIG_PACKAGE_kmod-veth=y -CONFIG_PACKAGE_kmod-xdp-sockets-diag=y ### Kernel Modules - out-of-tree driver CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y From 389717285199f59dd387fd0d016ad5674f47d49d Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 27 Feb 2026 20:23:01 +0800 Subject: [PATCH 366/425] config: nanopi-r76s: use the high-performance sdio wifi driver Signed-off-by: sbwml --- openwrt/25-config-musl-r76s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/25-config-musl-r76s b/openwrt/25-config-musl-r76s index 4f8cfbb66..c66b921c2 100644 --- a/openwrt/25-config-musl-r76s +++ b/openwrt/25-config-musl-r76s @@ -25,7 +25,7 @@ CONFIG_COREMARK_NUMBER_OF_THREADS=8 ### SDIO Wireless / Bluetooth CONFIG_PACKAGE_kmod-bluetooth=y -CONFIG_PACKAGE_kmod-rtw88-8822cs=y +CONFIG_PACKAGE_kmod-rtl8822cs=y CONFIG_PACKAGE_rtl8822cs-firmware=y ### HDMI From 53c5f61502a44494812b53a7d6608e4018ac0fb9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 27 Feb 2026 20:24:21 +0800 Subject: [PATCH 367/425] build: enable lto jobserver Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 213b3a949..e46d9ce36 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -10,6 +10,9 @@ else git clone https://$github/sbwml/arm-trusted-firmware-rockchip package/boot/arm-trusted-firmware-rockchip fi +# lto jobserver +sed -i 's/-flto=auto/-flto=jobserver/g' include/package.mk + # patch source curl -s $mirror/openwrt/patch/generic-25.12/0001-tools-add-upx-tools.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-25.12/0002-rootfs-add-upx-compression-support.patch | patch -p1 From f8c4bfd4a7d4af37ed7d5d2e6c5cf82423036b2a Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 27 Feb 2026 20:28:20 +0800 Subject: [PATCH 368/425] script: add rtl8852au driver (oot) Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 5 ++++- openwrt/scripts/01-prepare_base-mainline.sh | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index e46d9ce36..bdd73a5c9 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -69,7 +69,7 @@ sed -i '/luci-app-attendedsysupgrade/d' \ feeds/luci/collections/luci-ssl/Makefile \ feeds/luci/collections/luci/Makefile -# Realtek driver - R8168 & R8125 & R8126 & R8152 & R8101 & r8127 +# Realtek Ethernet driver - R8168 & R8125 & R8126 & R8152 & R8101 & r8127 rm -rf package/kernel/{r8168,r8101,r8125,r8126,r8127} git clone https://$github/sbwml/package_kernel_r8168 package/kernel/r8168 git clone https://$github/sbwml/package_kernel_r8152 package/kernel/r8152 @@ -77,6 +77,9 @@ git clone https://$github/sbwml/package_kernel_r8101 package/kernel/r8101 git clone https://$github/sbwml/package_kernel_r8125 package/kernel/r8125 git clone https://$github/sbwml/package_kernel_r8126 package/kernel/r8126 git clone https://$github/sbwml/package_kernel_r8127 package/kernel/r8127 +# Realtek Wireless driver - RTL8822CS & RTL8852AU +git clone https://$github/sbwml/package_kernel_rtl8822cs package/kernel/rtl8822cs +git clone https://$github/sbwml/package_kernel_rtl8852au package/kernel/rtl8852au # GCC Optimization level -O3 curl -s $mirror/openwrt/patch/target-modify_for_aarch64_x86_64.patch | patch -p1 diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 0b7f9d60c..f42f9dc60 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -183,9 +183,6 @@ curl -s $mirror/openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeo curl -s $mirror/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch > target/linux/generic/hack-6.18/952-net-conntrack-events-support-multiple-registrant.patch curl -s $mirror/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch > target/linux/generic/hack-6.18/953-net-patch-linux-kernel-to-support-shortcut-fe.patch -# rtl8822cs -git clone https://$github/sbwml/package_kernel_rtl8822cs package/kernel/rtl8822cs - # RTC if [ "$platform" = "rk3399" ] || [ "$platform" = "rk3568" ] || [ "$platform" = "rk3576" ]; then curl -s $mirror/openwrt/patch/rtc/sysfixtime > package/base-files/files/etc/init.d/sysfixtime From 3117f075e201be2c48285d35489b41e9ad66e064 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 27 Feb 2026 21:57:59 +0800 Subject: [PATCH 369/425] mt76: mt7925: import stability fixes from zbowling/linux-wifi Signed-off-by: sbwml --- ...-fix-NULL-pointer-dereference-in-vif.patch | 76 ++++++ ...-fix-missing-mutex-protection-in-res.patch | 57 ++++ ...-fix-missing-mutex-protection-in-run.patch | 71 +++++ ...-add-NULL-checks-in-MCU-STA-TLV-func.patch | 48 ++++ ...-add-NULL-checks-for-link_conf-and-m.patch | 122 +++++++++ ...-add-error-handling-for-AMPDU-MCU-co.patch | 64 +++++ ...-add-error-handling-for-BSS-info-MCU.patch | 40 +++ ...-add-error-handling-for-BSS-info-in-.patch | 35 +++ ...-add-NULL-checks-in-MLO-link-and-cha.patch | 104 +++++++ ...-fix-NULL-pointer-dereference-in-TX-.patch | 70 +++++ ...-add-lockdep-assertions-for-mutex-ve.patch | 52 ++++ ...-fix-key-removal-failure-during-MLO-.patch | 54 ++++ ...-fix-kernel-warning-in-MLO-ROC-setup.patch | 69 +++++ ...-add-NULL-checks-for-MLO-link-pointe.patch | 83 ++++++ ...-fix-firmware-reload-failure-after-p.patch | 53 ++++ ...-add-mutex-protection-in-resume-path.patch | 32 +++ ...-add-NULL-checks-for-link-pointers-i.patch | 48 ++++ ...-fix-BA-session-teardown-during-beac.patch | 45 ++++ ...-fix-deadlock-in-sta-removal-ROC-abo.patch | 143 ++++++++++ ...25-fix-ROC-timer-race-during-suspend.patch | 47 ++++ ...-add-ROC-rate-limiting-to-mitigate-M.patch | 254 ++++++++++++++++++ ...-improve-error-handling-and-code-cle.patch | 184 +++++++++++++ ...7925-fix-deadlock-and-WCID-leak-bugs.patch | 169 ++++++++++++ ...-fix-race-condition-in-async-ROC-abo.patch | 147 ++++++++++ ...=> 100-fix-build-with-linux-6.12rc2.patch} | 0 ...timer_setup-in-mt76x02u-beacon-init.patch} | 0 openwrt/scripts/01-prepare_base-mainline.sh | 30 ++- 27 files changed, 2095 insertions(+), 2 deletions(-) create mode 100644 openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch create mode 100644 openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch create mode 100644 openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch create mode 100644 openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch create mode 100644 openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch create mode 100644 openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch create mode 100644 openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch create mode 100644 openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch create mode 100644 openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch create mode 100644 openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch create mode 100644 openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch create mode 100644 openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch create mode 100644 openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch create mode 100644 openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch create mode 100644 openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch create mode 100644 openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch create mode 100644 openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch create mode 100644 openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch create mode 100644 openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch create mode 100644 openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch create mode 100644 openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch create mode 100644 openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch create mode 100644 openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch create mode 100644 openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch rename openwrt/patch/mt76/patches/{101-fix-build-with-linux-6.12rc2.patch => 100-fix-build-with-linux-6.12rc2.patch} (100%) rename openwrt/patch/mt76/patches/{002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch => 102-use-hrtimer_setup-in-mt76x02u-beacon-init.patch} (100%) diff --git a/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch b/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch new file mode 100644 index 000000000..97ca319e8 --- /dev/null +++ b/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch @@ -0,0 +1,76 @@ +From c0cffda0635828184cae6b8e2f91827deaff5062 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 16:51:17 -0800 +Subject: [PATCH 01/24] wifi: mt76: mt7925: fix NULL pointer dereference in vif + iteration + +Add NULL checks for bss_conf in all loops that iterate over valid_links +and call mt792x_vif_to_bss_conf(). This prevents kernel panics when the +link configuration in mac80211 is not yet set up even though the driver's +valid_links bitmap has the link marked as valid. + +This can happen during HW reset when link state is inconsistent, or during +MLO operations where the driver's link tracking is ahead of mac80211's +BSS configuration. + +Reported-by: Zac Bowling +Tested-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/mac.c | 6 ++++++ + mt7925/main.c | 8 ++++++++ + 2 files changed, 14 insertions(+) + +--- a/mt7925/mac.c ++++ b/mt7925/mac.c +@@ -1276,6 +1276,12 @@ mt7925_vif_connect_iter(void *priv, u8 * + bss_conf = mt792x_vif_to_bss_conf(vif, i); + mconf = mt792x_vif_to_link(mvif, i); + ++ /* Skip links that don't have bss_conf set up yet in mac80211. ++ * This can happen during HW reset when link state is inconsistent. ++ */ ++ if (!bss_conf) ++ continue; ++ + mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76, + &mvif->sta.deflink.wcid, true); + mt7925_mcu_set_tx(dev, bss_conf); +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -1312,6 +1312,8 @@ mt7925_mlo_pm_iter(void *priv, u8 *mac, + mt792x_mutex_acquire(dev); + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); ++ if (!bss_conf) ++ continue; + mt7925_mcu_uni_bss_ps(dev, bss_conf); + } + mt792x_mutex_release(dev); +@@ -1646,6 +1648,8 @@ static void mt7925_ipv6_addr_change(stru + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); ++ if (!bss_conf) ++ continue; + __mt7925_ipv6_addr_change(hw, bss_conf, idev); + } + } +@@ -1886,6 +1890,8 @@ static void mt7925_vif_cfg_changed(struc + if (changed & BSS_CHANGED_ARP_FILTER) { + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); ++ if (!bss_conf) ++ continue; + mt7925_mcu_update_arp_filter(&dev->mt76, bss_conf); + } + } +@@ -1901,6 +1907,8 @@ static void mt7925_vif_cfg_changed(struc + } else if (mvif->mlo_pm_state == MT792x_MLO_CHANGED_PS) { + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); ++ if (!bss_conf) ++ continue; + mt7925_mcu_uni_bss_ps(dev, bss_conf); + } + } diff --git a/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch b/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch new file mode 100644 index 000000000..83aac4a89 --- /dev/null +++ b/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch @@ -0,0 +1,57 @@ +From b597a5c4c11574a15db2a0a8f8fc07eaa869ccda Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 16:51:29 -0800 +Subject: [PATCH 02/24] wifi: mt76: mt7925: fix missing mutex protection in + reset and ROC abort + +During firmware recovery and ROC (Remain On Channel) abort operations, +the driver iterates over active interfaces and calls MCU functions that +require the device mutex to be held, but the mutex was not acquired. + +This causes system-wide hangs where network commands hang indefinitely, +processes get stuck in uninterruptible sleep (D state), and the system +becomes completely unresponsive requiring force reboot. + +Add mutex protection around interface iteration in: +- mt7925_mac_reset_work(): Called during firmware recovery after MCU + timeouts to reconnect all interfaces +- PCI suspend path: Wrap mt7925_roc_abort_sync() call with mutex + +Note: The mutex is added at the call site in pci.c rather than inside +mt7925_roc_abort_sync() because this function is also called from the +station remove path which already holds the mutex. + +Reported-by: Zac Bowling +Tested-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/mac.c | 2 ++ + mt7925/pci.c | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/mt7925/mac.c ++++ b/mt7925/mac.c +@@ -1336,9 +1336,11 @@ void mt7925_mac_reset_work(struct work_s + dev->hw_full_reset = false; + pm->suspended = false; + ieee80211_wake_queues(hw); ++ mt792x_mutex_acquire(dev); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_vif_connect_iter, NULL); ++ mt792x_mutex_release(dev); + mt76_connac_power_save_sched(&dev->mt76.phy, pm); + + mt7925_regd_change(&dev->phy, "00"); +--- a/mt7925/pci.c ++++ b/mt7925/pci.c +@@ -455,7 +455,9 @@ static int mt7925_pci_suspend(struct dev + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + ++ mt792x_mutex_acquire(dev); + mt7925_roc_abort_sync(dev); ++ mt792x_mutex_release(dev); + + err = mt792x_mcu_drv_pmctrl(dev); + if (err < 0) diff --git a/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch b/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch new file mode 100644 index 000000000..81b4521cc --- /dev/null +++ b/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch @@ -0,0 +1,71 @@ +From d50a5ea85f9f33b7127a26b12327ae622c1b45fd Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 16:51:37 -0800 +Subject: [PATCH 03/24] wifi: mt76: mt7925: fix missing mutex protection in + runtime PM and MLO PM + +Two additional code paths iterate over active interfaces and call MCU +functions without proper mutex protection: + +1. mt7925_set_runtime_pm(): Called when runtime PM settings change. + The ieee80211_iterate_active_interfaces() call invokes + mt7925_pm_interface_iter() which calls mt7925_mcu_set_beacon_filter(). + +2. mt7925_mlo_pm_work(): Workqueue function for MLO power management. + The iterator callback mt7925_mlo_pm_iter() calls mt7925_mcu_uni_bss_ps(). + +Add mutex protection around the iterate calls in both functions. For +mt7925_mlo_pm_iter(), move the mutex from inside the callback to the +caller (mt7925_mlo_pm_work) for consistency with other patterns. + +This matches the pattern used in the older mt7615 driver and other +wireless drivers like iwlwifi. + +Reported-by: Zac Bowling +Tested-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -759,9 +759,11 @@ void mt7925_set_runtime_pm(struct mt792x + bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); + + pm->enable = pm->enable_user && !monitor; ++ mt792x_mutex_acquire(dev); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_pm_interface_iter, dev); ++ mt792x_mutex_release(dev); + pm->ds_enable = pm->ds_enable_user && !monitor; + mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); + } +@@ -1309,14 +1311,12 @@ mt7925_mlo_pm_iter(void *priv, u8 *mac, + if (mvif->mlo_pm_state != MT792x_MLO_CHANGED_PS) + return; + +- mt792x_mutex_acquire(dev); + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + if (!bss_conf) + continue; + mt7925_mcu_uni_bss_ps(dev, bss_conf); + } +- mt792x_mutex_release(dev); + } + + void mt7925_mlo_pm_work(struct work_struct *work) +@@ -1325,9 +1325,11 @@ void mt7925_mlo_pm_work(struct work_stru + mlo_pm_work.work); + struct ieee80211_hw *hw = mt76_hw(dev); + ++ mt792x_mutex_acquire(dev); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mlo_pm_iter, dev); ++ mt792x_mutex_release(dev); + } + + void mt7925_scan_work(struct work_struct *work) diff --git a/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch b/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch new file mode 100644 index 000000000..c91b3e412 --- /dev/null +++ b/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch @@ -0,0 +1,48 @@ +From f6d73e60d473f84899ec8973d5b4c59520a1041b Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 17:09:05 -0800 +Subject: [PATCH 04/24] wifi: mt76: mt7925: add NULL checks in MCU STA TLV + functions + +Add NULL pointer checks for link_conf and mconf in: +- mt7925_mcu_sta_phy_tlv(): builds PHY capability TLV for station record +- mt7925_mcu_sta_rate_ctrl_tlv(): builds rate control TLV for station record + +Both functions call mt792x_vif_to_bss_conf() and mt792x_vif_to_link() +which can return NULL during MLO link state transitions when the link +configuration in mac80211 is not yet synchronized with the driver's +link tracking. + +Without these checks, the driver will crash with a NULL pointer +dereference when accessing link_conf->chanreq.oper or link_conf->basic_rates. + +Reported-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/mcu.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/mt7925/mcu.c ++++ b/mt7925/mcu.c +@@ -1778,6 +1778,10 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *s + + link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); + mconf = mt792x_vif_to_link(mvif, link_sta->link_id); ++ ++ if (!link_conf || !mconf) ++ return; ++ + chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : + &link_conf->chanreq.oper; + +@@ -1856,6 +1860,10 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_b + + link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); + mconf = mt792x_vif_to_link(mvif, link_sta->link_id); ++ ++ if (!link_conf || !mconf) ++ return; ++ + chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : + &link_conf->chanreq.oper; + band = chandef->chan->band; diff --git a/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch b/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch new file mode 100644 index 000000000..2c1e5e197 --- /dev/null +++ b/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch @@ -0,0 +1,122 @@ +From 36afd6a3968570e92101e3599fa5a28bc943f915 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 17:10:57 -0800 +Subject: [PATCH 05/24] wifi: mt76: mt7925: add NULL checks for link_conf and + mlink in main.c + +Add NULL pointer checks throughout main.c for functions that call +mt792x_vif_to_bss_conf(), mt792x_vif_to_link(), and mt792x_sta_to_link() +without verifying the return value before dereferencing. + +Functions fixed: +- mt7925_set_key(): Check link_conf, mconf, and mlink before use +- mt7925_mac_link_sta_add(): Check link_conf before BSS info update +- mt7925_mac_link_sta_assoc(): Check mlink and link_conf before use +- mt7925_mac_link_sta_remove(): Check mlink and link_conf, add goto + label for proper cleanup path +- mt7925_change_vif_links(): Check link_conf before adding BSS + +These functions can receive NULL when the link configuration in mac80211 +is not yet synchronized with the driver's link tracking during MLO +operations or state transitions. + +Without these checks, the driver will crash with NULL pointer +dereferences during station add/remove/association operations. + +Reported-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -612,6 +612,10 @@ static int mt7925_set_link_key(struct ie + link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(msta, link_id); ++ ++ if (!link_conf || !mconf || !mlink) ++ return -EINVAL; ++ + wcid = &mlink->wcid; + wcid_keyidx = &wcid->hw_key_idx; + +@@ -897,6 +901,8 @@ static int mt7925_mac_link_sta_add(struc + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + link_conf = mt792x_vif_to_bss_conf(vif, link_id); ++ if (!link_conf) ++ return -EINVAL; + + /* should update bss info before STA add */ + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { +@@ -1042,6 +1048,8 @@ static void mt7925_mac_link_sta_assoc(st + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); ++ if (!mlink) ++ return; + + mt792x_mutex_acquire(dev); + +@@ -1051,12 +1059,13 @@ static void mt7925_mac_link_sta_assoc(st + link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + } + +- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { ++ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_bss_conf *mconf; + + mconf = mt792x_link_conf_to_mconf(link_conf); +- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, +- link_conf, link_sta, true); ++ if (mconf) ++ mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, ++ link_conf, link_sta, true); + } + + ewma_avg_signal_init(&mlink->avg_ack_signal); +@@ -1103,6 +1112,8 @@ static void mt7925_mac_link_sta_remove(s + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_id); ++ if (!mlink) ++ return; + + mt7925_roc_abort_sync(dev); + +@@ -1116,10 +1127,12 @@ static void mt7925_mac_link_sta_remove(s + + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + +- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { ++ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_bss_conf *mconf; + + mconf = mt792x_link_conf_to_mconf(link_conf); ++ if (!mconf) ++ goto out; + + if (ieee80211_vif_is_mld(vif)) + mt792x_mac_link_bss_remove(dev, mconf, mlink); +@@ -1127,6 +1140,7 @@ static void mt7925_mac_link_sta_remove(s + mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, + link_sta, false); + } ++out: + + spin_lock_bh(&mdev->sta_poll_lock); + if (!list_empty(&mlink->wcid.poll_list)) +@@ -2050,6 +2064,11 @@ mt7925_change_vif_links(struct ieee80211 + mlink = mlinks[link_id]; + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + ++ if (!link_conf) { ++ err = -EINVAL; ++ goto free; ++ } ++ + rcu_assign_pointer(mvif->link_conf[link_id], mconf); + rcu_assign_pointer(mvif->sta.link[link_id], mlink); + diff --git a/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch b/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch new file mode 100644 index 000000000..55e1884c1 --- /dev/null +++ b/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch @@ -0,0 +1,64 @@ +From 110376227cac0081a5e137ae1f74ac1a766fcd62 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 17:20:50 -0800 +Subject: [PATCH 06/24] wifi: mt76: mt7925: add error handling for AMPDU MCU + commands + +Check return values of mt7925_mcu_uni_rx_ba() and mt7925_mcu_uni_tx_ba() +in mt7925_ampdu_action() and propagate errors to the caller. + +Previously, failures in these MCU commands were silently ignored, which +could leave block aggregation in an inconsistent state between the driver +and firmware. + +For IEEE80211_AMPDU_TX_STOP_CONT, only call the completion callback +ieee80211_stop_tx_ba_cb_irqsafe() if the MCU command succeeded, to avoid +signaling completion when the firmware operation failed. + +Reported-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -1279,22 +1279,22 @@ mt7925_ampdu_action(struct ieee80211_hw + case IEEE80211_AMPDU_RX_START: + mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn, + params->buf_size); +- mt7925_mcu_uni_rx_ba(dev, params, true); ++ ret = mt7925_mcu_uni_rx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); +- mt7925_mcu_uni_rx_ba(dev, params, false); ++ ret = mt7925_mcu_uni_rx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; +- mt7925_mcu_uni_tx_ba(dev, params, true); ++ ret = mt7925_mcu_uni_tx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->deflink.wcid.ampdu_state); +- mt7925_mcu_uni_tx_ba(dev, params, false); ++ ret = mt7925_mcu_uni_tx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_START: + set_bit(tid, &msta->deflink.wcid.ampdu_state); +@@ -1303,8 +1303,9 @@ mt7925_ampdu_action(struct ieee80211_hw + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->deflink.wcid.ampdu_state); +- mt7925_mcu_uni_tx_ba(dev, params, false); +- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ++ ret = mt7925_mcu_uni_tx_ba(dev, params, false); ++ if (!ret) ++ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + mt792x_mutex_release(dev); diff --git a/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch b/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch new file mode 100644 index 000000000..2f5977723 --- /dev/null +++ b/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch @@ -0,0 +1,40 @@ +From 4173078c845d19e66fc025abd26154ee22718a3f Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 17:21:34 -0800 +Subject: [PATCH 07/24] wifi: mt76: mt7925: add error handling for BSS info MCU + command in sta_add + +Check return value of mt7925_mcu_add_bss_info() in mt7925_mac_link_sta_add() +and propagate errors to the caller. + +BSS info must be set up before adding a station record. If this MCU +command fails, continuing with station add would leave the firmware in +an inconsistent state with a station but no BSS configuration. + +Reported-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -907,11 +907,14 @@ static int mt7925_mac_link_sta_add(struc + /* should update bss info before STA add */ + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + if (ieee80211_vif_is_mld(vif)) +- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, +- link_conf, link_sta, link_sta != mlink->pri_link); ++ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, ++ link_conf, link_sta, ++ link_sta != mlink->pri_link); + else +- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, +- link_conf, link_sta, false); ++ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, ++ link_conf, link_sta, false); ++ if (ret) ++ return ret; + } + + if (ieee80211_vif_is_mld(vif) && diff --git a/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch b/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch new file mode 100644 index 000000000..1b5537335 --- /dev/null +++ b/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch @@ -0,0 +1,35 @@ +From 0ed559511504baf62cfe5d714d9d7e2ca219fd7a Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 17:21:51 -0800 +Subject: [PATCH 08/24] wifi: mt76: mt7925: add error handling for BSS info in + key setup + +Check return value of mt7925_mcu_add_bss_info() in mt7925_set_key_link() +when setting up cipher for the first time and propagate errors. + +The BSS info update with cipher information must succeed before key +programming can proceed. If this MCU command fails, continuing with +key setup would program keys into the firmware for a BSS that doesn't +have the correct cipher configuration. + +Reported-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -645,8 +645,10 @@ static int mt7925_set_link_key(struct ie + struct mt792x_phy *phy = mt792x_hw_phy(hw); + + mconf->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); +- mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf, +- link_sta, true); ++ err = mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf, ++ link_sta, true); ++ if (err) ++ goto out; + } + + if (cmd == SET_KEY) diff --git a/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch b/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch new file mode 100644 index 000000000..29ff2b231 --- /dev/null +++ b/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch @@ -0,0 +1,104 @@ +From 17e94c11b17adcede06bf43deca351a2a5163705 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 17:32:55 -0800 +Subject: [PATCH 09/24] wifi: mt76: mt7925: add NULL checks in MLO link and + chanctx functions + +Add NULL pointer checks for mconf and link_conf in several functions +that were missing validation after calling mt792x_vif_to_link() and +mt792x_vif_to_bss_conf(). + +Functions fixed: +- mt7925_mac_set_links(): Check both primary and secondary link_conf + before dereferencing chanreq.oper for band selection +- mt7925_link_info_changed(): Check mconf before using it to get + link_conf, prevents NULL dereference chain +- mt7925_assign_vif_chanctx(): Check mconf before use, return -EINVAL + if NULL; check pri_link_conf before passing to MCU function +- mt7925_unassign_vif_chanctx(): Check mconf before dereferencing, + return early if NULL during MLO cleanup + +These functions handle MLO (Multi-Link Operation) scenarios where link +configurations may not be fully set up when called, particularly during +rapid link state transitions or error recovery paths. + +Reported-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 36 +++++++++++++++++++++++++++++------- + 1 file changed, 29 insertions(+), 7 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -1014,18 +1014,29 @@ mt7925_mac_set_links(struct mt76_dev *md + { + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; +- struct ieee80211_bss_conf *link_conf = +- mt792x_vif_to_bss_conf(vif, mvif->deflink_id); +- struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; +- enum nl80211_band band = chandef->chan->band, secondary_band; ++ struct ieee80211_bss_conf *link_conf; ++ struct cfg80211_chan_def *chandef; ++ enum nl80211_band band, secondary_band; ++ u16 sel_links; ++ u8 secondary_link_id; ++ ++ link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); ++ if (!link_conf) ++ return; + +- u16 sel_links = mt76_select_links(vif, 2); +- u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); ++ chandef = &link_conf->chanreq.oper; ++ band = chandef->chan->band; ++ ++ sel_links = mt76_select_links(vif, 2); ++ secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); + + if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2) + return; + + link_conf = mt792x_vif_to_bss_conf(vif, secondary_link_id); ++ if (!link_conf) ++ return; ++ + secondary_band = link_conf->chanreq.oper.chan->band; + + if (band == NL80211_BAND_2GHZ || +@@ -1951,6 +1962,8 @@ static void mt7925_link_info_changed(str + struct mt792x_bss_conf *mconf; + + mconf = mt792x_vif_to_link(mvif, info->link_id); ++ if (!mconf) ++ return; + + mt792x_mutex_acquire(dev); + +@@ -2155,9 +2168,14 @@ static int mt7925_assign_vif_chanctx(str + + if (ieee80211_vif_is_mld(vif)) { + mconf = mt792x_vif_to_link(mvif, link_conf->link_id); ++ if (!mconf) { ++ mutex_unlock(&dev->mt76.mutex); ++ return -EINVAL; ++ } ++ + pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); + +- if (vif->type == NL80211_IFTYPE_STATION && ++ if (pri_link_conf && vif->type == NL80211_IFTYPE_STATION && + mconf == &mvif->bss_conf) + mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf, + NULL, true); +@@ -2186,6 +2204,10 @@ static void mt7925_unassign_vif_chanctx( + + if (ieee80211_vif_is_mld(vif)) { + mconf = mt792x_vif_to_link(mvif, link_conf->link_id); ++ if (!mconf) { ++ mutex_unlock(&dev->mt76.mutex); ++ return; ++ } + + if (vif->type == NL80211_IFTYPE_STATION && + mconf == &mvif->bss_conf) diff --git a/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch b/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch new file mode 100644 index 000000000..a6ceabbb5 --- /dev/null +++ b/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch @@ -0,0 +1,70 @@ +From 1521b28edece1801c7e2edc657b456721720022c Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 17:38:26 -0800 +Subject: [PATCH 10/24] wifi: mt76: mt792x: fix NULL pointer dereference in TX + path + +Add NULL pointer checks in mt792x_tx() to prevent kernel crashes when +transmitting packets during MLO link removal. + +The function calls mt792x_sta_to_link() which can return NULL if the +link is being removed, but the return value was dereferenced without +checking. Similarly, the RCU-protected link_conf and link_sta pointers +were used without NULL validation. + +This race can occur when: +1. A packet is queued for transmission +2. Concurrently, the link is being removed (mt7925_mac_link_sta_remove) +3. mt792x_sta_to_link() returns NULL for the removed link +4. Kernel crashes on wcid = &mlink->wcid dereference + +Fix by: +- Check mlink return value before dereferencing wcid +- Check RCU-dereferenced conf and link_sta before use +- Free the SKB and return early if any pointer is NULL + +This affects both MT7921 and MT7925 drivers as mt792x_core.c is shared. + +Reported-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt792x_core.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/mt792x_core.c ++++ b/mt792x_core.c +@@ -95,6 +95,8 @@ void mt792x_tx(struct ieee80211_hw *hw, + IEEE80211_TX_CTRL_MLO_LINK); + sta = (struct mt792x_sta *)control->sta->drv_priv; + mlink = mt792x_sta_to_link(sta, link_id); ++ if (!mlink) ++ goto free_skb; + wcid = &mlink->wcid; + } + +@@ -113,9 +115,12 @@ void mt792x_tx(struct ieee80211_hw *hw, + link_id = wcid->link_id; + rcu_read_lock(); + conf = rcu_dereference(vif->link_conf[link_id]); +- memcpy(hdr->addr2, conf->addr, ETH_ALEN); +- + link_sta = rcu_dereference(control->sta->link[link_id]); ++ if (!conf || !link_sta) { ++ rcu_read_unlock(); ++ goto free_skb; ++ } ++ memcpy(hdr->addr2, conf->addr, ETH_ALEN); + memcpy(hdr->addr1, link_sta->addr, ETH_ALEN); + + if (vif->type == NL80211_IFTYPE_STATION) +@@ -136,6 +141,10 @@ void mt792x_tx(struct ieee80211_hw *hw, + } + + mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); ++ return; ++ ++free_skb: ++ ieee80211_free_txskb(hw, skb); + } + EXPORT_SYMBOL_GPL(mt792x_tx); + diff --git a/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch b/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch new file mode 100644 index 000000000..d2c2d5f3e --- /dev/null +++ b/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch @@ -0,0 +1,52 @@ +From e92c47a90205ce125af3d0b6f21d008f8e816aa8 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 31 Dec 2025 21:31:51 -0800 +Subject: [PATCH 11/24] wifi: mt76: mt7925: add lockdep assertions for mutex + verification + +Add lockdep_assert_held() calls to critical MCU functions to help catch +mutex violations during development and debugging. This follows the +pattern used in other mt76 drivers (mt7996, mt7915, mt7615). + +Functions with new assertions: +- mt7925_mcu_add_bss_info(): Core BSS configuration MCU command +- mt7925_mcu_sta_update(): Station record update MCU command +- mt7925_mcu_uni_bss_ps(): Power save state MCU command + +These functions modify firmware state and must be called with the +device mutex held to prevent race conditions. + +Signed-off-by: Zac Bowling +--- + mt7925/mcu.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/mt7925/mcu.c ++++ b/mt7925/mcu.c +@@ -1532,6 +1532,8 @@ int mt7925_mcu_uni_bss_ps(struct mt792x_ + }, + }; + ++ lockdep_assert_held(&dev->mt76.mutex); ++ + if (link_conf->vif->type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + +@@ -2042,6 +2044,8 @@ int mt7925_mcu_sta_update(struct mt792x_ + struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; + ++ lockdep_assert_held(&dev->mt76.mutex); ++ + if (link_sta) { + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); +@@ -2848,6 +2852,8 @@ int mt7925_mcu_add_bss_info(struct mt792 + struct mt792x_link_sta *mlink_bc; + struct sk_buff *skb; + ++ lockdep_assert_held(&dev->mt76.mutex); ++ + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, + MT7925_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) diff --git a/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch b/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch new file mode 100644 index 000000000..3fdecd1c8 --- /dev/null +++ b/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch @@ -0,0 +1,54 @@ +From 22e6df471b3f7f60cb947f9e71e0188ef07abea0 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Thu, 1 Jan 2026 12:09:42 -0800 +Subject: [PATCH 12/24] wifi: mt76: mt7925: fix key removal failure during MLO + roaming + +During MLO roaming, mac80211 may request key removal after the link state +has already been torn down. The current code returns -EINVAL when +link_conf, mconf, or mlink is NULL, causing 'failed to remove key from +hardware (-22)' errors in the kernel log. + +This is a race condition where: +1. MLO link teardown begins, cleaning up driver state +2. mac80211 requests group key removal for the old link +3. mt792x_vif_to_bss_conf() or related functions return NULL +4. Driver returns -EINVAL, confusing upper layers + +The fix: When removing a key (cmd != SET_KEY), if the link state is +already gone, return success (0) instead of error. The key is effectively +removed when the link was torn down. + +This prevents the following errors during roaming: + wlp192s0: failed to remove key (1, ff:ff:ff:ff:ff:ff) from hardware (-22) + wlp192s0: failed to remove key (4, ff:ff:ff:ff:ff:ff) from hardware (-22) + +And the associated wpa_supplicant warnings: + nl80211: kernel reports: link ID must for MLO group key + +Reported-by: Zac Bowling +Tested-by: Zac Bowling +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -613,8 +613,15 @@ static int mt7925_set_link_key(struct ie + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(msta, link_id); + +- if (!link_conf || !mconf || !mlink) ++ if (!link_conf || !mconf || !mlink) { ++ /* During MLO roaming, link state may be torn down before ++ * mac80211 requests key removal. If removing a key and ++ * the link is already gone, consider it successfully removed. ++ */ ++ if (cmd != SET_KEY) ++ return 0; + return -EINVAL; ++ } + + wcid = &mlink->wcid; + wcid_keyidx = &wcid->hw_key_idx; diff --git a/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch b/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch new file mode 100644 index 000000000..b881eb966 --- /dev/null +++ b/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch @@ -0,0 +1,69 @@ +From c3304a1b31fe91c3b79e4e8263ced6ace1d21052 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Thu, 1 Jan 2026 12:36:10 -0800 +Subject: [PATCH 13/24] wifi: mt76: mt7925: fix kernel warning in MLO ROC setup + when channel not configured + +mt7925_mcu_set_mlo_roc() uses WARN_ON_ONCE() to check if link_conf or +channel is NULL. However, during MLO AP setup, it's normal for the +channel to not be configured yet when this function is called. The +WARN_ON_ONCE triggers a kernel warning/oops that makes the system +appear to have crashed, even though it's just a timing issue. + +Replace WARN_ON_ONCE with regular NULL checks and return -ENOLINK to +indicate the link isn't fully configured yet. This allows the upper +layers to retry when the link is ready, without spamming the kernel +log with warnings. + +Also add a check for mconf in the first loop to match the pattern +used in the second loop, preventing potential NULL dereference. + +This fixes kernel oops reported during MLO AP setup on OpenWrt with +MT7925E hardware. + +Signed-off-by: Zac Bowling +--- + mt7925/mcu.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +--- a/mt7925/mcu.c ++++ b/mt7925/mcu.c +@@ -1341,15 +1341,23 @@ int mt7925_mcu_set_mlo_roc(struct mt792x + for (i = 0; i < ARRAY_SIZE(links); i++) { + links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) : + mconf->link_id; ++ + link_conf = mt792x_vif_to_bss_conf(vif, links[i].id); +- if (WARN_ON_ONCE(!link_conf)) +- return -EPERM; ++ if (!link_conf) ++ return -ENOLINK; + + links[i].chan = link_conf->chanreq.oper.chan; +- if (WARN_ON_ONCE(!links[i].chan)) +- return -EPERM; ++ if (!links[i].chan) ++ /* Channel not configured yet - this can happen during ++ * MLO AP setup when links are being added sequentially. ++ * Return -ENOLINK to indicate link not ready. ++ */ ++ return -ENOLINK; + + links[i].mconf = mt792x_vif_to_link(mvif, links[i].id); ++ if (!links[i].mconf) ++ return -ENOLINK; ++ + links[i].tag = links[i].id == mconf->link_id ? + UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK; + +@@ -1364,8 +1372,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x + type = MT7925_ROC_REQ_JOIN; + + for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) { +- if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan)) +- continue; ++ if (!links[i].mconf || !links[i].chan) ++ return -ENOLINK; + + chan = links[i].chan; + center_ch = ieee80211_frequency_to_channel(chan->center_freq); diff --git a/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch b/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch new file mode 100644 index 000000000..84028f1c7 --- /dev/null +++ b/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch @@ -0,0 +1,83 @@ +From 3f898f3367d6f211e8c40aa6d9144a45eb47b066 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Mon, 5 Jan 2026 13:17:14 -0800 +Subject: [PATCH 14/24] wifi: mt76: mt7925: add NULL checks for MLO link + pointers in MCU functions + +Several MCU functions dereference pointers returned by mt792x_sta_to_link() +and mt792x_vif_to_link() without checking for NULL. During MLO state +transitions, these functions can return NULL when link state is being +set up or torn down, causing kernel NULL pointer dereferences. + +Add NULL checks in the following functions: + +- mt7925_mcu_sta_hdr_trans_tlv(): Check mlink before dereferencing wcid +- mt7925_mcu_wtbl_update_hdr_trans(): Check mlink and mconf before use +- mt7925_mcu_sta_amsdu_tlv(): Check mlink before setting amsdu flag +- mt7925_mcu_sta_mld_tlv(): Check mconf and mlink in link iteration loop +- mt7925_mcu_sta_update(): Initialize mlink to NULL and check both + link_sta and mlink in the ternary condition + +Signed-off-by: Zac Bowling +--- + mt7925/mcu.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/mt7925/mcu.c ++++ b/mt7925/mcu.c +@@ -1087,6 +1087,8 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_b + struct mt792x_link_sta *mlink; + + mlink = mt792x_sta_to_link(msta, link_sta->link_id); ++ if (!mlink) ++ return; + wcid = &mlink->wcid; + } else { + wcid = &mvif->sta.deflink.wcid; +@@ -1120,6 +1122,9 @@ int mt7925_mcu_wtbl_update_hdr_trans(str + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); + mconf = mt792x_vif_to_link(mvif, link_id); + ++ if (!mlink || !mconf) ++ return -EINVAL; ++ + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, + &mlink->wcid, + MT7925_STA_UPDATE_MAX_SIZE); +@@ -1756,6 +1761,8 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff + amsdu->amsdu_en = true; + + mlink = mt792x_sta_to_link(msta, link_sta->link_id); ++ if (!mlink) ++ return; + mlink->wcid.amsdu = true; + + switch (link_sta->agg.max_amsdu_len) { +@@ -1958,6 +1965,9 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *s + + mconf = mt792x_vif_to_link(mvif, i); + mlink = mt792x_sta_to_link(msta, i); ++ if (!mconf || !mlink) ++ continue; ++ + mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); + mld->link[cnt++].bss_idx = mconf->mt76.idx; + +@@ -2050,7 +2060,7 @@ int mt7925_mcu_sta_update(struct mt792x_ + .rcpi = to_rcpi(rssi), + }; + struct mt792x_sta *msta; +- struct mt792x_link_sta *mlink; ++ struct mt792x_link_sta *mlink = NULL; + + lockdep_assert_held(&dev->mt76.mutex); + +@@ -2058,7 +2068,7 @@ int mt7925_mcu_sta_update(struct mt792x_ + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + } +- info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid; ++ info.wcid = (link_sta && mlink) ? &mlink->wcid : &mvif->sta.deflink.wcid; + info.newly = state != MT76_STA_INFO_STATE_ASSOC; + + return mt7925_mcu_sta_cmd(&dev->mphy, &info); diff --git a/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch b/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch new file mode 100644 index 000000000..be6f50d39 --- /dev/null +++ b/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch @@ -0,0 +1,53 @@ +From 59e0921dd7e913052f2b69b93ea544417595f118 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Thu, 1 Jan 2026 14:01:50 -0800 +Subject: [PATCH 15/24] wifi: mt76: mt792x: fix firmware reload failure after + previous load crash + +If the firmware loading process crashes or is interrupted after +acquiring the patch semaphore but before releasing it, subsequent +firmware load attempts will fail with 'Failed to get patch semaphore' +because the semaphore is still held. + +This issue manifests as devices becoming unusable after suspend/resume +failures or firmware crashes, requiring a full hardware reboot to +recover. This has been widely reported on MT7921 and MT7925 devices. + +Apply the same fix that was applied to MT7915 in commit 79dd14f: +1. Release the patch semaphore before starting firmware load (in case + it was held by a previous failed attempt) +2. Restart MCU firmware to ensure clean state +3. Wait briefly for MCU to be ready + +This fix applies to both MT7921 and MT7925 drivers which share the +mt792x_load_firmware() function. + +Fixes: 'Failed to get patch semaphore' errors after firmware crash +Signed-off-by: Zac Bowling +--- + mt792x_core.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/mt792x_core.c ++++ b/mt792x_core.c +@@ -935,6 +935,20 @@ int mt792x_load_firmware(struct mt792x_d + { + int ret; + ++ /* Release semaphore if taken by previous failed load attempt. ++ * This prevents "Failed to get patch semaphore" errors when ++ * recovering from firmware crashes or suspend/resume failures. ++ */ ++ ret = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); ++ if (ret < 0) ++ dev_dbg(dev->mt76.dev, "Semaphore release returned %d (may be expected)\n", ret); ++ ++ /* Always restart MCU to ensure clean state before loading firmware */ ++ mt76_connac_mcu_restart(&dev->mt76); ++ ++ /* Wait for MCU to be ready after restart */ ++ msleep(100); ++ + ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); + if (ret) + return ret; diff --git a/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch b/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch new file mode 100644 index 000000000..3c8205f4c --- /dev/null +++ b/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch @@ -0,0 +1,32 @@ +From c99b552b61470ff398b632fea8fcc4b5ee253223 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Wed, 14 Jan 2026 19:54:46 -0800 +Subject: [PATCH 16/24] wifi: mt76: mt7925: add mutex protection in resume path + +Add mutex protection around mt7925_mcu_set_deep_sleep() and +mt7925_regd_update() calls in the resume path to prevent +potential race conditions during resume operations. + +These MCU operations require serialization, and the resume +path was the only call site missing mutex protection. + +Signed-off-by: Zac Bowling +--- + mt7925/pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mt7925/pci.c ++++ b/mt7925/pci.c +@@ -584,10 +584,12 @@ static int _mt7925_pci_resume(struct dev + } + + /* restore previous ds setting */ ++ mt792x_mutex_acquire(dev); + if (!pm->ds_enable) + mt7925_mcu_set_deep_sleep(dev, false); + + mt7925_mcu_regd_update(dev, mdev->alpha2, dev->country_ie_env); ++ mt792x_mutex_release(dev); + failed: + pm->suspended = false; + diff --git a/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch b/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch new file mode 100644 index 000000000..751a05fa6 --- /dev/null +++ b/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch @@ -0,0 +1,48 @@ +From d4e0c1a849c99da51e6926947b1bd4c4757801e9 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Mon, 5 Jan 2026 13:19:02 -0800 +Subject: [PATCH 17/24] wifi: mt76: mt7925: add NULL checks for link pointers + in sta_add and conf_tx + +Add NULL pointer checks for mt792x_sta_to_link() and mt792x_vif_to_link() +results in mt7925_mac_link_sta_add() and mt7925_conf_tx() to prevent +kernel crashes during MLO operations. + +The init.c changes from the original patch are not needed as the +mt7925_regd_update() function was refactored in 6.19-rc4. + +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -879,12 +879,17 @@ static int mt7925_mac_link_sta_add(struc + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_id); ++ if (!mlink) ++ return -EINVAL; + + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; + + mconf = mt792x_vif_to_link(mvif, link_id); ++ if (!mconf) ++ return -EINVAL; ++ + mt76_wcid_init(&mlink->wcid, 0); + mlink->wcid.sta = 1; + mlink->wcid.idx = idx; +@@ -1751,6 +1756,9 @@ mt7925_conf_tx(struct ieee80211_hw *hw, + [IEEE80211_AC_BK] = 1, + }; + ++ if (!mconf) ++ return -EINVAL; ++ + /* firmware uses access class index */ + mconf->queue_params[mq_to_aci[queue]] = *params; + diff --git a/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch b/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch new file mode 100644 index 000000000..6c9c625d8 --- /dev/null +++ b/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch @@ -0,0 +1,45 @@ +From 593bb9c6da996644f40acf32abe5f1ae7fe406c3 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Thu, 15 Jan 2026 16:35:55 -0800 +Subject: [PATCH 18/24] wifi: mt76: mt7925: fix BA session teardown during + beacon loss + +The ieee80211_stop_tx_ba_cb_irqsafe() callback was conditionally called +only when the MCU command succeeded. However, during beacon connection +loss, the MCU command may fail because the AP is no longer reachable. + +If the callback is not called, mac80211's BA session state machine gets +stuck in an intermediate state. When mac80211 later tries to tear down +all BA sessions during disconnection, it hits a WARN in +__ieee80211_stop_tx_ba_session() due to the inconsistent state. + +Fix by making the callback unconditional, matching the behavior of +mt7921 and mt7996 drivers. The MCU command failure is acceptable during +disconnection - what matters is that mac80211 is notified to complete +the session teardown. + +Reported-by: Sean Wang +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -1331,9 +1331,13 @@ mt7925_ampdu_action(struct ieee80211_hw + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->deflink.wcid.ampdu_state); +- ret = mt7925_mcu_uni_tx_ba(dev, params, false); +- if (!ret) +- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ++ /* MCU command may fail during beacon loss, but callback must ++ * always be called to complete the BA session teardown in ++ * mac80211. Otherwise the state machine gets stuck and triggers ++ * WARN in __ieee80211_stop_tx_ba_session(). ++ */ ++ mt7925_mcu_uni_tx_ba(dev, params, false); ++ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + mt792x_mutex_release(dev); diff --git a/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch b/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch new file mode 100644 index 000000000..066d3b5ce --- /dev/null +++ b/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch @@ -0,0 +1,143 @@ +From 95dc76b6053151eeedaaa1477ffa26990fdb5fc8 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Fri, 16 Jan 2026 21:59:42 -0800 +Subject: [PATCH 19/24] wifi: mt76: mt7925: fix deadlock in sta removal ROC + abort path + +Fix a mutex deadlock that occurs during station removal when +cancel_work_sync() is called while already holding the device mutex. + +The deadlock occurs in the following scenario: + +Thread A (mac80211 sta_state callback): + mt76_sta_state() + -> mt76_sta_remove() + -> mutex_lock(&dev->mutex) // ACQUIRES MUTEX + -> __mt76_sta_remove() + -> mt7925_mac_sta_remove() + -> mt7925_mac_sta_remove_links() + -> mt7925_mac_link_sta_remove() + -> mt7925_roc_abort_sync() + -> cancel_work_sync(&roc_work) + // WAITS for roc_work + +Thread B (workqueue): + mt7925_roc_work() + -> mt792x_mutex_acquire() // BLOCKED waiting for mutex + +This results in a classic AB-BA deadlock where Thread A holds the mutex +and waits for roc_work to complete, while roc_work (Thread B) is blocked +waiting for the same mutex. + +From user reports (Framework Laptop 16 with MT7925, NixOS, kernel 6.18.5): + + INFO: task kworker/u128:0:48737 blocked for more than 122 seconds. + Workqueue: mt76 mt7925_mac_reset_work [mt7925_common] + Call Trace: + + __schedule+0x426/0x12c0 + schedule+0x27/0xf0 + schedule_preempt_disabled+0x15/0x30 + __mutex_lock.constprop.0+0x3d0/0x6d0 + mt7925_mac_reset_work+0x85/0x170 [mt7925_common] + ... + + Showing all locks held in the system: + 1 lock held by kworker/u128:5/48827: + #0: ffff9fff8179d930 (&dev->mutex){+.+.}-{4:4}, at: mt76_sta_remove + +The deadlock is triggered by roaming events (moving away from AP, BSSID +changes) when ROC work is pending and station removal occurs. + +The fix introduces an asynchronous ROC abort mechanism: + +1. Add MT76_STATE_ROC_ABORT flag to signal abort request +2. Create mt7925_roc_abort_async() that sets the flag without blocking +3. Modify mt7925_roc_work() to check abort flag BEFORE acquiring mutex +4. Use async abort in mt7925_mac_link_sta_remove() instead of sync + +The key insight is that if roc_work sees the abort flag before trying +to acquire the mutex, it can clean up and exit without blocking. This +breaks the deadlock chain while still ensuring proper ROC cleanup. + +Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") +Reported-by: Aritz Beobide-Cardinal +Signed-off-by: Zac Bowling +--- + mt76.h | 1 + + mt7925/main.c | 40 +++++++++++++++++++++++++++++++++++++++- + 2 files changed, 40 insertions(+), 1 deletion(-) + +--- a/mt76.h ++++ b/mt76.h +@@ -525,6 +525,7 @@ enum { + MT76_STATE_POWER_OFF, + MT76_STATE_SUSPEND, + MT76_STATE_ROC, ++ MT76_STATE_ROC_ABORT, + MT76_STATE_PM, + MT76_STATE_WED_RESET, + }; +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -457,6 +457,29 @@ static void mt7925_roc_iter(void *priv, + mt7925_mcu_abort_roc(phy, &mvif->bss_conf, phy->roc_token_id); + } + ++/* Async ROC abort - safe to call while holding mutex. ++ * Sets abort flag and lets roc_work handle cleanup without blocking. ++ * This prevents deadlock when called from sta_remove path which holds mutex. ++ */ ++static void mt7925_roc_abort_async(struct mt792x_dev *dev) ++{ ++ struct mt792x_phy *phy = &dev->phy; ++ ++ /* Set abort flag first - roc_work checks this before acquiring mutex */ ++ set_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); ++ ++ /* Clear ROC state */ ++ clear_bit(MT76_STATE_ROC, &phy->mt76->state); ++ ++ /* Stop the timer - use non-sync version to avoid blocking */ ++ timer_delete(&phy->roc_timer); ++ ++ /* Do NOT call cancel_work_sync here - that would deadlock if ++ * roc_work is waiting for mutex that we (caller) already hold. ++ * The work will see the abort flag and clean up gracefully. ++ */ ++} ++ + void mt7925_roc_abort_sync(struct mt792x_dev *dev) + { + struct mt792x_phy *phy = &dev->phy; +@@ -481,6 +504,17 @@ void mt7925_roc_work(struct work_struct + phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, + roc_work); + ++ /* Check abort flag BEFORE acquiring mutex to prevent deadlock. ++ * If abort is requested while we're in the sta_remove path (which ++ * holds the mutex), we must not try to acquire it or we'll deadlock. ++ * Just clear the flags and notify mac80211 that ROC expired. ++ */ ++ if (test_and_clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state)) { ++ clear_bit(MT76_STATE_ROC, &phy->mt76->state); ++ ieee80211_remain_on_channel_expired(phy->mt76->hw); ++ return; ++ } ++ + if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + return; + +@@ -1143,7 +1177,11 @@ static void mt7925_mac_link_sta_remove(s + if (!mlink) + return; + +- mt7925_roc_abort_sync(dev); ++ /* Use async abort to prevent deadlock - this function is called from ++ * mt76_sta_remove() which already holds dev->mt76.mutex. Using the ++ * sync version would deadlock if roc_work is waiting for the same mutex. ++ */ ++ mt7925_roc_abort_async(dev); + + mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); + mt76_connac_pm_wake(&dev->mphy, &dev->pm); diff --git a/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch b/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch new file mode 100644 index 000000000..35c260284 --- /dev/null +++ b/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch @@ -0,0 +1,47 @@ +From 428960f8f65f3be6a11910eba3e1f1000a80c4f6 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Mon, 19 Jan 2026 12:28:11 -0800 +Subject: [PATCH 20/24] wifi: mt76: mt7925: fix ROC timer race during suspend + +Cancel ROC timer and work in mt7925_suspend() (mac80211 callback) +before mac80211 finishes quiescing. Previously this was only done +in mt7925_pci_suspend() which is called later. + +The race condition: +1. mac80211 sets quiescing=true +2. mac80211 calls mt7925_suspend() - ROC timer still active +3. ROC timer fires, calls ieee80211_queue_work() -> warning +4. Later, mt7925_pci_suspend() cancels ROC timer (too late) + +This can leave the driver in an inconsistent state causing freezes +on resume. By canceling the ROC work early in the mac80211 suspend +callback, we ensure no ROC operations are pending when quiescing +begins. + +Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -1584,6 +1584,18 @@ static int mt7925_suspend(struct ieee802 + cancel_delayed_work_sync(&dev->pm.ps_work); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + ++ /* Cancel ROC timer and work before mac80211 finishes quiescing. ++ * This must happen here, not in pci_suspend, because mac80211 ++ * sets quiescing=true before calling this callback. If the ROC ++ * timer fires after quiescing starts, ieee80211_queue_work() will ++ * fail and leave the driver in an inconsistent state. ++ * ++ * IMPORTANT: Must be called BEFORE mutex_acquire to avoid deadlock. ++ * If roc_work is running and waiting for mutex, cancel_work_sync ++ * would block forever if we already hold the mutex. ++ */ ++ mt7925_roc_abort_sync(dev); ++ + mt792x_mutex_acquire(dev); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); diff --git a/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch b/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch new file mode 100644 index 000000000..511a636a6 --- /dev/null +++ b/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch @@ -0,0 +1,254 @@ +From 846ac23af31d165ce310257c91052518730d1604 Mon Sep 17 00:00:00 2001 +From: Zac Bowling +Date: Mon, 19 Jan 2026 12:32:01 -0800 +Subject: [PATCH 21/24] wifi: mt76: mt7925: add ROC rate limiting to mitigate + MLO auth failures + +Add exponential backoff rate limiting for ROC (Remain On Channel) +commands to prevent MCU overload during rapid reconnection cycles. + +Problem: +When MLO (Multi-Link Operation) authentication fails due to an upper +layer race condition, the driver enters a rapid reconnection loop that +overwhelms the MCU with ROC commands, causing timeouts and firmware +resets. + +Root Cause (upper layer bug, not fixed by this patch): +The kernel's nl80211 layer at net/wireless/nl80211.c:4828 requires +link_id for group key operations when MLO is active (wdev->valid_links +is set). During Fast Transition (802.11r) roaming: + +1. Device is connected in MLO mode (wdev->valid_links = bitmask) +2. FT roaming begins to new AP +3. wpa_supplicant attempts to set group keys without link_id +4. Disconnect hasn't completed yet - valid_links still set +5. nl80211 validation fails: "link ID must for MLO group key" +6. This triggers reconnection attempts with ROC commands +7. MCU overwhelmed -> timeouts -> firmware reset -> cycle repeats + +The race is between disconnect (which clears valid_links in +cfg80211's __cfg80211_disconnected at sme.c:1359) and key setup. + +This Mitigation: +- Track consecutive ROC timeouts in mt792x_phy structure +- Implement exponential backoff: 100ms, 200ms, 400ms, 800ms, 1600ms +- Reset backoff after 10 seconds of no timeouts +- Log warning after 5 consecutive timeouts to help identify the issue +- Short backoffs (<200ms) wait inline; longer ones return -EBUSY + +This doesn't fix the root cause but prevents the system from becoming +unresponsive during the failure cycle, giving users time to work around +the issue (e.g., disable MLO or use single-link WiFi 7). + +Upstream Bug Reports Needed: +- wpa_supplicant: MLO group key setup missing link_id during FT roaming +- mac80211/cfg80211: Race between disconnect and key setup sequencing + +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-- + mt792x.h | 7 +++ + 2 files changed, 136 insertions(+), 4 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -542,14 +542,108 @@ static int mt7925_abort_roc(struct mt792 + return err; + } + ++/* ROC rate limiting constants - exponential backoff to prevent MCU overload ++ * when upper layers trigger rapid reconnection cycles (e.g., MLO auth failures). ++ * Max backoff ~1.6s, resets after 10s of no timeouts. ++ */ ++#define MT7925_ROC_BACKOFF_BASE_MS 100 ++#define MT7925_ROC_BACKOFF_MAX_MS 1600 ++#define MT7925_ROC_TIMEOUT_RESET_MS 10000 ++#define MT7925_ROC_TIMEOUT_WARN_THRESH 5 ++ ++/* Check if ROC should be throttled due to recent timeouts. ++ * Returns delay in jiffies if throttling, 0 if OK to proceed. ++ */ ++static unsigned long mt7925_roc_throttle_check(struct mt792x_phy *phy) ++{ ++ unsigned long now = jiffies; ++ ++ /* Reset timeout counter if it's been a while since last timeout */ ++ if (phy->roc_timeout_count && ++ time_after(now, phy->roc_last_timeout + ++ msecs_to_jiffies(MT7925_ROC_TIMEOUT_RESET_MS))) { ++ phy->roc_timeout_count = 0; ++ phy->roc_backoff_until = 0; ++ } ++ ++ /* Check if we're still in backoff period */ ++ if (phy->roc_backoff_until && time_before(now, phy->roc_backoff_until)) ++ return phy->roc_backoff_until - now; ++ ++ return 0; ++} ++ ++/* Record ROC timeout and calculate backoff period */ ++static void mt7925_roc_record_timeout(struct mt792x_phy *phy) ++{ ++ unsigned int backoff_ms; ++ ++ phy->roc_last_timeout = jiffies; ++ phy->roc_timeout_count++; ++ ++ /* Exponential backoff: 100ms, 200ms, 400ms, 800ms, 1600ms (capped) */ ++ backoff_ms = MT7925_ROC_BACKOFF_BASE_MS << ++ min_t(u8, phy->roc_timeout_count - 1, 4); ++ if (backoff_ms > MT7925_ROC_BACKOFF_MAX_MS) ++ backoff_ms = MT7925_ROC_BACKOFF_MAX_MS; ++ ++ phy->roc_backoff_until = jiffies + msecs_to_jiffies(backoff_ms); ++ ++ /* Warn if we're seeing repeated timeouts - likely upper layer issue */ ++ if (phy->roc_timeout_count == MT7925_ROC_TIMEOUT_WARN_THRESH) ++ dev_warn(phy->dev->mt76.dev, ++ "mt7925: %u consecutive ROC timeouts, possible mac80211/wpa_supplicant issue (MLO key race?)\n", ++ phy->roc_timeout_count); ++} ++ ++/* Clear timeout tracking on successful ROC */ ++static void mt7925_roc_clear_timeout(struct mt792x_phy *phy) ++{ ++ phy->roc_timeout_count = 0; ++ phy->roc_backoff_until = 0; ++} ++ + static int mt7925_set_roc(struct mt792x_phy *phy, + struct mt792x_bss_conf *mconf, + struct ieee80211_channel *chan, + int duration, + enum mt7925_roc_req type) + { ++ unsigned long throttle; + int err; + ++ /* Check rate limiting - if in backoff period, wait or return busy */ ++ throttle = mt7925_roc_throttle_check(phy); ++ if (throttle) { ++ /* For short backoffs, wait; for longer ones, return busy */ ++ if (throttle < msecs_to_jiffies(200)) { ++ msleep(jiffies_to_msecs(throttle)); ++ } else { ++ dev_dbg(phy->dev->mt76.dev, ++ "mt7925: ROC throttled, %lu ms remaining\n", ++ jiffies_to_msecs(throttle)); ++ return -EBUSY; ++ } ++ } ++ ++ /* Clear any stale abort flag from previous ROC abort_async calls. ++ * If abort_async was called but roc_work never ran (timer was cancelled ++ * before firing), the abort flag would be stale and incorrectly abort ++ * this new ROC session. ++ */ ++ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); ++ ++ /* Cancel any pending roc_work from a previous async-aborted ROC. ++ * This prevents a race where stale work could abort our new ROC: ++ * 1. Previous ROC's roc_work clears ROC flag with test_and_clear ++ * 2. Work blocks waiting for mutex ++ * 3. abort_async called, sets abort flag ++ * 4. New ROC starts here, clears abort flag, sets ROC flag ++ * 5. Stale work gets mutex, calls mcu_abort_roc with NEW token ++ * Safe to call here since we don't hold the mutex yet. ++ */ ++ cancel_work_sync(&phy->roc_work); ++ + if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) + return -EBUSY; + +@@ -565,7 +659,11 @@ static int mt7925_set_roc(struct mt792x_ + if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { + mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); + clear_bit(MT76_STATE_ROC, &phy->mt76->state); ++ mt7925_roc_record_timeout(phy); + err = -ETIMEDOUT; ++ } else { ++ /* Successful ROC - reset timeout tracking */ ++ mt7925_roc_clear_timeout(phy); + } + + out: +@@ -576,8 +674,32 @@ static int mt7925_set_mlo_roc(struct mt7 + struct mt792x_bss_conf *mconf, + u16 sel_links) + { ++ unsigned long throttle; + int err; + ++ /* Check rate limiting - MLO ROC is especially prone to rapid-fire ++ * during reconnection cycles after MLO authentication failures. ++ */ ++ throttle = mt7925_roc_throttle_check(phy); ++ if (throttle) { ++ if (throttle < msecs_to_jiffies(200)) { ++ msleep(jiffies_to_msecs(throttle)); ++ } else { ++ dev_dbg(phy->dev->mt76.dev, ++ "mt7925: MLO ROC throttled, %lu ms remaining\n", ++ jiffies_to_msecs(throttle)); ++ return -EBUSY; ++ } ++ } ++ ++ /* Clear any stale abort flag from previous ROC abort_async calls */ ++ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); ++ ++ /* Cancel any pending roc_work from a previous async-aborted ROC. ++ * See comment in mt7925_set_roc for the race condition this prevents. ++ */ ++ cancel_work_sync(&phy->roc_work); ++ + if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) + return -EBUSY; + +@@ -592,7 +714,10 @@ static int mt7925_set_mlo_roc(struct mt7 + if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { + mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); + clear_bit(MT76_STATE_ROC, &phy->mt76->state); ++ mt7925_roc_record_timeout(phy); + err = -ETIMEDOUT; ++ } else { ++ mt7925_roc_clear_timeout(phy); + } + + out: +@@ -916,14 +1041,14 @@ static int mt7925_mac_link_sta_add(struc + if (!mlink) + return -EINVAL; + +- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); +- if (idx < 0) +- return -ENOSPC; +- + mconf = mt792x_vif_to_link(mvif, link_id); + if (!mconf) + return -EINVAL; + ++ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); ++ if (idx < 0) ++ return -ENOSPC; ++ + mt76_wcid_init(&mlink->wcid, 0); + mlink->wcid.sta = 1; + mlink->wcid.idx = idx; +--- a/mt792x.h ++++ b/mt792x.h +@@ -186,6 +186,13 @@ struct mt792x_phy { + wait_queue_head_t roc_wait; + u8 roc_token_id; + bool roc_grant; ++ ++ /* ROC rate limiting to prevent MCU overload during rapid reconnection ++ * cycles (e.g., MLO authentication failures causing repeated ROC). ++ */ ++ u8 roc_timeout_count; /* consecutive ROC timeouts */ ++ unsigned long roc_last_timeout; /* jiffies of last timeout */ ++ unsigned long roc_backoff_until;/* don't issue ROC until this time */ + }; + + struct mt792x_irq_map { diff --git a/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch b/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch new file mode 100644 index 000000000..8ed74863f --- /dev/null +++ b/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch @@ -0,0 +1,184 @@ +From 30c7e8a14f796c38176fe444e1d9af5900eed783 Mon Sep 17 00:00:00 2001 +From: Zac +Date: Mon, 19 Jan 2026 14:36:54 -0800 +Subject: [PATCH 22/24] wifi: mt76: mt7925: improve error handling and code + cleanup + +Address suggestions from code review: + +1. Remove redundant NULL check in mt7925_mcu_set_mlo_roc() + The check for links[i].mconf and links[i].chan at line 1375 was + redundant because the same check was already performed in the + initialization loop above. + +2. Add error logging for mt7925_mcu_add_bss_info() calls + Several call sites were not checking return values. While failures + in these paths often cannot be recovered from, logging helps with + debugging. Added dev_warn() logging in: + - beacon loss handler + - sta removal path + - link removal path + - stop_ap + - chanctx assign/unassign + +3. Add missing NULL check for mconf in link removal + mt792x_link_conf_to_mconf() can return NULL - add check before use. + +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 66 ++++++++++++++++++++++++++++++++++++++------------- + mt7925/mcu.c | 3 --- + 2 files changed, 49 insertions(+), 20 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -1248,11 +1248,17 @@ static void mt7925_mac_link_sta_assoc(st + + if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_bss_conf *mconf; ++ int ret; + + mconf = mt792x_link_conf_to_mconf(link_conf); +- if (mconf) +- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, +- link_conf, link_sta, true); ++ if (mconf) { ++ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, ++ link_conf, link_sta, true); ++ if (ret) ++ dev_warn(dev->mt76.dev, ++ "failed to update BSS info during beacon loss (ret=%d)\n", ++ ret); ++ } + } + + ewma_avg_signal_init(&mlink->avg_ack_signal); +@@ -1320,16 +1326,21 @@ static void mt7925_mac_link_sta_remove(s + + if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_bss_conf *mconf; ++ int ret; + + mconf = mt792x_link_conf_to_mconf(link_conf); + if (!mconf) + goto out; + +- if (ieee80211_vif_is_mld(vif)) ++ if (ieee80211_vif_is_mld(vif)) { + mt792x_mac_link_bss_remove(dev, mconf, mlink); +- else +- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, +- link_sta, false); ++ } else { ++ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, ++ link_conf, link_sta, false); ++ if (ret) ++ dev_warn(dev->mt76.dev, ++ "failed to remove BSS info (ret=%d)\n", ret); ++ } + } + out: + +@@ -1349,6 +1360,7 @@ mt7925_mac_sta_remove_links(struct mt792 + struct mt76_dev *mdev = &dev->mt76; + struct mt76_wcid *wcid; + unsigned int link_id; ++ int ret; + + /* clean up bss before starec */ + for_each_set_bit(link_id, &old_links, IEEE80211_MLD_MAX_NUM_LINKS) { +@@ -1373,9 +1385,14 @@ mt7925_mac_sta_remove_links(struct mt792 + continue; + + mconf = mt792x_link_conf_to_mconf(link_conf); ++ if (!mconf) ++ continue; + +- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, +- link_sta, false); ++ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, ++ link_conf, link_sta, false); ++ if (ret) ++ dev_warn(dev->mt76.dev, ++ "failed to remove link BSS info (ret=%d)\n", ret); + } + + for_each_set_bit(link_id, &old_links, IEEE80211_MLD_MAX_NUM_LINKS) { +@@ -1985,8 +2002,11 @@ mt7925_stop_ap(struct ieee80211_hw *hw, + if (err) + goto out; + +- mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, link_conf, +- NULL, false); ++ err = mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, ++ link_conf, NULL, false); ++ if (err) ++ dev_warn(dev->mt76.dev, ++ "failed to remove BSS info in stop_ap (ret=%d)\n", err); + + out: + mt792x_mutex_release(dev); +@@ -2357,6 +2377,7 @@ static int mt7925_assign_vif_chanctx(str + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct ieee80211_bss_conf *pri_link_conf; + struct mt792x_bss_conf *mconf; ++ int ret; + + mutex_lock(&dev->mt76.mutex); + +@@ -2370,9 +2391,14 @@ static int mt7925_assign_vif_chanctx(str + pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); + + if (pri_link_conf && vif->type == NL80211_IFTYPE_STATION && +- mconf == &mvif->bss_conf) +- mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf, +- NULL, true); ++ mconf == &mvif->bss_conf) { ++ ret = mt7925_mcu_add_bss_info(&dev->phy, NULL, ++ pri_link_conf, NULL, true); ++ if (ret) ++ dev_warn(dev->mt76.dev, ++ "failed to add BSS info in chanctx assign (ret=%d)\n", ++ ret); ++ } + } else { + mconf = &mvif->bss_conf; + } +@@ -2393,6 +2419,7 @@ static void mt7925_unassign_vif_chanctx( + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; ++ int ret; + + mutex_lock(&dev->mt76.mutex); + +@@ -2404,9 +2431,14 @@ static void mt7925_unassign_vif_chanctx( + } + + if (vif->type == NL80211_IFTYPE_STATION && +- mconf == &mvif->bss_conf) +- mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, +- NULL, false); ++ mconf == &mvif->bss_conf) { ++ ret = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, ++ NULL, false); ++ if (ret) ++ dev_warn(dev->mt76.dev, ++ "failed to remove BSS info in chanctx unassign (ret=%d)\n", ++ ret); ++ } + } else { + mconf = &mvif->bss_conf; + } +--- a/mt7925/mcu.c ++++ b/mt7925/mcu.c +@@ -1377,9 +1377,6 @@ int mt7925_mcu_set_mlo_roc(struct mt792x + type = MT7925_ROC_REQ_JOIN; + + for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) { +- if (!links[i].mconf || !links[i].chan) +- return -ENOLINK; +- + chan = links[i].chan; + center_ch = ieee80211_frequency_to_channel(chan->center_freq); + req.roc[i].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)); diff --git a/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch b/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch new file mode 100644 index 000000000..b23613d77 --- /dev/null +++ b/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch @@ -0,0 +1,169 @@ +From e4c4a356794090e0a5b2dec0a5b8b40c80e60d84 Mon Sep 17 00:00:00 2001 +From: Zac +Date: Mon, 19 Jan 2026 15:00:33 -0800 +Subject: [PATCH 23/24] wifi: mt76: mt7925: fix deadlock and WCID leak bugs + +Fix two bugs identified by code review: + +1. Potential deadlock in ROC path: + cancel_work_sync() was called inside mt7925_set_roc() and + mt7925_set_mlo_roc() while the mutex was already held by the + caller (e.g., mt7925_remain_on_channel). If roc_work was waiting + for the mutex, this would deadlock. Move cancel_work_sync() to + callers, before they acquire the mutex. + +2. WCID resource leak in mt7925_mac_link_sta_add: + After WCID allocation and registration (rcu_assign_pointer), + multiple error paths returned without cleaning up the WCID index. + This could exhaust the WCID table over time. Add proper error + cleanup path that clears the wcid pointer and frees the index. + +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 59 +++++++++++++++++++++++++++++---------------------- + 1 file changed, 34 insertions(+), 25 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -630,20 +630,12 @@ static int mt7925_set_roc(struct mt792x_ + * If abort_async was called but roc_work never ran (timer was cancelled + * before firing), the abort flag would be stale and incorrectly abort + * this new ROC session. ++ * ++ * Note: cancel_work_sync must be called by our callers BEFORE they ++ * acquire the mutex, to prevent deadlock. See mt7925_remain_on_channel. + */ + clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); + +- /* Cancel any pending roc_work from a previous async-aborted ROC. +- * This prevents a race where stale work could abort our new ROC: +- * 1. Previous ROC's roc_work clears ROC flag with test_and_clear +- * 2. Work blocks waiting for mutex +- * 3. abort_async called, sets abort flag +- * 4. New ROC starts here, clears abort flag, sets ROC flag +- * 5. Stale work gets mutex, calls mcu_abort_roc with NEW token +- * Safe to call here since we don't hold the mutex yet. +- */ +- cancel_work_sync(&phy->roc_work); +- + if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) + return -EBUSY; + +@@ -692,13 +684,11 @@ static int mt7925_set_mlo_roc(struct mt7 + } + } + +- /* Clear any stale abort flag from previous ROC abort_async calls */ +- clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); +- +- /* Cancel any pending roc_work from a previous async-aborted ROC. +- * See comment in mt7925_set_roc for the race condition this prevents. ++ /* Clear any stale abort flag from previous ROC abort_async calls. ++ * Note: cancel_work_sync must be called by our callers BEFORE they ++ * acquire the mutex, to prevent deadlock. + */ +- cancel_work_sync(&phy->roc_work); ++ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); + + if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) + return -EBUSY; +@@ -734,6 +724,11 @@ static int mt7925_remain_on_channel(stru + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int err; + ++ /* Cancel any pending ROC work BEFORE acquiring mutex to prevent ++ * deadlock. The work may be waiting for mutex we're about to take. ++ */ ++ cancel_work_sync(&phy->roc_work); ++ + mt792x_mutex_acquire(phy->dev); + err = mt7925_set_roc(phy, &mvif->bss_conf, + chan, duration, MT7925_ROC_REQ_ROC); +@@ -1068,14 +1063,16 @@ static int mt7925_mac_link_sta_add(struc + + ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); + if (ret) +- return ret; ++ goto err_wcid; + + mt7925_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + link_conf = mt792x_vif_to_bss_conf(vif, link_id); +- if (!link_conf) +- return -EINVAL; ++ if (!link_conf) { ++ ret = -EINVAL; ++ goto err_wcid; ++ } + + /* should update bss info before STA add */ + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { +@@ -1087,7 +1084,7 @@ static int mt7925_mac_link_sta_add(struc + ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, + link_conf, link_sta, false); + if (ret) +- return ret; ++ goto err_wcid; + } + + if (ieee80211_vif_is_mld(vif) && +@@ -1095,28 +1092,33 @@ static int mt7925_mac_link_sta_add(struc + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_NONE); + if (ret) +- return ret; ++ goto err_wcid; + } else if (ieee80211_vif_is_mld(vif) && + link_sta != mlink->pri_link) { + ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, + true, MT76_STA_INFO_STATE_ASSOC); + if (ret) +- return ret; ++ goto err_wcid; + + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_ASSOC); + if (ret) +- return ret; ++ goto err_wcid; + } else { + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_NONE); + if (ret) +- return ret; ++ goto err_wcid; + } + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + + return 0; ++ ++err_wcid: ++ rcu_assign_pointer(dev->mt76.wcid[idx], NULL); ++ mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx); ++ return ret; + } + + static int +@@ -2096,6 +2098,8 @@ static void mt7925_mgd_prepare_tx(struct + u16 duration = info->duration ? info->duration : + jiffies_to_msecs(HZ); + ++ cancel_work_sync(&mvif->phy->roc_work); ++ + mt792x_mutex_acquire(dev); + mt7925_set_roc(mvif->phy, &mvif->bss_conf, + mvif->bss_conf.mt76.ctx->def.chan, duration, +@@ -2244,6 +2248,11 @@ mt7925_change_vif_links(struct ieee80211 + if (old_links == new_links) + return 0; + ++ /* Cancel any pending ROC work before acquiring mutex to prevent ++ * deadlock if mt7925_set_mlo_roc is called below. ++ */ ++ cancel_work_sync(&phy->roc_work); ++ + mt792x_mutex_acquire(dev); + + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { diff --git a/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch b/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch new file mode 100644 index 000000000..4a1420290 --- /dev/null +++ b/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch @@ -0,0 +1,147 @@ +From a43924caa7a783b4371a03f8d663903015dfb2b1 Mon Sep 17 00:00:00 2001 +From: Zac +Date: Mon, 19 Jan 2026 15:29:29 -0800 +Subject: [PATCH 24/24] wifi: mt76: mt7925: fix race condition in async ROC + abort + +Fix multiple issues in the async ROC abort mechanism: + +1. Schedule roc_work after setting abort flag and deleting timer. + If the timer hasn't fired yet, roc_work would never be scheduled + and MT76_STATE_ROC would remain set permanently, causing future + ROC attempts to fail with -EBUSY. + +2. Remove the clear_bit(MT76_STATE_ROC) call to fix a race where + mac80211 might not receive the ROC expiry notification. + +3. Add missing power_save_sched call in WCID error cleanup path + to balance the pm_wake call and prevent power state imbalance. + +Also clean up verbose intermediate comments throughout ROC code. + +Reported-by: Cursor Bot (code review) +Reported-by: GitHub Copilot (code review) +Signed-off-by: Zac Bowling +--- + mt7925/main.c | 55 ++++++++++----------------------------------------- + 1 file changed, 10 insertions(+), 45 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -465,19 +465,14 @@ static void mt7925_roc_abort_async(struc + { + struct mt792x_phy *phy = &dev->phy; + +- /* Set abort flag first - roc_work checks this before acquiring mutex */ ++ /* Set abort flag - roc_work checks this before acquiring mutex */ + set_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); + +- /* Clear ROC state */ +- clear_bit(MT76_STATE_ROC, &phy->mt76->state); +- +- /* Stop the timer - use non-sync version to avoid blocking */ +- timer_delete(&phy->roc_timer); +- +- /* Do NOT call cancel_work_sync here - that would deadlock if +- * roc_work is waiting for mutex that we (caller) already hold. +- * The work will see the abort flag and clean up gracefully. ++ /* Stop timer and schedule work to handle cleanup. ++ * Must schedule work since timer may not have fired yet. + */ ++ timer_delete(&phy->roc_timer); ++ ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); + } + + void mt7925_roc_abort_sync(struct mt792x_dev *dev) +@@ -626,14 +621,7 @@ static int mt7925_set_roc(struct mt792x_ + } + } + +- /* Clear any stale abort flag from previous ROC abort_async calls. +- * If abort_async was called but roc_work never ran (timer was cancelled +- * before firing), the abort flag would be stale and incorrectly abort +- * this new ROC session. +- * +- * Note: cancel_work_sync must be called by our callers BEFORE they +- * acquire the mutex, to prevent deadlock. See mt7925_remain_on_channel. +- */ ++ /* Clear stale abort flag from previous ROC */ + clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); + + if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) +@@ -684,10 +672,7 @@ static int mt7925_set_mlo_roc(struct mt7 + } + } + +- /* Clear any stale abort flag from previous ROC abort_async calls. +- * Note: cancel_work_sync must be called by our callers BEFORE they +- * acquire the mutex, to prevent deadlock. +- */ ++ /* Clear stale abort flag from previous ROC */ + clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); + + if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) +@@ -724,11 +709,7 @@ static int mt7925_remain_on_channel(stru + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int err; + +- /* Cancel any pending ROC work BEFORE acquiring mutex to prevent +- * deadlock. The work may be waiting for mutex we're about to take. +- */ + cancel_work_sync(&phy->roc_work); +- + mt792x_mutex_acquire(phy->dev); + err = mt7925_set_roc(phy, &mvif->bss_conf, + chan, duration, MT7925_ROC_REQ_ROC); +@@ -1118,6 +1099,7 @@ static int mt7925_mac_link_sta_add(struc + err_wcid: + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx); ++ mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + return ret; + } + +@@ -1310,10 +1292,7 @@ static void mt7925_mac_link_sta_remove(s + if (!mlink) + return; + +- /* Use async abort to prevent deadlock - this function is called from +- * mt76_sta_remove() which already holds dev->mt76.mutex. Using the +- * sync version would deadlock if roc_work is waiting for the same mutex. +- */ ++ /* Async abort - caller already holds mutex */ + mt7925_roc_abort_async(dev); + + mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); +@@ -1728,18 +1707,8 @@ static int mt7925_suspend(struct ieee802 + cancel_delayed_work_sync(&dev->pm.ps_work); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + +- /* Cancel ROC timer and work before mac80211 finishes quiescing. +- * This must happen here, not in pci_suspend, because mac80211 +- * sets quiescing=true before calling this callback. If the ROC +- * timer fires after quiescing starts, ieee80211_queue_work() will +- * fail and leave the driver in an inconsistent state. +- * +- * IMPORTANT: Must be called BEFORE mutex_acquire to avoid deadlock. +- * If roc_work is running and waiting for mutex, cancel_work_sync +- * would block forever if we already hold the mutex. +- */ ++ /* Cancel ROC before quiescing starts */ + mt7925_roc_abort_sync(dev); +- + mt792x_mutex_acquire(dev); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); +@@ -2248,11 +2217,7 @@ mt7925_change_vif_links(struct ieee80211 + if (old_links == new_links) + return 0; + +- /* Cancel any pending ROC work before acquiring mutex to prevent +- * deadlock if mt7925_set_mlo_roc is called below. +- */ + cancel_work_sync(&phy->roc_work); +- + mt792x_mutex_acquire(dev); + + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { diff --git a/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch b/openwrt/patch/mt76/patches/100-fix-build-with-linux-6.12rc2.patch similarity index 100% rename from openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch rename to openwrt/patch/mt76/patches/100-fix-build-with-linux-6.12rc2.patch diff --git a/openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch b/openwrt/patch/mt76/patches/102-use-hrtimer_setup-in-mt76x02u-beacon-init.patch similarity index 100% rename from openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch rename to openwrt/patch/mt76/patches/102-use-hrtimer_setup-in-mt76x02u-beacon-init.patch diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index f42f9dc60..ae9de6117 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -156,8 +156,34 @@ git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile -curl -s $mirror/openwrt/patch/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch > package/kernel/mt76/patches/002-use-hrtimer_setup-in-mt76x02u-beacon-init.patch -curl -s $mirror/openwrt/patch/mt76/patches/101-fix-build-with-linux-6.12rc2.patch > package/kernel/mt76/patches/101-fix-build-with-linux-6.12rc2.patch +pushd package/kernel/mt76/patches + curl -Os $mirror/openwrt/patch/mt76/patches/100-fix-build-with-linux-6.12rc2.patch + curl -Os $mirror/openwrt/patch/mt76/patches/102-use-hrtimer_setup-in-mt76x02u-beacon-init.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch + curl -Os $mirror/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch +popd # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch From 0d6243af17e598d3b6048ef70c5653176b15fb6e Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 3 Mar 2026 11:13:05 +0800 Subject: [PATCH 370/425] config: add kmod-tun & ip-full pkgs Signed-off-by: sbwml --- openwrt/25-config-common | 2 ++ openwrt/25-config-std-common | 1 + 2 files changed, 3 insertions(+) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index 1d0cd4413..458e510d4 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -173,6 +173,7 @@ CONFIG_PACKAGE_kmod-br-netfilter=y CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y +CONFIG_PACKAGE_kmod-tun=y CONFIG_PACKAGE_kmod-fs-exfat=y CONFIG_PACKAGE_kmod-fs-f2fs=y CONFIG_PACKAGE_kmod-fs-ntfs3=y @@ -229,6 +230,7 @@ CONFIG_PACKAGE_ftp=y CONFIG_PACKAGE_gdisk=y CONFIG_PACKAGE_htop=y CONFIG_PACKAGE_iperf3=y +CONFIG_PACKAGE_ip-full=y CONFIG_PACKAGE_iputils-ping=y CONFIG_PACKAGE_lrzsz=y CONFIG_PACKAGE_lsblk=y diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index 925a93d5f..87ff29360 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -191,6 +191,7 @@ CONFIG_PACKAGE_ftp=y CONFIG_PACKAGE_gdisk=y CONFIG_PACKAGE_htop=y CONFIG_PACKAGE_iperf3=y +CONFIG_PACKAGE_ip-full=y CONFIG_PACKAGE_iputils-ping=y CONFIG_PACKAGE_lrzsz=y CONFIG_PACKAGE_lsblk=y From 083928477c109092c15e16fc9d8621b97559db5d Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 3 Mar 2026 11:13:44 +0800 Subject: [PATCH 371/425] linux-6.18: bump to 6.18.15 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 2d909eb44..61180cebd 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .14 -LINUX_KERNEL_HASH-6.18.14 = 8d1934a72a185f1be6b56e3ad8ea31fd9a381ffec0346c69f06c90d776da7cb8 +LINUX_VERSION-6.18 = .15 +LINUX_KERNEL_HASH-6.18.15 = 7c716216c3c4134ed0de69195701e677577bbcdd3979f331c182acd06bf2f170 From ebcd075991376c14c667ddcd5b24e09d94908d5d Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 7 Mar 2026 18:08:48 +0800 Subject: [PATCH 372/425] OpenWrt v25.12.0 Signed-off-by: sbwml --- openwrt/25-config-common | 2 - openwrt/files/etc/hotplug.d/block/20-usbreset | 24 -- ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 12 +- ...-app-firewall-add-shortcut-fe-option.patch | 16 +- ...uci-app-firewall-add-ipv6-nat-option.patch | 12 +- ...firewall-add-custom-nft-rule-support.patch | 20 +- ...firewall-add-natflow-offload-support.patch | 20 +- ...l-enable-hardware-offload-only-on-de.patch | 10 +- ...l-add-fullcone6-option-for-nftables-.patch | 10 +- ...m-add-modal-overlay-dialog-to-reboot.patch | 4 +- ...displays-actual-process-memory-usage.patch | 4 +- ...storage-index-applicable-only-to-val.patch | 4 +- ...firewall-disable-legacy-firewall-rul.patch | 17 +- ...-system-add-refresh-interval-setting.patch | 8 +- ...mounts-add-docker-directory-mount-po.patch | 6 +- ...add-ucitrack-luci-mod-system-zram.js.patch | 4 +- .../001-luci-app-frpc-hide-token.patch | 2 +- .../002-luci-app-frpc-add-enable-flag.patch | 4 +- ...-manager-support-installing-uploaded.patch | 10 +- openwrt/patch/openwrt-6.x/modules/block.mk | 2 +- openwrt/patch/openwrt-6.x/modules/crypto.mk | 262 ++---------------- openwrt/patch/openwrt-6.x/modules/fs.mk | 5 +- openwrt/patch/openwrt-6.x/modules/hwmon.mk | 34 +++ openwrt/patch/openwrt-6.x/modules/iio.mk | 6 +- openwrt/patch/openwrt-6.x/modules/lib.mk | 2 + .../patch/openwrt-6.x/modules/netdevices.mk | 11 +- .../patch/openwrt-6.x/modules/netfilter.mk | 4 +- .../patch/openwrt-6.x/modules/netsupport.mk | 90 +++++- openwrt/patch/openwrt-6.x/modules/other.mk | 27 +- openwrt/patch/openwrt-6.x/modules/usb.mk | 21 +- openwrt/patch/openwrt-6.x/modules/video.mk | 24 +- openwrt/scripts/00-prepare_base.sh | 7 - tags/v25 | 2 +- 33 files changed, 302 insertions(+), 384 deletions(-) delete mode 100644 openwrt/files/etc/hotplug.d/block/20-usbreset diff --git a/openwrt/25-config-common b/openwrt/25-config-common index 458e510d4..8edaeba7b 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -44,8 +44,6 @@ CONFIG_DOCKER_OPTIONAL_FEATURES=y CONFIG_DOCKER_STO_BTRFS=y CONFIG_DOCKER_STO_EXT4=y CONFIG_PACKAGE_luci-app-dockerman=y -CONFIG_PACKAGE_luci-lib-docker=y -# CONFIG_PACKAGE_cgroupfs-mount is not set ### Luci CONFIG_PACKAGE_luci=y diff --git a/openwrt/files/etc/hotplug.d/block/20-usbreset b/openwrt/files/etc/hotplug.d/block/20-usbreset deleted file mode 100644 index f7a051dfa..000000000 --- a/openwrt/files/etc/hotplug.d/block/20-usbreset +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -device=`basename $DEVPATH` - -case $device in - mtdblock*|ubiblock*|zram*) - exit 0 - ;; -esac - -case "$ACTION" in - add) - mkdir -p /usb/$device - mount -o rw,noatime,discard /dev/$device /usb/$device - if [ -f "/usb/$device/recovery.txt" ]; then - echo y | firstboot - sleep 2 - reboot - else - umount -l /usb/$device - rm -rf /usb - fi - ;; -esac diff --git a/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch index ac61cf2b1..f7be1f925 100644 --- a/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch +++ b/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch @@ -1,7 +1,7 @@ -From 314fbe82b79b19499507ec5e8043a4b32c9885a8 Mon Sep 17 00:00:00 2001 +From 0cfeaf969c9b000f6de383d111b8b923d6d05fed Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 03:35:05 +0800 -Subject: [PATCH 1/6] luci-app-firewall: add nft-fullcone and bcm-fullcone +Subject: [PATCH 1/7] luci-app-firewall: add nft-fullcone and bcm-fullcone option Signed-off-by: sbwml @@ -10,10 +10,10 @@ Signed-off-by: sbwml 1 file changed, 21 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 41b9834..b41ebae 100644 +index 129d290e5c..4675a44efd 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -58,6 +58,27 @@ return view.extend({ +@@ -56,6 +56,27 @@ return view.extend({ o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets')); @@ -38,9 +38,9 @@ index 41b9834..b41ebae 100644 + }; + } + - var p = [ + let p = [ s.option(form.ListValue, 'input', _('Input')), s.option(form.ListValue, 'output', _('Output')), -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch index 68cdcad6b..e32fc6a53 100644 --- a/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch +++ b/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch @@ -1,7 +1,7 @@ -From 23efb4fefdc8acf49623b67b93079f79b3594b69 Mon Sep 17 00:00:00 2001 +From 76323fe8dfaf8b241a36b22056781fcdf6f449cc Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 17:40:35 +0800 -Subject: [PATCH 2/6] luci-app-firewall: add shortcut-fe option +Subject: [PATCH 2/7] luci-app-firewall: add shortcut-fe option Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index b41ebae..12626c5 100644 +index 4675a44efd..98334c9165 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -104,18 +104,39 @@ return view.extend({ +@@ -102,18 +102,39 @@ return view.extend({ o.value('0', _("None")); o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); o.value('2', _("Hardware flow offloading"), _('Hardware based offloading for routing with/without NAT.') + ' ' + _(' Requires hardware NAT support.')); @@ -21,12 +21,12 @@ index b41ebae..12626c5 100644 + } o.optional = false; o.load = function (section_id) { - var flow_offloading = uci.get('firewall', section_id, 'flow_offloading'); - var flow_offloading_hw = uci.get('firewall', section_id, 'flow_offloading_hw'); + const flow_offloading = uci.get('firewall', section_id, 'flow_offloading'); + const flow_offloading_hw = uci.get('firewall', section_id, 'flow_offloading_hw'); - return (flow_offloading === '1') - ? (flow_offloading_hw === '1' ? '2' : '1') - : '0'; -+ var shortcut_fe = uci.get('firewall', section_id, 'shortcut_fe'); ++ const shortcut_fe = uci.get('firewall', section_id, 'shortcut_fe'); + if (flow_offloading === '1') { + return flow_offloading_hw === '1' ? '2' : '1'; + } else { @@ -56,5 +56,5 @@ index b41ebae..12626c5 100644 -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch index 14ceec8c7..842e2b652 100644 --- a/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch +++ b/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch @@ -1,7 +1,7 @@ -From fdf42e33bb356f2cf86edc42926f508a1c74624d Mon Sep 17 00:00:00 2001 +From 4e4415c040b8405121be9cc7d25e6e252dbb6316 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 03:37:02 +0800 -Subject: [PATCH 3/6] luci-app-firewall: add ipv6 nat option +Subject: [PATCH 3/7] luci-app-firewall: add ipv6 nat option Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 6 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 12626c5..a1fb06d 100644 +index 98334c9165..8417eb2bdc 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -79,6 +79,12 @@ return view.extend({ +@@ -77,6 +77,12 @@ return view.extend({ }; } @@ -22,9 +22,9 @@ index 12626c5..a1fb06d 100644 + _('Applicable to internet environments where the router is not assigned an IPv6 prefix, such as when using an upstream optical modem for dial-up.')); + }; + - var p = [ + let p = [ s.option(form.ListValue, 'input', _('Input')), s.option(form.ListValue, 'output', _('Output')), -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch index 858e9da34..4394e76bb 100644 --- a/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch +++ b/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch @@ -1,7 +1,7 @@ -From 523ec5d7928c348370e9de52adc6d14e5a13c63f Mon Sep 17 00:00:00 2001 +From a7812445e8f7dbf63c04996ed35dbb4869de26a7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Sep 2024 12:36:11 +0800 -Subject: [PATCH 4/6] luci-add-firewall: add custom nft rule support +Subject: [PATCH 4/7] luci-add-firewall: add custom nft rule support Signed-off-by: sbwml --- @@ -11,19 +11,19 @@ Signed-off-by: sbwml 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js -index 1997a72..b3183d6 100644 +index b273db4704..9bb4d3affa 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js @@ -5,13 +5,13 @@ return view.extend({ - load: function() { + load() { - return L.resolveDefault(fs.read('/etc/firewall.user'), ''); + return L.resolveDefault(fs.read('/etc/firewall4.user'), ''); }, - handleSave: function(ev) { - var value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n'; + handleSave(ev) { + const value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n'; - return fs.write('/etc/firewall.user', value).then(function(rc) { + return fs.write('/etc/firewall4.user', value).then(function(rc) { @@ -31,7 +31,7 @@ index 1997a72..b3183d6 100644 ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'); fs.exec('/etc/init.d/firewall', ['restart']); @@ -23,7 +23,7 @@ return view.extend({ - render: function(fwuser) { + render(fwuser) { return E([ E('h2', _('Firewall - Custom Rules')), - E('p', {}, _('Custom rules allow you to execute arbitrary iptables commands which are not otherwise covered by the firewall framework. The commands are executed after each firewall restart, right after the default ruleset has been loaded.')), @@ -40,7 +40,7 @@ index 1997a72..b3183d6 100644 ]); }, diff --git a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json -index f024dcf..8aea702 100644 +index f024dcfe25..8aea702c53 100644 --- a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json +++ b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json @@ -64,9 +64,6 @@ @@ -54,7 +54,7 @@ index f024dcf..8aea702 100644 } } diff --git a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json -index 17d1fba..7e06de7 100644 +index 17d1fbab12..7e06de7022 100644 --- a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json +++ b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json @@ -3,7 +3,8 @@ @@ -78,5 +78,5 @@ index 17d1fba..7e06de7 100644 "ubus": { "file": [ "write" ] -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch index ab56b1827..b1adce45f 100644 --- a/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch +++ b/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch @@ -1,7 +1,7 @@ -From 880db92c404fb4842fa31439c174224da4fd245d Mon Sep 17 00:00:00 2001 +From e19842ac20e07e2031558daa8c6d3c1811441b57 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 17:58:57 +0800 -Subject: [PATCH 5/6] luci-app-firewall: add natflow offload support +Subject: [PATCH 5/7] luci-app-firewall: add natflow offload support Signed-off-by: sbwml --- @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index a1fb06d..447c42b 100644 +index 8417eb2bdc..5ad81a4530 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -113,25 +113,38 @@ return view.extend({ +@@ -111,25 +111,38 @@ return view.extend({ if (L.hasSystemFeature('shortcutfe')) { o.value('3', _("Shortcut-FE flow offloading"), _('Shortcut-FE based offloading for routing/NAT')); } @@ -21,10 +21,10 @@ index a1fb06d..447c42b 100644 + } o.optional = false; o.load = function (section_id) { - var flow_offloading = uci.get('firewall', section_id, 'flow_offloading'); - var flow_offloading_hw = uci.get('firewall', section_id, 'flow_offloading_hw'); - var shortcut_fe = uci.get('firewall', section_id, 'shortcut_fe'); -+ var natflow = uci.get('firewall', section_id, 'natflow'); + const flow_offloading = uci.get('firewall', section_id, 'flow_offloading'); + const flow_offloading_hw = uci.get('firewall', section_id, 'flow_offloading_hw'); + const shortcut_fe = uci.get('firewall', section_id, 'shortcut_fe'); ++ const natflow = uci.get('firewall', section_id, 'natflow'); if (flow_offloading === '1') { return flow_offloading_hw === '1' ? '2' : '1'; - } else { @@ -52,7 +52,7 @@ index a1fb06d..447c42b 100644 } }; -@@ -143,6 +156,14 @@ return view.extend({ +@@ -141,6 +154,14 @@ return view.extend({ o.value('fast-classifier', _('fast-classifier')); o.default = 'shortcut-fe-cm'; o.depends('offloading_type', '3'); @@ -68,5 +68,5 @@ index a1fb06d..447c42b 100644 -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch b/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch index 32a0fc54b..ece9047b0 100644 --- a/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch +++ b/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch @@ -1,7 +1,7 @@ -From 8fd15c7ea624ba143176caeca61fd34cbbb6a195 Mon Sep 17 00:00:00 2001 +From 18fa3af2cf740557475bfcbdfd6a5aa909724b8a Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 21:04:10 +0800 -Subject: [PATCH 6/6] luci-app-firewall: enable hardware offload only on +Subject: [PATCH 6/7] luci-app-firewall: enable hardware offload only on devices with `offload_hw` system feature Signed-off-by: sbwml @@ -10,10 +10,10 @@ Signed-off-by: sbwml 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 447c42b..a527abb 100644 +index 5ad81a4530..df2f6d69a8 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -109,7 +109,9 @@ return view.extend({ +@@ -107,7 +107,9 @@ return view.extend({ o = s.option(form.RichListValue, "offloading_type", _("Flow offloading type")); o.value('0', _("None")); o.value('1', _("Software flow offloading"), _('Software based offloading for routing/NAT.')); @@ -25,5 +25,5 @@ index 447c42b..a527abb 100644 o.value('3', _("Shortcut-FE flow offloading"), _('Shortcut-FE based offloading for routing/NAT')); } -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch b/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch index 0fb3ac273..4e40aa565 100644 --- a/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch +++ b/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch @@ -1,8 +1,8 @@ -From 6d3223164d85f83b7568e0859e4cdcbbb7136f6c Mon Sep 17 00:00:00 2001 +From ff0f5e454d80e392f2985071ad9c0a3fd2fa01c6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 18 Dec 2024 23:38:26 +0800 -Subject: [PATCH] luci-app-firewall: add fullcone6 option for nftables based - fullcone +Subject: [PATCH 7/7] luci-app-firewall: add fullcone6 option for nftables + based fullcone Signed-off-by: sbwml --- @@ -10,10 +10,10 @@ Signed-off-by: sbwml 1 file changed, 19 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 3fe1065..37dfaf2 100644 +index df2f6d69a8..0a1646594d 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -77,6 +77,25 @@ return view.extend({ +@@ -75,6 +75,25 @@ return view.extend({ uci.set('firewall', section_id, 'fullcone', value === '0' ? null : '1'); uci.set('firewall', section_id, 'brcmfullcone', value === '2' ? '1' : null); }; diff --git a/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch b/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch index 0d9a9e532..44f6cd2c4 100644 --- a/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch +++ b/openwrt/patch/luci/0001-luci-mod-system-add-modal-overlay-dialog-to-reboot.patch @@ -1,4 +1,4 @@ -From d6e535bd88ef6c10500e60acb83f74b37a42a9f5 Mon Sep 17 00:00:00 2001 +From b5ae515838777322a9b6c76d1397b71403802514 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 19:36:44 +0800 Subject: [PATCH 1/7] luci-mod-system: add modal overlay dialog to reboot @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js -index 92e1dd4..c106f78 100644 +index 92e1dd4920..c106f781aa 100644 --- a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js +++ b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/reboot.js @@ -30,7 +30,26 @@ return view.extend({ diff --git a/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch index 5a86aaf07..496b7cf14 100644 --- a/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch +++ b/openwrt/patch/luci/0002-luci-mod-status-displays-actual-process-memory-usage.patch @@ -1,4 +1,4 @@ -From 673317998a908c133f7f677fa985b854d182e96a Mon Sep 17 00:00:00 2001 +From 6e22a4543779366d6c4c6fd5be92ba668d25870c Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 19:43:19 +0800 Subject: [PATCH 2/7] luci-mod-status: displays actual process memory usage @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js -index 0a885c0..56ac7c4 100644 +index 0a885c01c9..56ac7c4ac0 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/20_memory.js @@ -32,8 +32,8 @@ return baseclass.extend({ diff --git a/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch b/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch index 3e2213395..5e789213d 100644 --- a/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch +++ b/openwrt/patch/luci/0003-luci-mod-status-storage-index-applicable-only-to-val.patch @@ -1,4 +1,4 @@ -From a2ce3356bd451a51e241361e56f0b9ff7349273a Mon Sep 17 00:00:00 2001 +From 6c7f86e77b7f0659d19bea26bede8a05f1575197 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 24 Mar 2024 00:12:45 +0800 Subject: [PATCH 3/7] luci-mod-status: storage index applicable only to valid @@ -10,7 +10,7 @@ Signed-off-by: sbwml 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js -index 60661f6..aac6711 100644 +index 60661f63e5..aac6711ed3 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/25_storage.js @@ -13,12 +13,14 @@ var callMountPoints = rpc.declare({ diff --git a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch index caeea8674..d12537083 100644 --- a/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch +++ b/openwrt/patch/luci/0004-luci-mod-status-firewall-disable-legacy-firewall-rul.patch @@ -1,4 +1,4 @@ -From b8114ae5032c4f73994074326c0db004795bb0aa Mon Sep 17 00:00:00 2001 +From b0b925497f0e583e765992d18992b7dae3826b30 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 19:44:52 +0800 Subject: [PATCH 4/7] luci-mod-status: firewall: disable legacy firewall rule @@ -11,14 +11,14 @@ Signed-off-by: sbwml 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -index 40f7f71..38a0d24 100644 +index 682c29f872..1ebc17bfbd 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/nftables.js -@@ -773,26 +773,12 @@ return view.extend({ +@@ -773,23 +773,9 @@ return view.extend({ return node; }, -- checkLegacyRules: function(ipt4save, ipt6save) { +- checkLegacyRules(ipt4save, ipt6save) { - if (ipt4save.match(/\n-A /) || ipt6save.match(/\n-A /)) { - ui.addNotification(_('Legacy rules detected'), [ - E('p', _('There are legacy iptables rules present on the system. Mixing iptables and nftables rules is discouraged and may lead to incomplete traffic filtering.')), @@ -30,11 +30,8 @@ index 40f7f71..38a0d24 100644 - } - }, - - render: function(data) { - var view = E('div'), - nft = data[0], - ipt = data[1], - ipt6 = data[2]; + render([nft, ipt, ipt6]) { + const view = E('div'); - this.checkLegacyRules(ipt, ipt6); - @@ -42,7 +39,7 @@ index 40f7f71..38a0d24 100644 return E('em', _('No nftables ruleset loaded.')); diff --git a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json -index 23e8bdb..5ba794e 100644 +index 23e8bdb61d..5ba794e8fd 100644 --- a/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json +++ b/modules/luci-mod-status/root/usr/share/luci/menu.d/luci-mod-status.json @@ -60,23 +60,39 @@ diff --git a/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch b/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch index ff29c5261..299067fa7 100644 --- a/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch +++ b/openwrt/patch/luci/0005-luci-mod-system-add-refresh-interval-setting.patch @@ -1,4 +1,4 @@ -From 3d6420303179fbb13ed565aa816908a632303309 Mon Sep 17 00:00:00 2001 +From c061bab058aabf2bc68b0592d7194b7fc128e6e9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 13 Sep 2024 19:47:13 +0800 Subject: [PATCH 5/7] luci-mod-system: add refresh interval setting @@ -9,12 +9,12 @@ Signed-off-by: sbwml 1 file changed, 8 insertions(+) diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js -index e0835d1..59155f4 100644 +index 2b9b8f5f0f..50b4a7dd66 100644 --- a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js +++ b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/system.js @@ -252,6 +252,14 @@ return view.extend({ - if (k[i].charAt(0) != '.') - o.value(uci.get('luci', 'themes', k[i]), k[i]); + o.ucisection = 'main'; + o.ucioption = 'tablefilters'; + o = s.taboption('language', form.Value, 'pollinterval', _('Refresh interval'), _('Refresh interval in seconds')); + o.uciconfig = 'luci'; diff --git a/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch b/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch index 3d668bcc5..cafae8c1e 100644 --- a/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch +++ b/openwrt/patch/luci/0006-luci-mod-system-mounts-add-docker-directory-mount-po.patch @@ -1,4 +1,4 @@ -From 32885208f76463b46706ef88d080cce81529b903 Mon Sep 17 00:00:00 2001 +From a7bffd1634cfbc2f4fb5306f1329f57d7194cd7d Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 Nov 2024 19:13:53 +0800 Subject: [PATCH 6/7] luci-mod-system: mounts: add docker directory mount point @@ -9,10 +9,10 @@ Signed-off-by: sbwml 1 file changed, 1 insertion(+) diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js -index 269b4a9..72f20c2 100644 +index d496faa8c3..1f94d5ebdd 100644 --- a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js +++ b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/mounts.js -@@ -293,6 +293,7 @@ return view.extend({ +@@ -272,6 +272,7 @@ return view.extend({ o = s.taboption('general', form.Value, 'target', _('Mount point'), _('Specifies the directory the device is attached to')); o.value('/', _('Use as root filesystem (/)')); o.value('/overlay', _('Use as external overlay (/overlay)')); diff --git a/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch b/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch index e27929df6..472a9e232 100644 --- a/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch +++ b/openwrt/patch/luci/0007-luci-mod-system-add-ucitrack-luci-mod-system-zram.js.patch @@ -1,4 +1,4 @@ -From fe0acd787f369d075816ceafb5d95d1cfa40fd25 Mon Sep 17 00:00:00 2001 +From 77a578cdc2c3eb430a890c6a286e37fcc6b21575 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 5 May 2025 22:24:52 +0800 Subject: [PATCH 7/7] luci-mod-system: add ucitrack luci-mod-system-zram.json @@ -11,7 +11,7 @@ Signed-off-by: sbwml diff --git a/modules/luci-mod-system/root/usr/share/ucitrack/luci-mod-system-zram.json b/modules/luci-mod-system/root/usr/share/ucitrack/luci-mod-system-zram.json new file mode 100644 -index 0000000..56da09e +index 0000000000..56da09efc8 --- /dev/null +++ b/modules/luci-mod-system/root/usr/share/ucitrack/luci-mod-system-zram.json @@ -0,0 +1,4 @@ diff --git a/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch b/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch index 1a0bbdef5..0ea70d299 100644 --- a/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch +++ b/openwrt/patch/luci/applications/luci-app-frpc/001-luci-app-frpc-hide-token.patch @@ -1,6 +1,6 @@ --- a/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js +++ b/feeds/luci/applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js -@@ -24,7 +24,7 @@ var commonConf = [ +@@ -24,7 +24,7 @@ const commonConf = [ [form.ListValue, 'log_level', _('Log level'), _('LogLevel specifies the minimum log level. Valid values are "trace", "debug", "info", "warn", and "error".
By default, this value is "info".'), {values: ['trace', 'debug', 'info', 'warn', 'error']}], [form.Value, 'log_max_days', _('Log max days'), _('LogMaxDays specifies the maximum number of days to store log information before deletion. This is only used if LogWay == "file".
By default, this value is 0.'), {datatype: 'uinteger'}], [form.Flag, 'disable_log_color', _('Disable log color'), _('DisableLogColor disables log colors when LogWay == "console" when set to true.'), {datatype: 'bool', default: 'false'}], diff --git a/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch b/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch index 189d53666..11e215f80 100644 --- a/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch +++ b/openwrt/patch/luci/applications/luci-app-frpc/002-luci-app-frpc-add-enable-flag.patch @@ -3,7 +3,7 @@ @@ -7,11 +7,10 @@ // [Widget, Option, Title, Description, {Param: 'Value'}], - var startupConf = [ + const startupConf = [ - [form.Flag, 'stdout', _('Log stdout')], - [form.Flag, 'stderr', _('Log stderr')], + [form.Flag, 'enable', _('Enable'), undefined, {datatype: 'bool', default: 'true', rmempty: false}], @@ -11,6 +11,6 @@ [widgets.GroupSelect, 'group', _('Run daemon as group')], - [form.Flag, 'respawn', _('Respawn when crashed')], + [form.Flag, 'respawn', _('Respawn when crashed'), undefined, {datatype: 'bool', default: 'true', rmempty: false}], - [form.DynamicList, 'env', _('Environment variable'), _('OS environments pass to frp for config file template, see
frp README'), {placeholder: 'ENV_NAME=value'}], + [form.DynamicList, 'env', _('Environment variable'), _('OS environments pass to frp for config file template, see %s.'.format('frp README')), {placeholder: 'ENV_NAME=value'}], [form.DynamicList, 'conf_inc', _('Additional configs'), _('Config files include in temporary config file'), {placeholder: '/etc/frp/frpc.d/frpc_full.ini'}] ]; diff --git a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch index 896ad379a..09a6d722a 100644 --- a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch +++ b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch @@ -1,4 +1,4 @@ -From 6430d15ff19b9885b3aedb5b228b0c3a5652ef29 Mon Sep 17 00:00:00 2001 +From 17678ba3c7b04b39a9aef9751ad645f3671b4ecd Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 11 Feb 2026 01:11:00 +0800 Subject: [PATCH] luci-app-package-manager: support installing uploaded APK @@ -12,10 +12,10 @@ Signed-off-by: sbwml 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js -index 8a70b4b..ced8785 100644 +index 48476dbe16..6afa5895cc 100644 --- a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js +++ b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js -@@ -1084,7 +1084,7 @@ function handleUpload(ev) +@@ -1086,7 +1086,7 @@ function handleUpload(ev) }, _('Cancel')), ' ', E('div', { 'class': 'btn cbi-button-action', @@ -25,7 +25,7 @@ index 8a70b4b..ced8785 100644 'click': function(ev) { handlePkg(ev).finally(function() { diff --git a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call -index 3a41757..7fa58f9 100755 +index 3a4175783a..7fa58f9060 100755 --- a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call +++ b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call @@ -27,7 +27,7 @@ case "$action" in @@ -48,7 +48,7 @@ index 3a41757..7fa58f9 100755 action="update" ;; diff --git a/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json b/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json -index 8d55186..31eb0b6 100644 +index 8d551860e8..31eb0b6a84 100644 --- a/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json +++ b/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json @@ -20,6 +20,7 @@ diff --git a/openwrt/patch/openwrt-6.x/modules/block.mk b/openwrt/patch/openwrt-6.x/modules/block.mk index 3dbeca9f9..50e4c2483 100644 --- a/openwrt/patch/openwrt-6.x/modules/block.mk +++ b/openwrt/patch/openwrt-6.x/modules/block.mk @@ -380,7 +380,7 @@ $(eval $(call KernelPackage,md-raid10)) define KernelPackage/md-raid456 -$(call KernelPackage/md/Depends,+kmod-lib-raid6 +kmod-lib-xor +kmod-lib-crc32c) +$(call KernelPackage/md/Depends,+kmod-lib-raid6 +kmod-lib-xor) TITLE:=RAID Level 456 Driver KCONFIG:= \ CONFIG_ASYNC_CORE \ diff --git a/openwrt/patch/openwrt-6.x/modules/crypto.mk b/openwrt/patch/openwrt-6.x/modules/crypto.mk index 45d39de35..da5e5eeca 100644 --- a/openwrt/patch/openwrt-6.x/modules/crypto.mk +++ b/openwrt/patch/openwrt-6.x/modules/crypto.mk @@ -116,7 +116,7 @@ $(eval $(call KernelPackage,crypto-ccm)) define KernelPackage/crypto-chacha20poly1305 TITLE:=ChaCha20-Poly1305 AEAD support, RFC7539 (used by strongSwan IPsec VPN) - DEPENDS:=+kmod-crypto-aead +kmod-crypto-manager +!LINUX_6_12:kmod-crypto-lib-poly1305 + DEPENDS:=+kmod-crypto-aead +kmod-crypto-manager +kmod-crypto-lib-poly1305 KCONFIG:=CONFIG_CRYPTO_CHACHA20POLY1305 FILES:=$(LINUX_DIR)/crypto/chacha20poly1305.ko AUTOLOAD:=$(call AutoLoad,09,chacha20poly1305) @@ -143,9 +143,8 @@ define KernelPackage/crypto-crc32 DEPENDS:=+kmod-crypto-hash KCONFIG:=CONFIG_CRYPTO_CRC32 HIDDEN:=1 - FILES:=$(LINUX_DIR)/crypto/crc32_generic.ko@lt6.18 \ - $(LINUX_DIR)/crypto/crc32-cryptoapi.ko@ge6.18 - AUTOLOAD:=$(call AutoLoad,04,LINUX_6_12:crc32_generic !LINUX_6_12:crc32-cryptoapi,1) + FILES:=$(LINUX_DIR)/crypto/crc32-cryptoapi.ko + AUTOLOAD:=$(call AutoLoad,04,crc32-cryptoapi,1) $(call AddDepends/crypto) endef @@ -156,9 +155,8 @@ define KernelPackage/crypto-crc32c TITLE:=CRC32c CRC module DEPENDS:=+kmod-crypto-hash KCONFIG:=CONFIG_CRYPTO_CRC32C - FILES:=$(LINUX_DIR)/crypto/crc32c_generic.ko@lt6.18 \ - $(LINUX_DIR)/crypto/crc32c-cryptoapi.ko@ge6.18 - AUTOLOAD:=$(call AutoLoad,04,LINUX_6_12:crc32c_generic !LINUX_6_12:crc32c-cryptoapi,1) + FILES:=$(LINUX_DIR)/crypto/crc32c-cryptoapi.ko + AUTOLOAD:=$(call AutoLoad,04,crc32c-cryptoapi,1) $(call AddDepends/crypto) endef @@ -532,28 +530,20 @@ define KernelPackage/crypto-hw-eip93 KCONFIG:= \ CONFIG_CRYPTO_HW=y \ CONFIG_CRYPTO_DEV_EIP93 \ - CONFIG_CRYPTO_DEV_EIP93_AES=y@lt6.18 \ - CONFIG_CRYPTO_DEV_EIP93_DES=y@lt6.18 \ - CONFIG_CRYPTO_DEV_EIP93_AEAD=y@lt6.18 \ CONFIG_CRYPTO_DEV_EIP93_GENERIC_SW_MAX_LEN=256 \ CONFIG_CRYPTO_DEV_EIP93_AES_128_SW_MAX_LEN=512 - FILES:=$(LINUX_DIR)/drivers/crypto/mtk-eip93/crypto-hw-eip93.ko@lt6.18 \ - $(LINUX_DIR)/drivers/crypto/inside-secure/eip93/crypto-hw-eip93.ko@ge6.18 + FILES:=$(LINUX_DIR)/drivers/crypto/inside-secure/eip93/crypto-hw-eip93.ko AUTOLOAD:=$(call AutoLoad,09,crypto-hw-eip93) $(call AddDepends/crypto) endef define KernelPackage/crypto-hw-eip93/description Kernel module to enable EIP-93 Crypto engine as found -in Mediatek MT7621 and Airoha SoCs. +in the Mediatek MT7621 SoC. It enables DES/3DES/AES ECB/CBC/CTR and IPSEC offload with authenc(hmac(sha1/sha256), aes/cbc/rfc3686) endef -define KernelPackage/crypto-hw-eip93/airoha - FILES:=$(LINUX_DIR)/drivers/crypto/inside-secure/eip93/crypto-hw-eip93.ko -endef - $(eval $(call KernelPackage,crypto-hw-eip93)) define KernelPackage/crypto-kpp @@ -631,35 +621,10 @@ define KernelPackage/crypto-lib-curve25519 KCONFIG:=CONFIG_CRYPTO_LIB_CURVE25519 HIDDEN:=1 FILES:= \ - $(LINUX_DIR)/lib/crypto/libcurve25519.ko \ - $(LINUX_DIR)/lib/crypto/libcurve25519-generic.ko@lt6.18 + $(LINUX_DIR)/lib/crypto/libcurve25519.ko $(call AddDepends/crypto,+kmod-crypto-kpp) endef -ifeq ($(KERNEL_PATCHVER),6.12) -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-lib-curve25519/x86_64 - KCONFIG+=CONFIG_CRYPTO_CURVE25519_X86 - FILES+=$(LINUX_DIR)/arch/x86/crypto/curve25519-x86_64.ko -endef -endif - -define KernelPackage/crypto-lib-curve25519/arm-neon - KCONFIG+=CONFIG_CRYPTO_CURVE25519_NEON - FILES+=$(LINUX_DIR)/arch/arm/crypto/curve25519-neon.ko -endef - -ifeq ($(ARCH)-$(CONFIG_KERNEL_MODE_NEON),arm-y) - KernelPackage/crypto-lib-curve25519/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-lib-curve25519/arm-neon) -endif - -ifdef KernelPackage/crypto-lib-curve25519/$(ARCH) - KernelPackage/crypto-lib-curve25519/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-lib-curve25519/$(ARCH)) -endif -endif - $(eval $(call KernelPackage,crypto-lib-curve25519)) @@ -671,41 +636,6 @@ define KernelPackage/crypto-lib-poly1305 $(call AddDepends/crypto,+kmod-crypto-hash) endef -ifeq ($(KERNEL_PATCHVER),6.12) -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-lib-poly1305/x86_64 - KCONFIG+=CONFIG_CRYPTO_POLY1305_X86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/poly1305-x86_64.ko -endef -endif - -define KernelPackage/crypto-lib-poly1305/arm - KCONFIG+=CONFIG_CRYPTO_POLY1305_ARM - FILES:=$(LINUX_DIR)/arch/arm/crypto/poly1305-arm.ko -endef - -KernelPackage/crypto-lib-poly1305/armeb=$(KernelPackage/crypto-lib-poly1305/arm) - -define KernelPackage/crypto-lib-poly1305/aarch64 - KCONFIG+=CONFIG_CRYPTO_POLY1305_NEON - FILES:=$(LINUX_DIR)/arch/arm64/crypto/poly1305-neon.ko -endef - -define KernelPackage/crypto-lib-poly1305/mips - KCONFIG+=CONFIG_CRYPTO_POLY1305_MIPS - FILES:=$(LINUX_DIR)/arch/mips/crypto/poly1305-mips.ko -endef - -KernelPackage/crypto-lib-poly1305/mipsel=$(KernelPackage/crypto-lib-poly1305/mips) -KernelPackage/crypto-lib-poly1305/mips64=$(KernelPackage/crypto-lib-poly1305/mips) -KernelPackage/crypto-lib-poly1305/mips64el=$(KernelPackage/crypto-lib-poly1305/mips) - -ifdef KernelPackage/crypto-lib-poly1305/$(ARCH) - KernelPackage/crypto-lib-poly1305/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-lib-poly1305/$(ARCH)) -endif -endif - $(eval $(call KernelPackage,crypto-lib-poly1305)) @@ -743,8 +673,8 @@ define KernelPackage/crypto-md5 CONFIG_CRYPTO_MD5_OCTEON \ CONFIG_CRYPTO_MD5_PPC FILES:=$(LINUX_DIR)/crypto/md5.ko \ - $(LINUX_DIR)/lib/crypto/libmd5.ko@ge6.18 - AUTOLOAD:=$(call AutoLoad,09,md5 !LINUX_6_12:libmd5) + $(LINUX_DIR)/lib/crypto/libmd5.ko + AUTOLOAD:=$(call AutoLoad,09,md5 libmd5) $(call AddDepends/crypto) endef @@ -973,73 +903,12 @@ $(eval $(call KernelPackage,crypto-seqiv)) define KernelPackage/crypto-sha1 TITLE:=SHA1 digest CryptoAPI module DEPENDS:=+kmod-crypto-hash - KCONFIG:= \ - CONFIG_CRYPTO_SHA1 \ - CONFIG_CRYPTO_SHA1_ARM@lt6.18 \ - CONFIG_CRYPTO_SHA1_ARM_NEON@lt6.18 \ - CONFIG_CRYPTO_SHA1_ARM64_CE@lt6.18 \ - CONFIG_CRYPTO_SHA1_OCTEON@lt6.18 \ - CONFIG_CRYPTO_SHA1_PPC_SPE@lt6.18 \ - CONFIG_CRYPTO_SHA1_SSSE3@lt6.18 - FILES:=$(LINUX_DIR)/crypto/sha1_generic.ko@lt6.18 \ - $(LINUX_DIR)/crypto/sha1.ko@ge6.18 - AUTOLOAD:=$(call AutoLoad,09,LINUX_6_12:sha1_generic !LINUX_6_12:sha1) + KCONFIG:= CONFIG_CRYPTO_SHA1 + FILES:=$(LINUX_DIR)/crypto/sha1.ko + AUTOLOAD:=$(call AutoLoad,09,sha1) $(call AddDepends/crypto) endef -ifeq ($(KERNEL_PATCHVER),6.12) -define KernelPackage/crypto-sha1/arm - FILES+=$(LINUX_DIR)/arch/arm/crypto/sha1-arm.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-arm) -endef - -define KernelPackage/crypto-sha1/arm-neon - $(call KernelPackage/crypto-sha1/arm) - FILES+=$(LINUX_DIR)/arch/arm/crypto/sha1-arm-neon.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-arm-neon) -endef - -define KernelPackage/crypto-sha1/aarch64-ce - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha1-ce.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-ce) -endef - -KernelPackage/crypto-sha1/imx/cortexa7=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/imx/cortexa9=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/ipq40xx=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/mediatek/filogic=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/mediatek/mt7622=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/mvebu/cortexa9=$(KernelPackage/crypto-sha1/arm-neon) -KernelPackage/crypto-sha1/mvebu/cortexa53=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/mvebu/cortexa72=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/qualcommax=$(KernelPackage/crypto-sha1/aarch64-ce) -KernelPackage/crypto-sha1/rockchip/armv8=$(KernelPackage/crypto-sha1/aarch64-ce) - -define KernelPackage/crypto-sha1/octeon - FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha1.ko - AUTOLOAD+=$(call AutoLoad,09,octeon-sha1) -endef - -KernelPackage/crypto-sha1/tegra=$(KernelPackage/crypto-sha1/arm) - -define KernelPackage/crypto-sha1/mpc85xx - FILES+=$(LINUX_DIR)/arch/powerpc/crypto/sha1-ppc-spe.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-ppc-spe) -endef - -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-sha1/x86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/sha1-ssse3.ko - AUTOLOAD+=$(call AutoLoad,09,sha1-ssse3) -endef -endif - -ifdef KernelPackage/crypto-sha1/$(ARCH) - KernelPackage/crypto-sha1/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-sha1/$(ARCH)) -endif -endif - $(eval $(call KernelPackage,crypto-sha1)) @@ -1058,118 +927,27 @@ $(eval $(call KernelPackage,crypto-sha3)) define KernelPackage/crypto-sha256 TITLE:=SHA224 SHA256 digest CryptoAPI module DEPENDS:=+kmod-crypto-hash - KCONFIG:= \ - CONFIG_CRYPTO_SHA256 \ - CONFIG_CRYPTO_SHA256_OCTEON@lt6.18 \ - CONFIG_CRYPTO_SHA256_PPC_SPE@lt6.18 \ - CONFIG_CRYPTO_SHA256_ARM64@lt6.18 \ - CONFIG_CRYPTO_SHA2_ARM64_CE@lt6.18 \ - CONFIG_CRYPTO_SHA256_SSSE3@lt6.18 + KCONFIG:=CONFIG_CRYPTO_SHA256 FILES:= \ - $(LINUX_DIR)/crypto/sha256_generic.ko@lt6.18 \ - $(LINUX_DIR)/crypto/sha256.ko@ge6.18 \ + $(LINUX_DIR)/crypto/sha256.ko \ $(LINUX_DIR)/lib/crypto/libsha256.ko - AUTOLOAD:=$(call AutoLoad,09,LINUX_6_12:sha256_generic !LINUX_6_12:sha256) + AUTOLOAD:=$(call AutoLoad,09,sha256) $(call AddDepends/crypto) endef -ifeq ($(KERNEL_PATCHVER),6.12) -define KernelPackage/crypto-sha256/aarch64 - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha256-arm64.ko - AUTOLOAD+=$(call AutoLoad,09,sha256-arm64) -endef - -define KernelPackage/crypto-sha256/aarch64-ce - $(call KernelPackage/crypto-sha256/aarch64) - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha2-ce.ko - AUTOLOAD+=$(call AutoLoad,09,sha2-ce) -endef - -define KernelPackage/crypto-sha256/octeon - FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha256.ko - AUTOLOAD+=$(call AutoLoad,09,octeon-sha256) -endef - -define KernelPackage/crypto-sha256/mpc85xx - FILES+=$(LINUX_DIR)/arch/powerpc/crypto/sha256-ppc-spe.ko - AUTOLOAD+=$(call AutoLoad,09,sha256-ppc-spe) -endef - -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-sha256/x86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/sha256-ssse3.ko - AUTOLOAD+=$(call AutoLoad,09,sha256-ssse3) -endef -endif - -KernelPackage/crypto-sha256/mediatek/filogic=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/mediatek/mt7622=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/mvebu/cortexa53=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/mvebu/cortexa72=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/qualcommax=$(KernelPackage/crypto-sha256/aarch64-ce) -KernelPackage/crypto-sha256/rockchip/armv8=$(KernelPackage/crypto-sha256/aarch64-ce) - -ifdef KernelPackage/crypto-sha256/$(ARCH) - KernelPackage/crypto-sha256/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-sha256/$(ARCH)) -endif -endif - $(eval $(call KernelPackage,crypto-sha256)) define KernelPackage/crypto-sha512 TITLE:=SHA512 digest CryptoAPI module DEPENDS:=+kmod-crypto-hash - KCONFIG:= \ - CONFIG_CRYPTO_SHA512 \ - CONFIG_CRYPTO_SHA512_ARM@lt6.18 \ - CONFIG_CRYPTO_SHA512_ARM64@lt6.18 \ - CONFIG_CRYPTO_SHA512_OCTEON@lt6.18 \ - CONFIG_CRYPTO_SHA512_SSSE3@lt6.18 - FILES:=$(LINUX_DIR)/crypto/sha512_generic.ko@lt6.18 \ - $(LINUX_DIR)/crypto/sha512.ko@ge6.18 \ - $(LINUX_DIR)/lib/crypto/libsha512.ko@ge6.18 - AUTOLOAD:=$(call AutoLoad,09,LINUX_6_12:sha512_generic !LINUX_6_12:sha512) + KCONFIG:=CONFIG_CRYPTO_SHA512 + FILES:=$(LINUX_DIR)/crypto/sha512.ko \ + $(LINUX_DIR)/lib/crypto/libsha512.ko + AUTOLOAD:=$(call AutoLoad,09,sha512) $(call AddDepends/crypto) endef -ifeq ($(KERNEL_PATCHVER),6.12) -define KernelPackage/crypto-sha512/arm - FILES+=$(LINUX_DIR)/arch/arm/crypto/sha512-arm.ko - AUTOLOAD+=$(call AutoLoad,09,sha512-arm) -endef - -define KernelPackage/crypto-sha512/aarch64 - FILES+=$(LINUX_DIR)/arch/arm64/crypto/sha512-arm64.ko - AUTOLOAD+=$(call AutoLoad,09,sha512-arm64) -endef - -KernelPackage/crypto-sha512/imx/cortexa7=$(KernelPackage/crypto-sha512/arm) -KernelPackage/crypto-sha512/imx/cortexa9=$(KernelPackage/crypto-sha512/arm) -KernelPackage/crypto-sha512/ipq40xx=$(KernelPackage/crypto-sha512/arm) -KernelPackage/crypto-sha512/mvebu/cortexa9=$(KernelPackage/crypto-sha512/arm) - -define KernelPackage/crypto-sha512/octeon - FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha512.ko - AUTOLOAD+=$(call AutoLoad,09,octeon-sha512) -endef - -KernelPackage/crypto-sha512/tegra=$(KernelPackage/crypto-sha512/arm) - -ifndef CONFIG_TARGET_uml -define KernelPackage/crypto-sha512/x86_64 - FILES+=$(LINUX_DIR)/arch/x86/crypto/sha512-ssse3.ko - AUTOLOAD+=$(call AutoLoad,09,sha512-ssse3) -endef -endif - -ifdef KernelPackage/crypto-sha512/$(ARCH) - KernelPackage/crypto-sha512/$(CRYPTO_TARGET)=\ - $(KernelPackage/crypto-sha512/$(ARCH)) -endif -endif - $(eval $(call KernelPackage,crypto-sha512)) diff --git a/openwrt/patch/openwrt-6.x/modules/fs.mk b/openwrt/patch/openwrt-6.x/modules/fs.mk index 4a6e77788..3ed3dd149 100644 --- a/openwrt/patch/openwrt-6.x/modules/fs.mk +++ b/openwrt/patch/openwrt-6.x/modules/fs.mk @@ -67,7 +67,7 @@ $(eval $(call KernelPackage,fs-autofs4)) define KernelPackage/fs-btrfs SUBMENU:=$(FS_MENU) TITLE:=BTRFS filesystem support - DEPENDS:=+kmod-lib-crc32c +kmod-lib-lzo +kmod-lib-zlib-inflate +kmod-lib-zlib-deflate +kmod-lib-raid6 +kmod-lib-xor +kmod-lib-zstd +kmod-crypto-blake2b +kmod-crypto-xxhash + DEPENDS:=+kmod-lib-lzo +kmod-lib-zlib-inflate +kmod-lib-zlib-deflate +kmod-lib-raid6 +kmod-lib-xor +kmod-lib-zstd +kmod-crypto-blake2b +kmod-crypto-xxhash KCONFIG:=\ CONFIG_BTRFS_FS \ CONFIG_BTRFS_FS_CHECK_INTEGRITY=n @@ -473,6 +473,7 @@ define KernelPackage/fs-nfs-common CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" \ CONFIG_NFS_V4_1_MIGRATION=n \ CONFIG_NFS_V4_2=y \ + CONFIG_NFSD_V4_DELEG_TIMESTAMPS=n \ CONFIG_NFS_V4_2_READ_PLUS=n FILES:= \ $(LINUX_DIR)/fs/lockd/lockd.ko \ @@ -668,7 +669,7 @@ define KernelPackage/fs-xfs SUBMENU:=$(FS_MENU) TITLE:=XFS filesystem support KCONFIG:=CONFIG_XFS_FS - DEPENDS:= +kmod-fs-exportfs +kmod-lib-crc32c + DEPENDS:= +kmod-fs-exportfs FILES:=$(LINUX_DIR)/fs/xfs/xfs.ko AUTOLOAD:=$(call AutoLoad,30,xfs,1) endef diff --git a/openwrt/patch/openwrt-6.x/modules/hwmon.mk b/openwrt/patch/openwrt-6.x/modules/hwmon.mk index bdc13f1e8..a0b425275 100644 --- a/openwrt/patch/openwrt-6.x/modules/hwmon.mk +++ b/openwrt/patch/openwrt-6.x/modules/hwmon.mk @@ -63,6 +63,21 @@ endef $(eval $(call KernelPackage,hwmon-adt7410)) +define KernelPackage/hwmon-adt7470 + TITLE:=ADT7470 monitoring support + KCONFIG:=CONFIG_SENSORS_ADT7470 + FILES:=$(LINUX_DIR)/drivers/hwmon/adt7470.ko + AUTOLOAD:=$(call AutoProbe,adt7470) + $(call AddDepends/hwmon,+kmod-i2c-core +kmod-regmap-i2c) +endef + +define KernelPackage/hwmon-adt7470/description + Kernel module for ADT7470 thermal monitor chip +endef + +$(eval $(call KernelPackage,hwmon-adt7470)) + + define KernelPackage/hwmon-adt7475 TITLE:=ADT7473/7475/7476/7490 monitoring support KCONFIG:=CONFIG_SENSORS_ADT7475 @@ -493,6 +508,25 @@ endef $(eval $(call KernelPackage,pmbus-core)) +define KernelPackage/pmbus-sensors + TITLE:=Generic PMBus devices monitoring support + KCONFIG:=CONFIG_SENSORS_PMBUS + FILES:=$(LINUX_DIR)/drivers/hwmon/pmbus/pmbus.ko + AUTOLOAD:=$(call AutoProbe,pmbus) + $(call AddDepends/hwmon,+kmod-pmbus-core) +endef + +define KernelPackage/pmbus-sensors/description + Kernel modules for generic PMBus devices, +including but not limited to ADP4000, BMR310, BMR453, +BMR454, BMR456, BMR457, BMR458, BMR480, BMR490, BMR491, BMR492, +MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, +TPS40400, TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020. +endef + +$(eval $(call KernelPackage,pmbus-sensors)) + + define KernelPackage/pmbus-zl6100 TITLE:=Intersil / Zilker Labs ZL6100 hardware monitoring KCONFIG:=CONFIG_SENSORS_ZL6100 diff --git a/openwrt/patch/openwrt-6.x/modules/iio.mk b/openwrt/patch/openwrt-6.x/modules/iio.mk index fcb67e0de..0bdcf5a8c 100644 --- a/openwrt/patch/openwrt-6.x/modules/iio.mk +++ b/openwrt/patch/openwrt-6.x/modules/iio.mk @@ -485,7 +485,8 @@ $(eval $(call KernelPackage,iio-lsm6dsx)) define KernelPackage/iio-lsm6dsx-i2c DEPENDS:=+kmod-iio-lsm6dsx +kmod-i2c-core +kmod-regmap-i2c TITLE:=ST LSM6DSx driver for IMU MEMS sensors (I2C) - KCONFIG:=CONFIG_IIO_ST_LSM6DSX_I2C + KCONFIG:=CONFIG_IIO_ST_LSM6DSX \ + CONFIG_IIO_ST_LSM6DSX_I2C FILES:=$(LINUX_DIR)/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.ko AUTOLOAD:=$(call AutoProbe,st_lsm6dsx-i2c) $(call AddDepends/iio) @@ -501,7 +502,8 @@ $(eval $(call KernelPackage,iio-lsm6dsx-i2c)) define KernelPackage/iio-lsm6dsx-spi DEPENDS:=+kmod-iio-lsm6dsx +kmod-regmap-spi TITLE:=ST LSM6DSx driver for IMU MEMS sensors (SPI) - KCONFIG:=CONFIG_IIO_ST_LSM6DSX_SPI + KCONFIG:=CONFIG_IIO_ST_LSM6DSX \ + CONFIG_IIO_ST_LSM6DSX_SPI FILES:=$(LINUX_DIR)/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.ko AUTOLOAD:=$(call AutoProbe,st_lsm6dsx-spi) $(call AddDepends/iio) diff --git a/openwrt/patch/openwrt-6.x/modules/lib.mk b/openwrt/patch/openwrt-6.x/modules/lib.mk index c119ae05b..e8559a02a 100644 --- a/openwrt/patch/openwrt-6.x/modules/lib.mk +++ b/openwrt/patch/openwrt-6.x/modules/lib.mk @@ -359,6 +359,7 @@ $(eval $(call KernelPackage,oid-registry)) define KernelPackage/lib-objagg SUBMENU:=$(LIB_MENU) TITLE:=objagg support + HIDDEN:=1 FILES:=$(LINUX_DIR)/lib/objagg.ko KCONFIG:= \ CONFIG_OBJAGG \ @@ -372,6 +373,7 @@ $(eval $(call KernelPackage,lib-objagg)) define KernelPackage/lib-parman SUBMENU:=$(LIB_MENU) TITLE:=parman support + HIDDEN:=1 FILES:=$(LINUX_DIR)/lib/parman.ko KCONFIG:= \ CONFIG_PARMAN \ diff --git a/openwrt/patch/openwrt-6.x/modules/netdevices.mk b/openwrt/patch/openwrt-6.x/modules/netdevices.mk index 18052cbd7..af631831c 100644 --- a/openwrt/patch/openwrt-6.x/modules/netdevices.mk +++ b/openwrt/patch/openwrt-6.x/modules/netdevices.mk @@ -155,12 +155,11 @@ define KernelPackage/libphy SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=PHY library KCONFIG:=CONFIG_PHYLIB \ - CONFIG_MDIO_BUS \ - CONFIG_PHYLIB_LEDS=y - FILES:= \ - $(LINUX_DIR)/drivers/net/phy/libphy.ko \ - $(LINUX_DIR)/drivers/net/phy/mdio-bus.ko - AUTOLOAD:=$(call AutoLoad,15,libphy,1) + CONFIG_PHYLIB_LEDS=y \ + CONFIG_MDIO_BUS + FILES:=$(LINUX_DIR)/drivers/net/phy/libphy.ko \ + $(LINUX_DIR)/drivers/net/phy/mdio-bus.ko@ge6.18 + AUTOLOAD:=$(call AutoLoad,15,libphy mdio-bus,1) endef define KernelPackage/libphy/description diff --git a/openwrt/patch/openwrt-6.x/modules/netfilter.mk b/openwrt/patch/openwrt-6.x/modules/netfilter.mk index 96531b1e0..64e3e3482 100644 --- a/openwrt/patch/openwrt-6.x/modules/netfilter.mk +++ b/openwrt/patch/openwrt-6.x/modules/netfilter.mk @@ -440,7 +440,7 @@ IPVS_MODULES:= \ define KernelPackage/nf-ipvs SUBMENU:=Netfilter Extensions TITLE:=IP Virtual Server modules - DEPENDS:=@IPV6 +kmod-lib-crc32c +kmod-ipt-conntrack +kmod-nf-conntrack + DEPENDS:=@IPV6 +kmod-ipt-conntrack +kmod-nf-conntrack KCONFIG:= \ CONFIG_IP_VS \ CONFIG_IP_VS_IPV6=y \ @@ -1135,7 +1135,7 @@ $(eval $(call KernelPackage,ipt-rpfilter)) define KernelPackage/nft-core SUBMENU:=$(NF_MENU) TITLE:=Netfilter nf_tables support - DEPENDS:=+kmod-nfnetlink +kmod-nf-reject +IPV6:kmod-nf-reject6 +IPV6:kmod-nf-conntrack6 +kmod-nf-nat +kmod-nf-log +IPV6:kmod-nf-log6 +kmod-lib-crc32c + DEPENDS:=+kmod-nfnetlink +kmod-nf-reject +IPV6:kmod-nf-reject6 +IPV6:kmod-nf-conntrack6 +kmod-nf-nat +kmod-nf-log +IPV6:kmod-nf-log6 FILES:=$(foreach mod,$(NFT_CORE-m),$(LINUX_DIR)/net/$(mod).ko) AUTOLOAD:=$(call AutoProbe,$(notdir $(NFT_CORE-m))) KCONFIG:= \ diff --git a/openwrt/patch/openwrt-6.x/modules/netsupport.mk b/openwrt/patch/openwrt-6.x/modules/netsupport.mk index 6431e7507..46bb81c1a 100644 --- a/openwrt/patch/openwrt-6.x/modules/netsupport.mk +++ b/openwrt/patch/openwrt-6.x/modules/netsupport.mk @@ -1016,7 +1016,7 @@ SCHED_FILES_EXTRA = $(foreach mod,$(SCHED_MODULES_EXTRA),$(LINUX_DIR)/net/sched/ define KernelPackage/sched SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Extra traffic schedulers - DEPENDS:=+kmod-sched-core +kmod-lib-crc32c +kmod-lib-textsearch + DEPENDS:=+kmod-sched-core +kmod-lib-textsearch KCONFIG:= \ CONFIG_NET_SCH_CODEL \ CONFIG_NET_SCH_GRED \ @@ -1234,10 +1234,11 @@ define KernelPackage/sctp CONFIG_SCTP_COOKIE_HMAC_MD5=y \ CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE=n \ CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=n \ + CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA256=n \ CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y FILES:= $(LINUX_DIR)/net/sctp/sctp.ko AUTOLOAD:= $(call AutoLoad,32,sctp) - DEPENDS:=+kmod-lib-crc32c +kmod-crypto-md5 +kmod-crypto-hmac \ + DEPENDS:=+kmod-crypto-md5 +kmod-crypto-hmac \ +kmod-udptunnel4 +kmod-udptunnel6 endef @@ -1635,3 +1636,88 @@ define KernelPackage/qrtr-mhi/description endef $(eval $(call KernelPackage,qrtr-mhi)) + +define KernelPackage/unix-diag + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=UNIX socket monitoring interface + KCONFIG:=CONFIG_UNIX_DIAG + FILES:= $(LINUX_DIR)/net/unix/unix_diag.ko + AUTOLOAD:=$(call AutoProbe,unix_diag) +endef + +$(eval $(call KernelPackage,unix-diag)) + +define KernelPackage/packet-diag + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Packet sockets monitoring interface + KCONFIG:=CONFIG_PACKET_DIAG + FILES:= $(LINUX_DIR)/net/packet/af_packet_diag.ko + AUTOLOAD:=$(call AutoProbe,af_packet_diag) +endef + +$(eval $(call KernelPackage,packet-diag)) + +define KernelPackage/team + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Ethernet team driver + KCONFIG:=CONFIG_NET_TEAM + FILES:=$(LINUX_DIR)/drivers/net/team/team.ko + AUTOLOAD:=$(call AutoProbe,team) +endef + +$(eval $(call KernelPackage,team)) + +define KernelPackage/team-mode-broadcast + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Broadcast mode support + DEPENDS:=kmod-team + KCONFIG:=CONFIG_NET_TEAM_MODE_BROADCAST + FILES:=$(LINUX_DIR)/drivers/net/team/team_mode_broadcast.ko + AUTOLOAD:=$(call AutoProbe,team_mode_broadcast) +endef + +$(eval $(call KernelPackage,team-mode-broadcast)) + +define KernelPackage/team-mode-roundrobin + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Round-robin mode support + DEPENDS:=kmod-team + KCONFIG:=CONFIG_NET_TEAM_MODE_ROUNDROBIN + FILES:=$(LINUX_DIR)/drivers/net/team/team_mode_roundrobin.ko + AUTOLOAD:=$(call AutoProbe,team_mode_roundrobin) +endef + +$(eval $(call KernelPackage,team-mode-roundrobin)) + +define KernelPackage/team-mode-random + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Random mode support + DEPENDS:=kmod-team + KCONFIG:=CONFIG_NET_TEAM_MODE_RANDOM + FILES:=$(LINUX_DIR)/drivers/net/team/team_mode_random.ko + AUTOLOAD:=$(call AutoProbe,team_mode_random) +endef + +$(eval $(call KernelPackage,team-mode-random)) + +define KernelPackage/team-mode-activebackup + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Active-backup mode support + DEPENDS:=kmod-team + KCONFIG:=CONFIG_NET_TEAM_MODE_ACTIVEBACKUP + FILES:=$(LINUX_DIR)/drivers/net/team/team_mode_activebackup.ko + AUTOLOAD:=$(call AutoProbe,team_mode_activebackup) +endef + +$(eval $(call KernelPackage,team-mode-activebackup)) + +define KernelPackage/team-mode-loadbalance + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=Load-balance mode support + DEPENDS:=kmod-team + KCONFIG:=CONFIG_NET_TEAM_MODE_LOADBALANCE + FILES:=$(LINUX_DIR)/drivers/net/team/team_mode_loadbalance.ko + AUTOLOAD:=$(call AutoProbe,team_mode_loadbalance) +endef + +$(eval $(call KernelPackage,team-mode-loadbalance)) diff --git a/openwrt/patch/openwrt-6.x/modules/other.mk b/openwrt/patch/openwrt-6.x/modules/other.mk index 74cbefd75..bb642bdf8 100644 --- a/openwrt/patch/openwrt-6.x/modules/other.mk +++ b/openwrt/patch/openwrt-6.x/modules/other.mk @@ -34,7 +34,7 @@ define KernelPackage/dma-buf KCONFIG:=CONFIG_DMA_SHARED_BUFFER ifeq ($(strip $(CONFIG_EXTERNAL_KERNEL_TREE)),"") ifeq ($(strip $(CONFIG_KERNEL_GIT_CLONE_URI)),"") - FILES:=$(LINUX_DIR)/drivers/dma-buf/dma-shared-buffer.ko@le6.6 + FILES:=$(LINUX_DIR)/drivers/dma-buf/dma-shared-buffer.ko@lt6.18 endif endif AUTOLOAD:=$(call AutoLoad,20,dma-shared-buffer) @@ -222,7 +222,7 @@ define KernelPackage/pinctrl-mcp23s08 SUBMENU:=$(OTHER_MENU) TITLE:=Microchip MCP23xxx I/O expander HIDDEN:=1 - DEPENDS:=@GPIO_SUPPORT +kmod-regmap-core + DEPENDS:=@GPIO_SUPPORT @PINCTRL_SUPPORT +kmod-regmap-core KCONFIG:=CONFIG_PINCTRL_MCP23S08 FILES:=$(LINUX_DIR)/drivers/pinctrl/pinctrl-mcp23s08.ko AUTOLOAD:=$(call AutoLoad,40,pinctrl-mcp23s08) @@ -975,7 +975,7 @@ $(eval $(call KernelPackage,tpm)) define KernelPackage/tpm-tis SUBMENU:=$(OTHER_MENU) TITLE:=TPM TIS 1.2 Interface / TPM 2.0 FIFO Interface - DEPENDS:= @(TARGET_x86||TARGET_armsr) +kmod-tpm + DEPENDS:= @(TARGET_x86||TARGET_armsr||TARGET_imx) +kmod-tpm KCONFIG:= CONFIG_TCG_TIS FILES:= \ $(LINUX_DIR)/drivers/char/tpm/tpm_tis.ko \ @@ -992,6 +992,27 @@ endef $(eval $(call KernelPackage,tpm-tis)) +define KernelPackage/tpm-tis-spi + SUBMENU:=$(OTHER_MENU) + TITLE:=TPM TIS 1.3 Interface SPI Interface + DEPENDS:= +kmod-tpm-tis +kmod-spi-dev + KCONFIG:= CONFIG_TCG_TIS_SPI \ + CONFIG_TCG_TIS_SPI_CR50=n + FILES:= \ + $(LINUX_DIR)/drivers/char/tpm/tpm_tis_spi.ko + AUTOLOAD:=$(call AutoLoad,20,tpm_tis_spi,1) +endef + +define KernelPackage/tpm-tis-spi/description + If you have a TPM security chip which is connected to a regular, + non-tcg SPI master that is compliant with the + TCG TIS 1.3 TPM specification (TPM1.2) or the TCG PTP FIFO + specification (TPM2.0) say Yes and it will be accessible from + within Linux. +endef + +$(eval $(call KernelPackage,tpm-tis-spi)) + define KernelPackage/tpm-i2c-atmel SUBMENU:=$(OTHER_MENU) TITLE:=TPM I2C Atmel Support diff --git a/openwrt/patch/openwrt-6.x/modules/usb.mk b/openwrt/patch/openwrt-6.x/modules/usb.mk index cffcd329b..11c56c848 100644 --- a/openwrt/patch/openwrt-6.x/modules/usb.mk +++ b/openwrt/patch/openwrt-6.x/modules/usb.mk @@ -154,6 +154,24 @@ endef $(eval $(call KernelPackage,usb-gadget-hid)) +define KernelPackage/usb-gadget-fs + TITLE:=USB FunctionFS Gadget Support + KCONFIG:=CONFIG_USB_FUNCTIONFS \ + CONFIG_USB_FUNCTIONFS_ETH=n \ + CONFIG_USB_FUNCTIONFS_RNDIS=n + FILES:= \ + $(LINUX_DIR)/drivers/usb/gadget/legacy/g_ffs.ko \ + $(LINUX_DIR)/drivers/usb/gadget/function/usb_f_fs.ko + AUTOLOAD:=$(call AutoLoad,52,usb_f_fs) + $(call AddDepends/usbgadget,+kmod-usb-lib-composite +kmod-dma-buf) +endef + +define KernelPackage/usb-gadget-fs/description + Kernel support for USB FunctionFS Gadget. +endef + +$(eval $(call KernelPackage,usb-gadget-fs)) + define KernelPackage/usb-gadget-ehci-debug TITLE:=USB EHCI debug port Gadget support KCONFIG:=\ @@ -1319,7 +1337,7 @@ $(eval $(call KernelPackage,usb-net-kaweth)) define KernelPackage/usb-net-lan78xx TITLE:=USB-To-Ethernet Microchip LAN78XX convertors - DEPENDS:=+kmod-fixed-phy +kmod-phy-microchip +kmod-phylink +PACKAGE_kmod-of-mdio:kmod-of-mdio + DEPENDS:=+kmod-fixed-phy +kmod-phy-microchip +kmod-phylink +PACKAGE_kmod-of-mdio:kmod-of-mdio +kmod-net-selftests KCONFIG:=CONFIG_USB_LAN78XX FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/lan78xx.ko AUTOLOAD:=$(call AutoProbe,lan78xx) @@ -1842,6 +1860,7 @@ define KernelPackage/usb3 TITLE:=Support for USB3 controllers DEPENDS:= \ +kmod-usb-xhci-hcd \ + +TARGET_airoha_an7581:kmod-usb-xhci-mtk \ +TARGET_bcm53xx:kmod-usb-bcma \ +TARGET_bcm53xx:kmod-phy-bcm-ns-usb3 \ +TARGET_ramips_mt7621:kmod-usb-xhci-mtk \ diff --git a/openwrt/patch/openwrt-6.x/modules/video.mk b/openwrt/patch/openwrt-6.x/modules/video.mk index f8d05103e..044ffc072 100644 --- a/openwrt/patch/openwrt-6.x/modules/video.mk +++ b/openwrt/patch/openwrt-6.x/modules/video.mk @@ -128,8 +128,7 @@ define KernelPackage/fb CONFIG_VT_CONSOLE=y \ CONFIG_VT_HW_CONSOLE_BINDING=y FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb.ko \ - $(LINUX_DIR)/lib/fonts/font.ko \ - $(LINUX_DIR)/drivers/video/fbdev/core/fb_io_fops.ko@lt6.12 + $(LINUX_DIR)/lib/fonts/font.ko AUTOLOAD:=$(call AutoLoad,06,fb font) endef @@ -138,8 +137,8 @@ define KernelPackage/fb/description endef define KernelPackage/fb/x86 - FILES+=$(LINUX_DIR)/arch/x86/video/fbdev.ko@lt6.12 - AUTOLOAD:=$(call AutoLoad,06,fbdev fb font) + FILES+=$(LINUX_DIR)/arch/x86/video/video-common.ko + AUTOLOAD:=$(call AutoLoad,06,video-common fb font) endef $(eval $(call KernelPackage,fb)) @@ -192,13 +191,24 @@ endef $(eval $(call KernelPackage,fb-cfb-imgblt)) +define KernelPackage/fb-io-fops + SUBMENU:=$(VIDEO_MENU) + TITLE:=Fbdev helpers for framebuffers in I/O memory + HIDDEN:=1 + KCONFIG:=CONFIG_FB_IOMEM_FOPS + FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb_io_fops.ko + AUTOLOAD:=$(call AutoLoad,07,fb_io_fops) +endef + +$(eval $(call KernelPackage,fb-io-fops)) + + define KernelPackage/fb-sys-fops SUBMENU:=$(VIDEO_MENU) TITLE:=Framebuffer software sys ops support DEPENDS:=+kmod-fb KCONFIG:= \ - CONFIG_FB_SYS_FOPS@lt6.12 \ - CONFIG_FB_SYSMEM_FOPS@ge6.12 + CONFIG_FB_SYSMEM_FOPS FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb_sys_fops.ko AUTOLOAD:=$(call AutoLoad,07,fb_sys_fops) endef @@ -334,6 +344,7 @@ define KernelPackage/drm-buddy SUBMENU:=$(VIDEO_MENU) TITLE:=A page based buddy allocator DEPENDS:=@DISPLAY_SUPPORT +kmod-drm + HIDDEN:=1 KCONFIG:=CONFIG_DRM_BUDDY FILES:= $(LINUX_DIR)/drivers/gpu/drm/drm_buddy.ko AUTOLOAD:=$(call AutoProbe,drm_buddy) @@ -349,6 +360,7 @@ define KernelPackage/drm-display-helper SUBMENU:=$(VIDEO_MENU) TITLE:=DRM helpers for display adapters drivers DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper +kmod-cec-core + HIDDEN:=1 KCONFIG:=CONFIG_DRM_DISPLAY_HELPER FILES:=$(LINUX_DIR)/drivers/gpu/drm/display/drm_display_helper.ko AUTOLOAD:=$(call AutoProbe,drm_display_helper) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index bdd73a5c9..74c5eabaf 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -265,9 +265,6 @@ popd # Luci diagnostics.js sed -i "s/openwrt.org/www.qq.com/g" feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/diagnostics.js -# luci - disable wireless WPA3 -[ "$platform" = "bcm53xx" ] && sed -i -e '/if (has_ap_sae || has_sta_sae) {/{N;N;N;N;d;}' feeds/luci/modules/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js - # luci-compat - remove extra line breaks from description sed -i '/
/d' feeds/luci/modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm @@ -302,10 +299,6 @@ mkdir -p files/etc/sysctl.d curl -so files/etc/sysctl.d/10-default.conf $mirror/openwrt/files/etc/sysctl.d/10-default.conf curl -so files/etc/sysctl.d/15-vm-swappiness.conf $mirror/openwrt/files/etc/sysctl.d/15-vm-swappiness.conf curl -so files/etc/sysctl.d/16-udp-buffer-size.conf $mirror/openwrt/files/etc/sysctl.d/16-udp-buffer-size.conf -if [ "$platform" = "bcm53xx" ]; then - mkdir -p files/etc/hotplug.d/block - curl -so files/etc/hotplug.d/block/20-usbreset $mirror/openwrt/files/etc/hotplug.d/block/20-usbreset -fi # NTP sed -i 's/0.openwrt.pool.ntp.org/ntp1.aliyun.com/g' package/base-files/files/bin/config_generate diff --git a/tags/v25 b/tags/v25 index 925018892..df030b74a 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.0-rc5 +25.12.0 From 1e9803fb12d4d8b77622702340f3367359efc83d Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 7 Mar 2026 23:15:05 +0800 Subject: [PATCH 373/425] script: cleanup script Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 5 ----- openwrt/scripts/05-fix-source.sh | 7 ------- 2 files changed, 12 deletions(-) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 74c5eabaf..6ed5d1fde 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -277,11 +277,6 @@ popd rm -rf package/system/urngd git clone https://$github/sbwml/package_system_urngd package/system/urngd -# zlib - 1.3 -ZLIB_VERSION=1.3.1 -ZLIB_HASH=38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32 -sed -ri "s/(PKG_VERSION:=)[^\"]*/\1$ZLIB_VERSION/;s/(PKG_HASH:=)[^\"]*/\1$ZLIB_HASH/" package/libs/zlib/Makefile - # profile sed -i 's#\\u@\\h:\\w\\\$#\\[\\e[32;1m\\][\\u@\\h\\[\\e[0m\\] \\[\\033[01;34m\\]\\W\\[\\033[00m\\]\\[\\e[32;1m\\]]\\[\\e[0m\\]\\\$#g' package/base-files/files/etc/profile sed -ri 's/(export PATH=")[^"]*/\1%PATH%:\/opt\/bin:\/opt\/sbin:\/opt\/usr\/bin:\/opt\/usr\/sbin/' package/base-files/files/etc/profile diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index d49f32b77..242db50e2 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -1,12 +1,5 @@ #!/bin/bash -# odhcp6c-2025-10 -rm -rf package/network/ipv6/odhcp6c -git clone https://$gitea/sbwml/package_network_ipv6_odhcp6c package/network/ipv6/odhcp6c -#if [ "$branch" = "v25.12.0-rc1" ]; then -# curl -s $mirror/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch | patch -p1 -#fi - if [ "$KERNEL_CLANG_LTO" = "y" ]; then # linux-atm curl -s $mirror/openwrt/patch/packages-patches/clang/linux-atm/openwrt-fix-build-with-clang.patch | patch -p1 From 3e4981fe8288c3ee3548940a4b94574c832e3c66 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 8 Mar 2026 01:41:40 +0800 Subject: [PATCH 374/425] linux-6.18: bump to 6.18.16 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 61180cebd..071d198b6 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .15 -LINUX_KERNEL_HASH-6.18.15 = 7c716216c3c4134ed0de69195701e677577bbcdd3979f331c182acd06bf2f170 +LINUX_VERSION-6.18 = .16 +LINUX_KERNEL_HASH-6.18.16 = 4f21c01f4d04c1d1b3ed794153f8900802c92497be620b07c4869530f2d28ee3 From ba7d68116fc610216a9bbca1c4b2ec0f3647f46f Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 10 Mar 2026 22:03:41 +0800 Subject: [PATCH 375/425] config-common: update config Signed-off-by: sbwml --- openwrt/25-config-common | 2 -- openwrt/25-config-minimal-common | 9 --------- openwrt/25-config-std-common | 1 - 3 files changed, 12 deletions(-) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index 8edaeba7b..cb92a14ec 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -79,7 +79,6 @@ CONFIG_NGINX_STREAM_REAL_IP=y CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y -CONFIG_PACKAGE_luci-app-aria2=y CONFIG_PACKAGE_luci-app-autoreboot=y # CONFIG_PACKAGE_luci-app-bandix is not set CONFIG_PACKAGE_luci-app-commands=y @@ -111,7 +110,6 @@ CONFIG_PACKAGE_luci-app-watchcat=y CONFIG_PACKAGE_luci-app-webdav=y CONFIG_PACKAGE_luci-app-wolplus=y CONFIG_PACKAGE_luci-app-zerotier=y -CONFIG_PACKAGE_ariang-nginx=y ### ImmortalWrt Proxy - nft CONFIG_PACKAGE_luci-app-homeproxy=y diff --git a/openwrt/25-config-minimal-common b/openwrt/25-config-minimal-common index cf7b5b741..7e5378248 100644 --- a/openwrt/25-config-minimal-common +++ b/openwrt/25-config-minimal-common @@ -65,18 +65,12 @@ CONFIG_NGINX_STREAM_REAL_IP=y ### APPS CONFIG_PACKAGE_luci-app-autoreboot=y CONFIG_PACKAGE_luci-app-cpufreq=y -CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-filemanager=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y -### DDNS Scripts -CONFIG_PACKAGE_ddns-scripts=y -CONFIG_PACKAGE_ddns-scripts-aliyun=y -CONFIG_PACKAGE_ddns-scripts-dnspod=y - ### OpenSSL CONFIG_OPENSSL_ENGINE=y CONFIG_OPENSSL_OPTIMIZE_SPEED=y @@ -131,9 +125,6 @@ CONFIG_PACKAGE_kmod-usb2=y CONFIG_PACKAGE_kmod-usb3=y CONFIG_PACKAGE_kmod-veth=y -### Kernel Modules - out-of-tree driver -CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y - ### Kernel Modules - USB WiFi Adapter CONFIG_PACKAGE_kmod-mt7921u=y diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index 87ff29360..cd583deac 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -74,7 +74,6 @@ CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y -CONFIG_PACKAGE_luci-app-eqos=y CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-frpc=y CONFIG_PACKAGE_luci-app-mosdns=y From 3f422b2c33047b7f47e12ca6c6a96322598e3580 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 10 Mar 2026 22:04:20 +0800 Subject: [PATCH 376/425] luci-app-package-manager: fix upload-install (25.10.0) Signed-off-by: sbwml --- ...app-package-manager-support-installing-uploaded.patch | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch index 09a6d722a..4798610cc 100644 --- a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch +++ b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch @@ -12,7 +12,7 @@ Signed-off-by: sbwml 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js -index 48476dbe16..6afa5895cc 100644 +index 48476db..6afa589 100644 --- a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js +++ b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js @@ -1086,7 +1086,7 @@ function handleUpload(ev) @@ -25,7 +25,7 @@ index 48476dbe16..6afa5895cc 100644 'click': function(ev) { handlePkg(ev).finally(function() { diff --git a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call -index 3a4175783a..7fa58f9060 100755 +index 3a41757..7fa58f9 100755 --- a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call +++ b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call @@ -27,7 +27,7 @@ case "$action" in @@ -48,14 +48,15 @@ index 3a4175783a..7fa58f9060 100755 action="update" ;; diff --git a/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json b/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json -index 8d551860e8..31eb0b6a84 100644 +index 8d55186..6ec7947 100644 --- a/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json +++ b/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json -@@ -20,6 +20,7 @@ +@@ -20,6 +20,8 @@ "file": { "/usr/libexec/package-manager-call install": [ "exec" ], "/usr/libexec/package-manager-call install *": [ "exec" ], + "/usr/libexec/package-manager-call install-upload": [ "exec" ], ++ "/usr/libexec/package-manager-call install-upload *": [ "exec" ], "/usr/libexec/package-manager-call remove *": [ "exec" ], "/usr/libexec/package-manager-call update": [ "exec" ], "/usr/libexec/package-manager-call upgrade": [ "exec" ], From 055a476c8ec11b270dabde5282d658111e8b864b Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 10 Mar 2026 22:04:56 +0800 Subject: [PATCH 377/425] x86: update config Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/x86/64/config-6.18 | 180 +++++++++--------- .../x86/base-files/etc/board.d/02_network | 66 +++++++ openwrt/patch/openwrt-6.x/x86/config-6.18 | 101 +++++----- 3 files changed, 211 insertions(+), 136 deletions(-) diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.18 b/openwrt/patch/openwrt-6.x/x86/64/config-6.18 index 996c787f7..7bfb6e30a 100644 --- a/openwrt/patch/openwrt-6.x/x86/64/config-6.18 +++ b/openwrt/patch/openwrt-6.x/x86/64/config-6.18 @@ -1,5 +1,6 @@ CONFIG_64BIT=y # CONFIG_ACER_WMI is not set +CONFIG_ACPI=y CONFIG_ACPI_AC=y CONFIG_ACPI_BATTERY=y # CONFIG_ACPI_BGRT is not set @@ -8,8 +9,8 @@ CONFIG_ACPI_BUTTON=y CONFIG_ACPI_CONTAINER=y CONFIG_ACPI_CPPC_LIB=y CONFIG_ACPI_CPU_FREQ_PSS=y -# CONFIG_ACPI_DEBUGGER is not set # CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_DEBUGGER is not set # CONFIG_ACPI_DOCK is not set # CONFIG_ACPI_DPTF is not set # CONFIG_ACPI_EC_DEBUGFS is not set @@ -26,33 +27,32 @@ CONFIG_ACPI_PCC=y # CONFIG_ACPI_PCI_SLOT is not set # CONFIG_ACPI_PFRUT is not set CONFIG_ACPI_PRMT=y +CONFIG_ACPI_PROCESSOR=y # CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set CONFIG_ACPI_PROCESSOR_CSTATE=y CONFIG_ACPI_PROCESSOR_IDLE=y -CONFIG_ACPI_PROCESSOR=y CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y # CONFIG_ACPI_SBS is not set CONFIG_ACPI_SPCR_TABLE=y CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y # CONFIG_ACPI_TAD is not set -CONFIG_ACPI_THERMAL_LIB=y CONFIG_ACPI_THERMAL=y +CONFIG_ACPI_THERMAL_LIB=y # CONFIG_ACPI_TOSHIBA is not set CONFIG_ACPI_VIDEO=y CONFIG_ACPI_VIOT=y CONFIG_ACPI_WMI=y -CONFIG_ACPI=y # CONFIG_ACRN_GUEST is not set # CONFIG_ADDRESS_MASKING is not set # CONFIG_ADV_SWBUTTON is not set +CONFIG_AGP=y # CONFIG_AGP_AMD64 is not set CONFIG_AGP_INTEL=y # CONFIG_AGP_SIS is not set # CONFIG_AGP_VIA is not set -CONFIG_AGP=y # CONFIG_AMD_HSMP is not set -CONFIG_AMD_IOMMU_V2=y CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y # CONFIG_AMD_PMC is not set # CONFIG_AMD_PMF is not set # CONFIG_AMD_PTDMA is not set @@ -72,10 +72,10 @@ CONFIG_AUDIT_ARCH=y CONFIG_AUXILIARY_BUS=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BALLOON_COMPACTION=y -CONFIG_BLK_DEV_BSG_COMMON=y CONFIG_BLK_DEV_BSGLIB=y -CONFIG_BLK_DEV_INTEGRITY_T10=y +CONFIG_BLK_DEV_BSG_COMMON=y CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y CONFIG_BLK_DEV_NVME=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_MQ_VIRTIO=y @@ -84,12 +84,13 @@ CONFIG_BOOT_VESA_SUPPORT=y CONFIG_BTT=y CONFIG_CALL_DEPTH_TRACKING=y CONFIG_CALL_PADDING=y -# CONFIG_CALL_THUNKS_DEBUG is not set CONFIG_CALL_THUNKS=y +# CONFIG_CALL_THUNKS_DEBUG is not set CONFIG_CDROM=y +CONFIG_CGROUP_HUGETLB=y CONFIG_CONNECTOR=y -CONFIG_CONTEXT_TRACKING_IDLE=y CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=y CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPU_IBPB_ENTRY=y @@ -98,8 +99,8 @@ CONFIG_CPU_IBRS_ENTRY=y CONFIG_CPU_RMAP=y CONFIG_CPU_SRSO=y CONFIG_CPU_UNRET_ENTRY=y -CONFIG_CRC64_ROCKSOFT=y CONFIG_CRC64=y +CONFIG_CRC64_ROCKSOFT=y CONFIG_CRC_T10DIF=y CONFIG_CRYPTO_AES_NI_INTEL=y CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y @@ -114,8 +115,8 @@ CONFIG_CRYPTO_BLAKE2S_X86=y # CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set # CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set CONFIG_CRYPTO_CRC64_ROCKSOFT=y -# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set CONFIG_CRYPTO_CRCT10DIF=y +# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set CONFIG_CRYPTO_CRYPTD=y # CONFIG_CRYPTO_DES3_EDE_X86_64 is not set CONFIG_CRYPTO_ECB=y @@ -135,13 +136,14 @@ CONFIG_CRYPTO_SIMD=y # CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set # CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set # CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set -# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set # CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set CONFIG_CRYPTO_XTS=y +CONFIG_DMAR_TABLE=y CONFIG_DMA_ACPI=y CONFIG_DMA_OPS=y -CONFIG_DMAR_TABLE=y CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DRM=y # CONFIG_DRM_AMDGPU_WERROR is not set # CONFIG_DRM_AMD_SECURE_DISPLAY is not set CONFIG_DRM_BOCHS=y @@ -157,16 +159,17 @@ CONFIG_DRM_GEM_SHMEM_HELPER=y # CONFIG_DRM_HYPERV is not set CONFIG_DRM_KMS_HELPER=y CONFIG_DRM_MIPI_DSI=y +CONFIG_DRM_PANEL=y CONFIG_DRM_PANEL_BRIDGE=y CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y -CONFIG_DRM_PANEL=y -CONFIG_DRM_TTM_HELPER=y CONFIG_DRM_TTM=y -CONFIG_DRM_VIRTIO_GPU_KMS=y +CONFIG_DRM_TTM_HELPER=y CONFIG_DRM_VIRTIO_GPU=y +CONFIG_DRM_VIRTIO_GPU_KMS=y CONFIG_DRM_VRAM_HELPER=y -CONFIG_DRM=y CONFIG_DYNAMIC_PHYSICAL_MASK=y +CONFIG_EFI=y +CONFIG_EFIVAR_FS=m # CONFIG_EFI_BOOTLOADER_CONTROL is not set # CONFIG_EFI_CAPSULE_LOADER is not set # CONFIG_EFI_COCO_SECRET is not set @@ -186,12 +189,11 @@ CONFIG_EFI_RUNTIME_WRAPPERS=y # CONFIG_EFI_SECRET is not set CONFIG_EFI_STUB=y # CONFIG_EFI_TEST is not set -CONFIG_EFIVAR_FS=m # CONFIG_EFI_VARS is not set -# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set # CONFIG_EFI_VARS_PSTORE is not set -CONFIG_EFI=y +# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set CONFIG_FAILOVER=y +CONFIG_FB=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_IMAGEBLIT=y @@ -205,21 +207,20 @@ CONFIG_FB_IOMEM_FOPS=y CONFIG_FB_IOMEM_HELPERS=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_SIMPLE=y +CONFIG_FB_SYSMEM_HELPERS=y +CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y CONFIG_FB_SYS_COPYAREA=y CONFIG_FB_SYS_FILLRECT=y CONFIG_FB_SYS_FOPS=y CONFIG_FB_SYS_IMAGEBLIT=y -CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y -CONFIG_FB_SYSMEM_HELPERS=y CONFIG_FB_TILEBLITTING=y # CONFIG_FB_VESA is not set -CONFIG_FB=y CONFIG_FONT_8x16=y CONFIG_FONT_8x8=y CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FREEZER=y CONFIG_FUSION_SAS=y CONFIG_FW_CACHE=y @@ -234,9 +235,9 @@ CONFIG_GENERIC_PINCONF=y # CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT is not set # CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set # CONFIG_GOOGLE_SMI is not set +CONFIG_GPIOLIB_IRQCHIP=y CONFIG_GPIO_ACPI=y CONFIG_GPIO_ICH=y -CONFIG_GPIOLIB_IRQCHIP=y CONFIG_GPIO_SCH=y CONFIG_GUEST_PERF_EVENTS=y CONFIG_HALTPOLL_CPUIDLE=y @@ -246,35 +247,37 @@ CONFIG_HIBERNATE_CALLBACKS=y CONFIG_HID_BATTERY_STRENGTH=y CONFIG_HID_GENERIC=y CONFIG_HID_HYPERV_MOUSE=y +CONFIG_HOTPLUG_CORE_SYNC=y CONFIG_HOTPLUG_CORE_SYNC_DEAD=y CONFIG_HOTPLUG_CORE_SYNC_FULL=y -CONFIG_HOTPLUG_CORE_SYNC=y CONFIG_HOTPLUG_CPU=y CONFIG_HOTPLUG_PARALLEL=y -# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set # CONFIG_HOTPLUG_PCI_PCIE is not set # CONFIG_HOTPLUG_PCI_SHPC is not set -CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_SMT=y CONFIG_HOTPLUG_SPLIT_STARTUP=y -# CONFIG_HP_ACCEL is not set -CONFIG_HPET_MMAP=y CONFIG_HPET=y +CONFIG_HPET_MMAP=y +# CONFIG_HP_ACCEL is not set # CONFIG_HUAWEI_WMI is not set +CONFIG_HUGETLBFS=y CONFIG_HVC_DRIVER=y CONFIG_HVC_IRQ=y -CONFIG_HVC_XEN_FRONTEND=y CONFIG_HVC_XEN=y -CONFIG_HWMON_VID=y +CONFIG_HVC_XEN_FRONTEND=y CONFIG_HWMON=y +CONFIG_HWMON_VID=y CONFIG_HW_RANDOM_AMD=y CONFIG_HW_RANDOM_INTEL=y CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HYPERV=y +CONFIG_HYPERVISOR_GUEST=y CONFIG_HYPERV_BALLOON=y CONFIG_HYPERV_IOMMU=y -CONFIG_HYPERVISOR_GUEST=y CONFIG_HYPERV_KEYBOARD=y CONFIG_HYPERV_NET=y CONFIG_HYPERV_STORAGE=y @@ -283,13 +286,12 @@ CONFIG_HYPERV_TIMER=y CONFIG_HYPERV_UTILS=y # CONFIG_HYPERV_VSOCKETS is not set # CONFIG_HYPERV_VTL_MODE is not set -CONFIG_HYPERV=y +CONFIG_I2C=y CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_AMD_MP2 is not set CONFIG_I2C_BOARDINFO=y # CONFIG_I2C_HID_ACPI is not set # CONFIG_I2C_MULTI_INSTANTIATE is not set -CONFIG_I2C=y # CONFIG_I8K is not set # CONFIG_IA32_EMULATION is not set CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 @@ -297,15 +299,15 @@ CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y CONFIG_INTEL_GTT=y CONFIG_INTEL_IDLE=y -# CONFIG_INTEL_IDXD_COMPAT is not set # CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IDXD_COMPAT is not set # CONFIG_INTEL_IFS is not set +CONFIG_INTEL_IOMMU=y # CONFIG_INTEL_IOMMU_DEFAULT_ON is not set CONFIG_INTEL_IOMMU_FLOPPY_WA=y CONFIG_INTEL_IOMMU_PERF_EVENTS=y # CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set # CONFIG_INTEL_IOMMU_SVM is not set -CONFIG_INTEL_IOMMU=y # CONFIG_INTEL_IPS is not set # CONFIG_INTEL_MEI_GSC_PROXY is not set # CONFIG_INTEL_MEI_HDCP is not set @@ -325,20 +327,20 @@ CONFIG_INTEL_TDX_GUEST=y # CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set # CONFIG_INTEL_WMI_THUNDERBOLT is not set CONFIG_INTERVAL_TREE=y +# CONFIG_IOMMUFD is not set CONFIG_IOMMU_API=y -# CONFIG_IOMMU_DEBUGFS is not set # CONFIG_IOMMU_DEBUG is not set +# CONFIG_IOMMU_DEBUGFS is not set CONFIG_IOMMU_DEFAULT_DMA_LAZY=y # CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set # CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set CONFIG_IOMMU_DMA=y -# CONFIG_IOMMUFD is not set CONFIG_IOMMU_HELPER=y -CONFIG_IOMMU_IO_PGTABLE=y CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_IO_PGTABLE=y CONFIG_IOMMU_SUPPORT=y -# CONFIG_IOSF_MBI_DEBUG is not set CONFIG_IOSF_MBI=y +# CONFIG_IOSF_MBI_DEBUG is not set # CONFIG_IPU_BRIDGE is not set CONFIG_IRQ_MSI_IOMMU=y CONFIG_IRQ_REMAP=y @@ -367,16 +369,22 @@ CONFIG_MEMREGION=y CONFIG_MFD_CORE=y # CONFIG_MFD_INTEL_LPSS_ACPI is not set # CONFIG_MFD_INTEL_PMC_BXT is not set +CONFIG_MITIGATION_CALL_DEPTH_TRACKING=y +CONFIG_MITIGATION_ITS=y +CONFIG_MITIGATION_SLS=y +CONFIG_MITIGATION_SRBDS=y +CONFIG_MITIGATION_SRSO=y +CONFIG_MITIGATION_UNRET_ENTRY=y +CONFIG_MMC=y CONFIG_MMC_BLOCK=y CONFIG_MMC_CQHCI=y CONFIG_MMC_RICOH_MMC=y +CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ACPI=y CONFIG_MMC_SDHCI_IO_ACCESSORS=y CONFIG_MMC_SDHCI_PCI=y # CONFIG_MMC_SDHCI_PLTFM is not set -CONFIG_MMC_SDHCI=y # CONFIG_MMC_WBSD is not set -CONFIG_MMC=y CONFIG_MMU_NOTIFIER=y CONFIG_MODULES_USE_ELF_RELA=y # CONFIG_MPSC is not set @@ -391,10 +399,7 @@ CONFIG_NET_FAILOVER=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NET_PTP_CLASSIFY=y # CONFIG_NITRO_ENCLAVES is not set -CONFIG_NR_CPUS=512 -CONFIG_NR_CPUS_DEFAULT=64 -CONFIG_NR_CPUS_RANGE_BEGIN=2 -CONFIG_NR_CPUS_RANGE_END=512 +# CONFIG_NO_PAGE_MAPCOUNT is not set # CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set CONFIG_NVME_CORE=y CONFIG_NVME_HWMON=y @@ -405,11 +410,11 @@ CONFIG_P2SB=y CONFIG_PADATA=y CONFIG_PAGE_REPORTING=y CONFIG_PAGE_TABLE_ISOLATION=y +CONFIG_PARAVIRT=y CONFIG_PARAVIRT_CLOCK=y # CONFIG_PARAVIRT_DEBUG is not set CONFIG_PARAVIRT_SPINLOCKS=y CONFIG_PARAVIRT_XXL=y -CONFIG_PARAVIRT=y CONFIG_PATA_AMD=y CONFIG_PATA_ATIIXP=y CONFIG_PATA_MPIIX=y @@ -419,23 +424,25 @@ CONFIG_PATA_VIA=y CONFIG_PCC=y # CONFIG_PCENGINES_APU2 is not set CONFIG_PCIEAER=y +CONFIG_PCIEASPM=y CONFIG_PCIEASPM_DEFAULT=y # CONFIG_PCIEASPM_PERFORMANCE is not set # CONFIG_PCIEASPM_POWERSAVE is not set # CONFIG_PCIEASPM_POWER_SUPERSAVE is not set -CONFIG_PCIEASPM=y -CONFIG_PCIE_PME=y CONFIG_PCIEPORTBUS=y -CONFIG_PCI_HYPERV_INTERFACE=y +CONFIG_PCIE_PME=y CONFIG_PCI_HYPERV=y +CONFIG_PCI_HYPERV_INTERFACE=y # CONFIG_PCI_MMCONFIG is not set CONFIG_PCI_PASID=y CONFIG_PCI_PRI=y CONFIG_PCI_XEN=y +CONFIG_PERSISTENT_HUGE_ZERO_FOLIO=y CONFIG_PER_VMA_LOCK=y CONFIG_PGTABLE_LEVELS=4 -CONFIG_PHYS_ADDR_T_64BIT=y CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PINCTRL=y CONFIG_PINCTRL_ALDERLAKE=y CONFIG_PINCTRL_BAYTRAIL=y CONFIG_PINCTRL_BROXTON=y @@ -453,21 +460,20 @@ CONFIG_PINCTRL_LYNXPOINT=y CONFIG_PINCTRL_METEORLAKE=y CONFIG_PINCTRL_SUNRISEPOINT=y CONFIG_PINCTRL_TIGERLAKE=y -CONFIG_PINCTRL=y -CONFIG_PM_CLK=y +CONFIG_PM=y # CONFIG_PMIC_OPREGION is not set -CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_CLK=y CONFIG_PM_SLEEP=y -CONFIG_PM=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PNP=y CONFIG_PNPACPI=y CONFIG_PNP_DEBUG_MESSAGES=y -CONFIG_PNP=y CONFIG_PPS=y CONFIG_PREFIX_SYMBOLS=y CONFIG_PROC_EVENTS=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PTP_1588_CLOCK_KVM=y CONFIG_PTP_1588_CLOCK_VMW=y -CONFIG_PTP_1588_CLOCK=y CONFIG_PVH=y CONFIG_QUEUED_RWLOCKS=y CONFIG_QUEUED_SPINLOCKS=y @@ -482,8 +488,8 @@ CONFIG_RWSEM_SPIN_ON_OWNER=y # CONFIG_SAMSUNG_Q10 is not set CONFIG_SATA_AHCI=y # CONFIG_SCHED_CORE is not set -CONFIG_SCHED_MC_PRIO=y CONFIG_SCHED_MC=y +CONFIG_SCHED_MC_PRIO=y CONFIG_SCHED_SMT=y CONFIG_SCSI_SAS_ATTRS=y CONFIG_SCSI_VIRTIO=y @@ -514,17 +520,17 @@ CONFIG_SMP=y # CONFIG_SND_SOC_AMD_RPL_ACP6x is not set # CONFIG_SND_SOC_INTEL_AVS is not set CONFIG_SOCK_RX_QUEUE_MAPPING=y +CONFIG_SPARSEMEM=y CONFIG_SPARSEMEM_EXTREME=y -CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y # CONFIG_SPARSEMEM_VMEMMAP is not set -CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y CONFIG_STACK_VALIDATION=y -CONFIG_SWIOTLB_XEN=y CONFIG_SWIOTLB=y +CONFIG_SWIOTLB_XEN=y CONFIG_SYNC_FILE=y CONFIG_SYSFB=y -CONFIG_SYS_HYPERVISOR=y # CONFIG_SYSTEM76_ACPI is not set +CONFIG_SYS_HYPERVISOR=y # CONFIG_TDX_GUEST_DRIVER is not set CONFIG_THERMAL_ACPI=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -533,6 +539,10 @@ CONFIG_THERMAL_WRITABLE_TRIPS=y # CONFIG_THINKPAD_LMI is not set # CONFIG_TOSHIBA_BT_RFKILL is not set # CONFIG_TOSHIBA_WMI is not set +CONFIG_TRANSPARENT_HUGEPAGE=y +# CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS is not set +# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set +CONFIG_TRANSPARENT_HUGEPAGE_NEVER=y CONFIG_TREE_RCU=y CONFIG_TREE_SRCU=y # CONFIG_UACCE is not set @@ -544,49 +554,49 @@ CONFIG_USB_STORAGE=y CONFIG_VIDEO_CMDLINE=y # CONFIG_VIDEO_IPU3_CIO2 is not set CONFIG_VIDEO_NOMODESET=y -CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO=y CONFIG_VIRTIO_ANCHOR=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_BLK=y CONFIG_VIRTIO_CONSOLE=y CONFIG_VIRTIO_DMA_SHARED_BUFFER=y CONFIG_VIRTIO_IOMMU=y -CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_PCI_LEGACY=y -CONFIG_VIRTIO_PCI_LIB_LEGACY=y CONFIG_VIRTIO_PCI_LIB=y -CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI_LIB_LEGACY=y # CONFIG_VIRTIO_PMEM is not set -CONFIG_VIRTIO_VSOCKETS_COMMON=y # CONFIG_VIRTIO_VSOCKETS is not set -CONFIG_VIRTIO=y +CONFIG_VIRTIO_VSOCKETS_COMMON=y +CONFIG_VIRT_DRIVERS=y CONFIG_VMAP_PFN=y CONFIG_VMAP_STACK=y # CONFIG_VMD is not set CONFIG_VMGENID=y CONFIG_VMWARE_BALLOON=y CONFIG_VMWARE_PVSCSI=y -CONFIG_VMWARE_VMCI_VSOCKETS=y CONFIG_VMWARE_VMCI=y +CONFIG_VMWARE_VMCI_VSOCKETS=y CONFIG_VMXNET3=y -CONFIG_VSOCKETS_LOOPBACK=y CONFIG_VSOCKETS=y +CONFIG_VSOCKETS_LOOPBACK=y CONFIG_VT_CONSOLE_SLEEP=y CONFIG_WATCHDOG_CORE=y # CONFIG_WIRELESS_HOTKEY is not set # CONFIG_WMI_BMOF is not set # CONFIG_X86_5LEVEL is not set -CONFIG_X86_64_SMP=y CONFIG_X86_64=y -# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +CONFIG_X86_64_SMP=y CONFIG_X86_ACPI_CPUFREQ=y +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set CONFIG_X86_AMD_FREQ_SENSITIVITY=y CONFIG_X86_AMD_PLATFORM_DEVICE=y +CONFIG_X86_AMD_PSTATE=y CONFIG_X86_AMD_PSTATE_DEFAULT_MODE=3 # CONFIG_X86_AMD_PSTATE_UT is not set -CONFIG_X86_AMD_PSTATE=y CONFIG_X86_CPUID=y CONFIG_X86_DIRECT_GBPAGES=y CONFIG_X86_HV_CALLBACK_VECTOR=y @@ -605,11 +615,13 @@ CONFIG_X86_PM_TIMER=y # CONFIG_X86_USER_SHADOW_STACK is not set # CONFIG_X86_VSYSCALL_EMULATION is not set CONFIG_X86_X2APIC=y -# CONFIG_X86_X32_ABI is not set # CONFIG_X86_X32 is not set +# CONFIG_X86_X32_ABI is not set +CONFIG_XEN=y +CONFIG_XENFS=y CONFIG_XEN_512GB=y -CONFIG_XEN_ACPI_PROCESSOR=y CONFIG_XEN_ACPI=y +CONFIG_XEN_ACPI_PROCESSOR=y CONFIG_XEN_AUTO_XLATE=y # CONFIG_XEN_BACKEND is not set CONFIG_XEN_BALLOON=y @@ -620,7 +632,6 @@ CONFIG_XEN_DEV_EVTCHN=y CONFIG_XEN_DOM0=y CONFIG_XEN_EFI=y CONFIG_XEN_FBDEV_FRONTEND=y -CONFIG_XENFS=y CONFIG_XEN_GNTDEV=y CONFIG_XEN_GRANT_DEV_ALLOC=y CONFIG_XEN_GRANT_DMA_OPS=y @@ -629,25 +640,24 @@ CONFIG_XEN_HAVE_VPMU=y # CONFIG_XEN_MCE_LOG is not set CONFIG_XEN_NETDEV_FRONTEND=y CONFIG_XEN_PCIDEV_FRONTEND=y -# CONFIG_XEN_PRIVCMD_IRQFD is not set CONFIG_XEN_PRIVCMD=y -CONFIG_XEN_PV_DOM0=y +# CONFIG_XEN_PRIVCMD_IRQFD is not set +CONFIG_XEN_PV=y +CONFIG_XEN_PVH=y +CONFIG_XEN_PVHVM=y CONFIG_XEN_PVHVM_GUEST=y CONFIG_XEN_PVHVM_SMP=y -CONFIG_XEN_PVHVM=y -CONFIG_XEN_PVH=y +CONFIG_XEN_PV_DOM0=y CONFIG_XEN_PV_MSR_SAFE=y CONFIG_XEN_PV_SMP=y -CONFIG_XEN_PV=y CONFIG_XEN_SAVE_RESTORE=y CONFIG_XEN_SCSI_FRONTEND=y CONFIG_XEN_SYMS=y CONFIG_XEN_SYS_HYPERVISOR=y -# CONFIG_XEN_VIRTIO_FORCE_GRANT is not set CONFIG_XEN_VIRTIO=y +# CONFIG_XEN_VIRTIO_FORCE_GRANT is not set CONFIG_XEN_WDT=y CONFIG_XEN_XENBUS_FRONTEND=y -CONFIG_XEN=y # CONFIG_XIAOMI_WMI is not set CONFIG_XPS=y # CONFIG_YOGABOOK is not set diff --git a/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network b/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network index f2ae8f225..c7b3780fa 100644 --- a/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network +++ b/openwrt/patch/openwrt-6.x/x86/base-files/etc/board.d/02_network @@ -35,6 +35,63 @@ cisco-mx100-hw) ucidef_set_network_device_path "eth11" "pci0000:00/0000:00:01.1/0000:02:00.2" ucidef_set_interfaces_lan_wan "mgmt eth2 eth3 eth4 eth5 eth6 eth7 eth8 eth9 eth10 eth11" "wan" ;; +dell-emc-edge620) + ucidef_set_interfaces_lan_wan "eth0 eth1 eth2 eth3 eth7" "eth6" + ;; +gowin-solution-co-ltd-gw-mb-u01) + ucidef_set_network_device_path "eth1" "pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:04:00.0" + ucidef_set_network_device_path "eth2" "pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:00.0/0000:03:00.0" + ucidef_set_network_device_path "eth3" "pci0000:00/0000:00:1c.2/0000:07:00.0/0000:08:02.0/0000:0a:00.0" + ucidef_set_network_device_path "eth4" "pci0000:00/0000:00:1c.2/0000:07:00.0/0000:08:00.0/0000:09:00.0" + ucidef_set_network_device_path "poe" "pci0000:00/0000:00:1c.2/0000:07:00.0/0000:08:06.0/0000:0b:00.0" + + sfp_device="pci0000:00/0000:00:1d.0" + sfp_device_path="/sys/devices/$sfp_device" + + pci_count="$(ls -d $sfp_device_path/0000:*:00.* 2>/dev/null | wc -l)" + if [ "$pci_count" -eq 2 ]; then + sfp_port1="$(basename $sfp_device_path/0000:*:00.1)" + sfp_port2="$(basename $sfp_device_path/0000:*:00.0)" + + ucidef_set_network_device_path "sfp1" "$sfp_device/$sfp_port1" + ucidef_set_network_device_path "sfp2" "$sfp_device/$sfp_port2" + elif [ "$pci_count" -eq 1 ]; then + sfp_port="$(basename $sfp_device_path/0000:*:00.0)" + + ucidef_set_network_device_path_port "sfp1" "$sfp_device/$sfp_port" "1" + ucidef_set_network_device_path_port "sfp2" "$sfp_device/$sfp_port" "0" + fi + + ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 poe" "sfp1 sfp2" + ;; +micro-computer-hk-tech-limited-ms-a2) + ucidef_set_network_device_path "lan1" "pci0000:00/0000:00:03.2/0000:04:00.0" + ucidef_set_network_device_path "lan2" "pci0000:00/0000:00:03.1/0000:03:00.0" + ucidef_set_network_device_path "sfp1" "pci0000:00/0000:00:02.1/0000:05:00.0" + ucidef_set_network_device_path "sfp2" "pci0000:00/0000:00:02.1/0000:05:00.1" + ucidef_set_interface_lan "lan1 lan2 sfp1 sfp2" + ;; +mellanox-technologies-ltd-msn2100) + ucidef_set_network_device_path "mgmt" "pci0000:00/0000:00:14.0" + ucidef_set_interface_lan "mgmt " + ucidef_set_interface_netdev_range "lan" "swp" "1" "16" + ;; +mellanox-technologies-ltd-msn2700) + ucidef_set_network_device_path "mgmt0" "pci0000:00/0000:00:19.0" + ucidef_set_network_device_path "mgmt1" "pci0000:00/0000:00:1c.6/0000:06:00.0" + ucidef_set_interface_lan "mgmt0 mgmt1 " + ucidef_set_interface_netdev_range "lan" "swp" "1" "32" + ;; +mellanox-technologies-ltd-msn3420) + ucidef_set_network_device_path "mgmt" "pci0000:00/0000:00:1c.7/0000:09:00.0" + ucidef_set_interface_lan "mgmt " + ucidef_set_interface_netdev_range "lan" "swp" "1" "60" + ;; +mellanox-technologies-ltd-msn3700) + ucidef_set_network_device_path "mgmt" "pci0000:00/0000:00:1c.7/0000:09:00.0" + ucidef_set_interface_lan "mgmt " + ucidef_set_interface_netdev_range "lan" "swp" "1" "32" + ;; pc-engines-apu1|pc-engines-apu2|pc-engines-apu3) ucidef_set_interfaces_lan_wan "eth1 eth2" "eth0" ;; @@ -68,10 +125,19 @@ sophos-sg-135r2|sophos-xg-135r2| \ sophos-sg-135wr2|sophos-xg-135wr2) ucidef_set_interfaces_lan_wan "eth0 eth2 eth3 eth4 eth5 eth6 eth7" "eth1" ;; +sophos-sg-125r3|sophos-xg-125r3| \ +sophos-sg-125wr3|sophos-xg-125wr3| \ sophos-sg-135r3|sophos-xg-135r3| \ sophos-sg-135wr3|sophos-xg-135wr3) ucidef_set_interfaces_lan_wan "eth0 eth1 eth2 eth3 eth5 eth7 eth8" "eth6" ;; +sophos-sg-210r3|sophos-xg-210r3| \ +sophos-sg-230r2|sophox-xg-230r2) + ucidef_set_interfaces_lan_wan "eth0 eth2 eth3 eth4 eth5" "eth1" + ;; +supermicro-sys-e302-9d) + ucidef_set_interface_lan "eth0 eth1 eth2 eth3 eth4 eth5 eth6 eth7" + ;; traverse-technologies-geos) ucidef_set_interface_lan "eth0 eth1" ucidef_add_atm_bridge "0" "35" "llc" "bridged" diff --git a/openwrt/patch/openwrt-6.x/x86/config-6.18 b/openwrt/patch/openwrt-6.x/x86/config-6.18 index 55e3b043e..9065a3023 100644 --- a/openwrt/patch/openwrt-6.x/x86/config-6.18 +++ b/openwrt/patch/openwrt-6.x/x86/config-6.18 @@ -1,7 +1,7 @@ # CONFIG_60XX_WDT is not set # CONFIG_64BIT is not set -CONFIG_ACPI_EC=y # CONFIG_ACPI is not set +CONFIG_ACPI_EC=y # CONFIG_ACPI_WMI_LEGACY_DEVICE_NAMES is not set # CONFIG_ACQUIRE_WDT is not set # CONFIG_AD3530R is not set @@ -42,9 +42,9 @@ CONFIG_ARCH_USES_PG_ARCH_2=y CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y CONFIG_ARCH_WANTS_NO_INSTR=y # CONFIG_AS21XXX_PHY is not set +CONFIG_ATA=y CONFIG_ATA_GENERIC=y CONFIG_ATA_PIIX=y -CONFIG_ATA=y # CONFIG_AUTOFDO_CLANG is not set # CONFIG_BARCO_P50_GPIO is not set # CONFIG_BASE_SMALL is not set @@ -59,16 +59,17 @@ CONFIG_BUFFER_HEAD=y CONFIG_CLKBLD_I8253=y CONFIG_CLKEVT_I8253=y CONFIG_CLKSRC_I8253=y -CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100 CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100 CONFIG_CLONE_BACKWARDS=y CONFIG_COMMON_CLK=y CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 -CONFIG_COMPAT_32BIT_TIME=y CONFIG_COMPAT_32=y +CONFIG_COMPAT_32BIT_TIME=y # CONFIG_COMPAT_VDSO is not set CONFIG_CONSOLE_TRANSLATIONS=y CONFIG_CPUFREQ_ARCH_CUR_FREQ=y +CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set CONFIG_CPU_FREQ_GOV_ATTR_SET=y @@ -79,11 +80,10 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set # CONFIG_CPU_FREQ_GOV_USERSPACE is not set CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ=y +CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPU_IDLE_GOV_MENU=y CONFIG_CPU_IDLE_GOV_TEO=y -CONFIG_CPU_IDLE=y CONFIG_CPU_MITIGATIONS=y CONFIG_CPU_SUP_AMD=y CONFIG_CPU_SUP_CENTAUR=y @@ -96,8 +96,8 @@ CONFIG_CPU_SUP_VORTEX_32=y CONFIG_CPU_SUP_ZHAOXIN=y CONFIG_CRC16=y # CONFIG_CRYPTO_BENCHMARK is not set -CONFIG_CRYPTO_CRC32C=y CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y # CONFIG_CRYPTO_DEV_QAT_6XXX is not set CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_LIB_GF128MUL=y @@ -124,10 +124,10 @@ CONFIG_DECOMPRESS_BZIP2=y CONFIG_DECOMPRESS_GZIP=y CONFIG_DIMLIB=y CONFIG_DMADEVICES=y +CONFIG_DMI=y CONFIG_DMIID=y CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y CONFIG_DMI_SYSFS=y -CONFIG_DMI=y CONFIG_DNOTIFY=y # CONFIG_DRM_AMD_ISP is not set # CONFIG_DRM_EFIDRM is not set @@ -137,8 +137,8 @@ CONFIG_DNOTIFY=y # CONFIG_DRM_VESADRM is not set CONFIG_DUMMY_CONSOLE=y CONFIG_DYNAMIC_SIGFRAME=y -# CONFIG_EARLY_PRINTK_DBGP is not set CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y # CONFIG_EDD is not set @@ -162,21 +162,21 @@ CONFIG_FUNCTION_ALIGNMENT=4 CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_PADDING_BYTES=4 CONFIG_FUNCTION_PADDING_CFI=0 +CONFIG_FUSION=y # CONFIG_FUSION_CTL is not set # CONFIG_FUSION_LOGGING is not set CONFIG_FUSION_MAX_SGE=128 CONFIG_FUSION_SPI=y -CONFIG_FUSION=y CONFIG_FUTEX_PRIVATE_HASH=y CONFIG_FW_LOADER_PAGED_BUF=y CONFIG_FW_LOADER_SYSFS=y CONFIG_GCC_NO_STRINGOP_OVERFLOW=y CONFIG_GENERIC_ALLOCATOR=y CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE=y +CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE=y CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y -CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_CPU_AUTOPROBE=y CONFIG_GENERIC_CPU_DEVICES=y @@ -200,26 +200,26 @@ CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT=y # CONFIG_GEOS is not set CONFIG_GLOB=y -# CONFIG_GPIO_ELKHARTLAKE is not set CONFIG_GPIOLIB_LEGACY=y +# CONFIG_GPIO_ELKHARTLAKE is not set # CONFIG_GPIO_VIRTIO is not set # CONFIG_HANGCHECK_TIMER is not set CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT_MAP=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_IOPORT_MAP=y CONFIG_HAS_LTO_CLANG=y -CONFIG_HID_SUPPORT=y CONFIG_HID=y -CONFIG_HIGHMEM4G=y +CONFIG_HID_SUPPORT=y CONFIG_HIGHMEM=y +CONFIG_HIGHMEM4G=y # CONFIG_HINIC3 is not set CONFIG_HPET_EMULATE_RTC=y CONFIG_HPET_TIMER=y +CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_GEODE=y CONFIG_HW_RANDOM_VIA=y -CONFIG_HW_RANDOM=y # CONFIG_HYPERVISOR_GUEST is not set CONFIG_HYPERV_VMBUS=y CONFIG_HZ_PERIODIC=y @@ -233,9 +233,9 @@ CONFIG_IA32_FEAT_CTL=y CONFIG_ILLEGAL_POINTER_VALUE=0 # CONFIG_INFINEON_TLV493D is not set CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y CONFIG_INPUT_KEYBOARD=y CONFIG_INPUT_VIVALDIFMAP=y -CONFIG_INPUT=y # CONFIG_INSPUR_PLATFORM_PROFILE is not set CONFIG_INSTRUCTION_DECODER=y # CONFIG_INTEL_HFI_THERMAL is not set @@ -246,30 +246,30 @@ CONFIG_INSTRUCTION_DECODER=y # CONFIG_INTEL_SCU_PCI is not set # CONFIG_INTEL_THC_HID is not set # CONFIG_INTEL_VSEC is not set +# CONFIG_IOSF_MBI is not set CONFIG_IO_DELAY_0X80=y # CONFIG_IO_DELAY_0XED is not set # CONFIG_IO_DELAY_NONE is not set # CONFIG_IO_DELAY_UDELAY is not set -# CONFIG_IOSF_MBI is not set +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y # CONFIG_IR_ENE is not set # CONFIG_IR_FINTEK is not set # CONFIG_IR_ITE_CIR is not set # CONFIG_IR_NUVOTON is not set -CONFIG_IRQ_DOMAIN_HIERARCHY=y -CONFIG_IRQ_DOMAIN=y -CONFIG_IRQ_FORCED_THREADING=y -CONFIG_IRQ_WORK=y # CONFIG_IR_WINBOND_CIR is not set -CONFIG_ISA_DMA_API=y # CONFIG_ISA is not set +CONFIG_ISA_DMA_API=y # CONFIG_IT8712F_WDT is not set # CONFIG_IT87_WDT is not set # CONFIG_ITCO_WDT is not set CONFIG_JBD2=y CONFIG_KALLSYMS=y +CONFIG_KEXEC=y CONFIG_KEXEC_CORE=y # CONFIG_KEXEC_HANDOVER is not set -CONFIG_KEXEC=y CONFIG_KEYBOARD_ATKBD=y CONFIG_KMAP_LOCAL=y CONFIG_KVM_HYPERV=y @@ -302,10 +302,10 @@ CONFIG_MEMFD_CREATE=y # CONFIG_MFD_UPBOARD_FPGA is not set # CONFIG_MGEODEGX1 is not set # CONFIG_MGEODE_LX is not set +CONFIG_MICROCODE=y # CONFIG_MICROCODE_DBG is not set CONFIG_MICROCODE_INITRD32=y # CONFIG_MICROCODE_LATE_LOADING is not set -CONFIG_MICROCODE=y CONFIG_MIGRATION=y CONFIG_MITIGATION_GDS=y CONFIG_MITIGATION_IBPB_ENTRY=y @@ -335,15 +335,15 @@ CONFIG_MMU_LAZY_TLB_REFCOUNT=y CONFIG_MODULES_TREE_LOOKUP=y CONFIG_MODULES_USE_ELF_REL=y # CONFIG_MPENTIUM4 is not set -# CONFIG_MPENTIUMIII is not set # CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set # CONFIG_MPENTIUMM is not set # CONFIG_MSHV_ROOT is not set # CONFIG_MTD_INTEL_DG is not set # CONFIG_MTD_SBC_GXX is not set # CONFIG_MTD_SCx200_DOCFLASH is not set -# CONFIG_MTRR_SANITIZER is not set CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set # CONFIG_MVIAC3_2 is not set # CONFIG_MVIAC7 is not set # CONFIG_MWINCHIP3D is not set @@ -391,6 +391,7 @@ CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y CONFIG_PC104=y # CONFIG_PC8736x_GPIO is not set # CONFIG_PC87413_WDT is not set +CONFIG_PCI=y CONFIG_PCI_ATS=y CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y @@ -403,22 +404,20 @@ CONFIG_PCI_IOV=y CONFIG_PCI_LABEL=y CONFIG_PCI_LOCKLESS_CONFIG=y CONFIG_PCI_MSI=y -CONFIG_PCI=y CONFIG_PCSPKR_PLATFORM=y +CONFIG_PERF_EVENTS=y # CONFIG_PERF_EVENTS_AMD_BRS is not set # CONFIG_PERF_EVENTS_AMD_UNCORE is not set CONFIG_PERF_EVENTS_INTEL_CSTATE=y CONFIG_PERF_EVENTS_INTEL_RAPL=y CONFIG_PERF_EVENTS_INTEL_UNCORE=y -CONFIG_PERF_EVENTS=y CONFIG_PGTABLE_LEVELS=2 -# CONFIG_PHY_INTEL_LGM_EMMC is not set CONFIG_PHYSICAL_ALIGN=0x100000 CONFIG_PHYSICAL_START=0x1000000 +# CONFIG_PHY_INTEL_LGM_EMMC is not set # CONFIG_PINCTRL_INTEL_PLATFORM is not set # CONFIG_PINCTRL_METEORPOINT is not set # CONFIG_PM_USERSPACE_AUTOSLEEP is not set -CONFIG_PM_USERSPACE_AUTOSLEEP is not set # CONFIG_PORTWELL_EC is not set CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y CONFIG_POWER_SUPPLY=y @@ -453,23 +452,23 @@ CONFIG_SATA_HOST=y # CONFIG_SBC8360_WDT is not set # CONFIG_SBC_EPX_C3_WATCHDOG is not set # CONFIG_SC1200_WDT is not set +CONFIG_SCSI=y CONFIG_SCSI_COMMON=y CONFIG_SCSI_SPI_ATTRS=y -CONFIG_SCSI=y -# CONFIG_SCx200_GPIO is not set +CONFIG_SCx200=y CONFIG_SCx200HR_TIMER=y +# CONFIG_SCx200_GPIO is not set # CONFIG_SCx200_WDT is not set -CONFIG_SCx200=y # CONFIG_SEN0322 is not set # CONFIG_SENSORS_GPD is not set # CONFIG_SERIAL_8250_NI is not set -CONFIG_SERIAL_8250_PCILIB=y CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PCILIB=y # CONFIG_SERIAL_LANTIQ is not set +CONFIG_SERIO=y CONFIG_SERIO_I8042=y CONFIG_SERIO_LIBPS2=y CONFIG_SERIO_SERPORT=y -CONFIG_SERIO=y CONFIG_SGL_ALLOC=y CONFIG_SG_POOL=y # CONFIG_SIEMENS_SIMATIC_IPC is not set @@ -505,8 +504,8 @@ CONFIG_SND_HDA_CODEC_HDMI_SIMPLE=m # CONFIG_SND_USB_US144MKII is not set # CONFIG_SND_VIRTIO is not set CONFIG_SOFTIRQ_ON_OWN_STACK=y -CONFIG_SPARSE_IRQ=y CONFIG_SPARSEMEM_STATIC=y +CONFIG_SPARSE_IRQ=y # CONFIG_SPI_INTEL_PCI is not set # CONFIG_SPI_INTEL_PLATFORM is not set # CONFIG_SPI_VIRTIO is not set @@ -522,14 +521,14 @@ CONFIG_SYSCTL_EXCEPTION_TRACE=y # CONFIG_TEST_FPU is not set # CONFIG_TEST_KALLSYMS is not set # CONFIG_TEST_MAPLE_TREE is not set +CONFIG_THERMAL=y CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 CONFIG_THERMAL_GOV_STEP_WISE=y -CONFIG_THERMAL=y CONFIG_THREAD_INFO_IN_TASK=y CONFIG_TICK_CPU_ACCOUNTING=y -# CONFIG_TI_FPC202 is not set CONFIG_TINY_SRCU=y +# CONFIG_TI_FPC202 is not set CONFIG_TOOLS_SUPPORT_RELR=y # CONFIG_TOSHIBA is not set # CONFIG_TQMX86_WDT is not set @@ -538,19 +537,20 @@ CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y CONFIG_UNWINDER_FRAME_POINTER=y # CONFIG_UNWINDER_GUESS is not set CONFIG_UP_LATE_INIT=y +CONFIG_USB=y # CONFIG_USB_CDNS3_PCI_WRAP is not set # CONFIG_USB_CDNSP_PCI is not set CONFIG_USB_COMMON=y CONFIG_USB_DEFAULT_AUTHORIZATION_MODE=1 -# CONFIG_USB_EHCI_HCD_PLATFORM is not set CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set CONFIG_USB_EHCI_PCI=y -CONFIG_USB_HIDDEV=y CONFIG_USB_HID=y +CONFIG_USB_HIDDEV=y # CONFIG_USB_LJCA is not set +CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PCI=y # CONFIG_USB_OHCI_HCD_PLATFORM is not set -CONFIG_USB_OHCI_HCD=y CONFIG_USB_PCI=y CONFIG_USB_SUPPORT=y CONFIG_USB_UHCI_HCD=y @@ -559,7 +559,6 @@ CONFIG_USB_UHCI_HCD=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_PCI=y # CONFIG_USB_XHCI_PLATFORM is not set -CONFIG_USB=y # CONFIG_USER_NS is not set CONFIG_USER_STACKTRACE_SUPPORT=y # CONFIG_VEML6046X00 is not set @@ -570,13 +569,14 @@ CONFIG_VGA_CONSOLE=y # CONFIG_VIDEO_LT6911UXE is not set # CONFIG_VIRTIO_RTC is not set CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_VT=y # CONFIG_WAFER_WDT is not set # CONFIG_WINMATE_FM07_KEYS is not set -# CONFIG_X86_32_IRIS is not set +CONFIG_X86=y CONFIG_X86_32=y +# CONFIG_X86_32_IRIS is not set # CONFIG_X86_ANCIENT_MCE is not set CONFIG_X86_BUS_LOCK_DETECT=y # CONFIG_X86_CHECK_BIOS_CORRUPTION is not set @@ -600,8 +600,8 @@ CONFIG_X86_DISABLED_FEATURE_PCID=y CONFIG_X86_DISABLED_FEATURE_PKU=y CONFIG_X86_DISABLED_FEATURE_PTI=y CONFIG_X86_DISABLED_FEATURE_RETHUNK=y -CONFIG_X86_DISABLED_FEATURE_RETPOLINE_LFENCE=y CONFIG_X86_DISABLED_FEATURE_RETPOLINE=y +CONFIG_X86_DISABLED_FEATURE_RETPOLINE_LFENCE=y CONFIG_X86_DISABLED_FEATURE_SEV_SNP=y CONFIG_X86_DISABLED_FEATURE_SGX=y CONFIG_X86_DISABLED_FEATURE_TDX_GUEST=y @@ -619,18 +619,18 @@ CONFIG_X86_INTEL_TSX_MODE_OFF=y # CONFIG_X86_INTEL_TSX_MODE_ON is not set CONFIG_X86_INTEL_USERCOPY=y CONFIG_X86_INTERNODE_CACHE_SHIFT=6 -CONFIG_X86_IO_APIC=y CONFIG_X86_IOPL_IOPERM=y +CONFIG_X86_IO_APIC=y CONFIG_X86_L1_CACHE_SHIFT=6 # CONFIG_X86_LEGACY_VM86 is not set CONFIG_X86_LOCAL_APIC=y # CONFIG_X86_LONGRUN is not set +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set CONFIG_X86_MCE_AMD=y # CONFIG_X86_MCE_INJECT is not set CONFIG_X86_MCE_INTEL=y -# CONFIG_X86_MCELOG_LEGACY is not set CONFIG_X86_MCE_THRESHOLD=y -CONFIG_X86_MCE=y CONFIG_X86_MINIMUM_CPU_FAMILY=6 CONFIG_X86_MPPARSE=y CONFIG_X86_MSR=y @@ -662,7 +662,6 @@ CONFIG_X86_UP_IOAPIC=y CONFIG_X86_USE_PPRO_CHECKSUM=y CONFIG_X86_VERBOSE_BOOTUP=y CONFIG_X86_VMX_FEATURE_NAMES=y -CONFIG_X86=y # CONFIG_XEN_PRIVCMD_EVENTFD is not set CONFIG_XXHASH=y CONFIG_XZ_DEC_BCJ=y From 597390cbb459ecec4acaac72fbaf547d447b1bf2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 10 Mar 2026 22:05:12 +0800 Subject: [PATCH 378/425] build: remove unused patche Signed-off-by: sbwml --- ...-update-to-25.12-Git-HEAD-2025-12-29.patch | 68 ------------------- openwrt/scripts/02-prepare_package.sh | 8 --- 2 files changed, 76 deletions(-) delete mode 100644 openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch diff --git a/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch b/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch deleted file mode 100644 index 3af58bb70..000000000 --- a/openwrt/patch/odhcp6c/0001-odhcp6c-update-to-25.12-Git-HEAD-2025-12-29.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 948b1b564dcf0afa84882cb79691951d41ff51a5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= -Date: Mon, 29 Dec 2025 18:25:47 +0100 -Subject: [PATCH] odhcp6c: update to 25.12 Git HEAD (2025-12-29) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -699cc61568b6 dhcpv6: omit IA_NA on Request -8774d3c0ec9c dhcpv6: dhcpv6_send: convert whitespaces to tabs -11abe3790431 ra: convert if block to switch -c05b803d38e9 odhcp6c: do cleanup at exit -6aa4e491a869 config: fix potential memory leaks in error paths -235cdc97d73b all: add log helpers -6e3272d609d3 dhcpv6: clarifying comments -04aea4e3f870 dhcpv6: offload FQDN construction to init_dhcpv6 -449ce8374275 dhcpv6: migrate dhcpv6_response_is_valid to switch case - -https://github.com/openwrt/odhcp6c/compare/5ab3203875ad...699cc61568b6 - -Signed-off-by: Álvaro Fernández Rojas ---- - package/network/ipv6/odhcp6c/Makefile | 6 +++--- - package/network/ipv6/odhcp6c/files/dhcpv6.sh | 4 ++-- - 2 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/package/network/ipv6/odhcp6c/Makefile b/package/network/ipv6/odhcp6c/Makefile -index 952831e47a..9741046cfe 100644 ---- a/package/network/ipv6/odhcp6c/Makefile -+++ b/package/network/ipv6/odhcp6c/Makefile -@@ -12,9 +12,9 @@ PKG_RELEASE:=1 - - PKG_SOURCE_PROTO:=git - PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcp6c.git --PKG_SOURCE_DATE:=2025-12-18 --PKG_SOURCE_VERSION:=5ab3203875ad938ea85f6d0ceebdff113c355656 --PKG_MIRROR_HASH:=4de69fe364be2d302329cdc86d4d93820e73c82f00d788a536cf947076a4ded3 -+PKG_SOURCE_DATE:=2025-12-29 -+PKG_SOURCE_VERSION:=699cc61568b6816783d17d57dda4ef7851198528 -+PKG_MIRROR_HASH:=e8a42c429ed83660ccc04d69e3bcbf0056d8e96e08caff0f14518150b89ec352 - - PKG_MAINTAINER:=Álvaro Fernández Rojas - PKG_LICENSE:=GPL-2.0 -diff --git a/package/network/ipv6/odhcp6c/files/dhcpv6.sh b/package/network/ipv6/odhcp6c/files/dhcpv6.sh -index 59a6021c5c..d59e988991 100755 ---- a/package/network/ipv6/odhcp6c/files/dhcpv6.sh -+++ b/package/network/ipv6/odhcp6c/files/dhcpv6.sh -@@ -42,7 +42,7 @@ proto_dhcpv6_init_config() { - proto_config_add_boolean sourcefilter - proto_config_add_boolean keep_ra_dnslifetime - proto_config_add_int "ra_holdoff" -- proto_config_add_boolean verbose -+ proto_config_add_int 'verbose:range(0, 7)' - proto_config_add_boolean dynamic - } - -@@ -116,7 +116,7 @@ proto_dhcpv6_setup() { - - [ -n "$ra_holdoff" ] && append opts "-m$ra_holdoff" - -- [ "$verbose" = "1" ] && append opts "-v" -+ [ -n "$verbose" ] && append opts "-l$verbose" - - json_for_each_item proto_dhcpv6_add_sendopts sendopts opts - --- -2.43.5 - diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index bbf33b17d..e5c9aa25d 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -91,13 +91,6 @@ sed -i 's/0666/0644/g;s/0777/0755/g' feeds/packages/net/samba4/files/smb.conf.te rm -rf feeds/packages/net/zerotier git clone https://$github/sbwml/feeds_packages_net_zerotier feeds/packages/net/zerotier -# aria2 & ariaNG -rm -rf feeds/packages/net/ariang -rm -rf feeds/luci/applications/luci-app-aria2 -git clone https://$github/sbwml/ariang-nginx package/new/ariang-nginx -rm -rf feeds/packages/net/aria2 -git clone https://$github/sbwml/feeds_packages_net_aria2 -b 22.03 feeds/packages/net/aria2 - # airconnect git clone https://$github/sbwml/luci-app-airconnect package/new/airconnect --depth=1 @@ -155,7 +148,6 @@ sed -i 's/<%:Up%>/<%:Move up%>/g' feeds/luci/modules/luci-compat/luasrc/view/cbi sed -i 's/<%:Down%>/<%:Move down%>/g' feeds/luci/modules/luci-compat/luasrc/view/cbi/tblsection.htm # frpc translation -sed -i 's,发送,Transmission,g' feeds/luci/applications/luci-app-transmission/po/zh_Hans/transmission.po sed -i 's,frp 服务器,Frp 服务器,g' feeds/luci/applications/luci-app-frps/po/zh_Hans/frps.po sed -i 's,frp 客户端,Frp 客户端,g' feeds/luci/applications/luci-app-frpc/po/zh_Hans/frpc.po From c134e758b1f0bb735dca0c0d830c2bc4f4ef0ab2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 11 Mar 2026 17:01:49 +0800 Subject: [PATCH 379/425] bluetooth: fix realtek hci-uart bluetooth driver Signed-off-by: sbwml --- openwrt/25-config-musl-r76s | 6 +++-- .../patch/openwrt-6.x/modules/bluetooth.mk | 25 ++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/openwrt/25-config-musl-r76s b/openwrt/25-config-musl-r76s index c66b921c2..25ba3c82b 100644 --- a/openwrt/25-config-musl-r76s +++ b/openwrt/25-config-musl-r76s @@ -23,9 +23,11 @@ CONFIG_TARGET_ROOTFS_PARTSIZE=944 CONFIG_COREMARK_NUMBER_OF_THREADS=8 # CONFIG_KERNEL_KALLSYMS is not set -### SDIO Wireless / Bluetooth -CONFIG_PACKAGE_kmod-bluetooth=y +### SDIO Wireles CONFIG_PACKAGE_kmod-rtl8822cs=y + +### UART Bluetooth +CONFIG_PACKAGE_kmod-hci-uart=y CONFIG_PACKAGE_rtl8822cs-firmware=y ### HDMI diff --git a/openwrt/patch/openwrt-6.x/modules/bluetooth.mk b/openwrt/patch/openwrt-6.x/modules/bluetooth.mk index f86763271..21c53ae03 100644 --- a/openwrt/patch/openwrt-6.x/modules/bluetooth.mk +++ b/openwrt/patch/openwrt-6.x/modules/bluetooth.mk @@ -38,13 +38,15 @@ $(eval $(call KernelPackage,bluetooth)) define KernelPackage/hci-uart SUBMENU:=$(BLUETOOTH_MENU) TITLE:=Bluetooth HCI UART support - DEPENDS:=+kmod-bluetooth + DEPENDS:=+kmod-bluetooth +kmod-btrtl KCONFIG:= \ CONFIG_BT_HCIUART \ + CONFIG_BT_HCIUART_3WIRE=y \ CONFIG_BT_HCIUART_BCM=n \ + CONFIG_BT_HCIUART_H4=y \ CONFIG_BT_HCIUART_INTEL=n \ - CONFIG_BT_HCIUART_H4 \ - CONFIG_BT_HCIUART_NOKIA=n + CONFIG_BT_HCIUART_NOKIA=n \ + CONFIG_BT_HCIUART_RTL=y FILES:= \ $(LINUX_DIR)/drivers/bluetooth/hci_uart.ko AUTOLOAD:=$(call AutoProbe,hci_uart) @@ -60,7 +62,7 @@ $(eval $(call KernelPackage,hci-uart)) define KernelPackage/btusb SUBMENU:=$(BLUETOOTH_MENU) TITLE:=Bluetooth HCI USB support - DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-bluetooth +kmod-btmtk + DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-bluetooth +kmod-btmtk +kmod-btrtl KCONFIG:= \ CONFIG_BT_HCIBTUSB \ CONFIG_BT_HCIBTUSB_BCM=n \ @@ -68,8 +70,7 @@ define KernelPackage/btusb CONFIG_BT_HCIBTUSB_RTL=y FILES:= \ $(LINUX_DIR)/drivers/bluetooth/btusb.ko \ - $(LINUX_DIR)/drivers/bluetooth/btintel.ko \ - $(LINUX_DIR)/drivers/bluetooth/btrtl.ko + $(LINUX_DIR)/drivers/bluetooth/btintel.ko AUTOLOAD:=$(call AutoProbe,btusb) endef @@ -92,6 +93,18 @@ endef $(eval $(call KernelPackage,btmtk)) +define KernelPackage/btrtl + SUBMENU:=$(BLUETOOTH_MENU) + TITLE:=Realtek Bluetooth support + HIDDEN:=1 + DEPENDS:=+kmod-bluetooth + KCONFIG:=CONFIG_BT_RTL + FILES:=$(LINUX_DIR)/drivers/bluetooth/btrtl.ko +endef + +$(eval $(call KernelPackage,btrtl)) + + define KernelPackage/ath3k SUBMENU:=$(BLUETOOTH_MENU) TITLE:=ATH3K Kernel Module support From d2913cacac14ff1cf7c06da6ecfc5c2e7ae2e8c0 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 14 Mar 2026 13:58:39 +0800 Subject: [PATCH 380/425] build: add luci-app-bluetooth for nanopi-r76s Signed-off-by: sbwml --- openwrt/25-config-musl-r76s | 1 + openwrt/scripts/02-prepare_package.sh | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/openwrt/25-config-musl-r76s b/openwrt/25-config-musl-r76s index 25ba3c82b..d36bb7321 100644 --- a/openwrt/25-config-musl-r76s +++ b/openwrt/25-config-musl-r76s @@ -29,6 +29,7 @@ CONFIG_PACKAGE_kmod-rtl8822cs=y ### UART Bluetooth CONFIG_PACKAGE_kmod-hci-uart=y CONFIG_PACKAGE_rtl8822cs-firmware=y +CONFIG_PACKAGE_luci-app-bluetooth=y ### HDMI CONFIG_PACKAGE_kmod-drm-rockchip=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index e5c9aa25d..a80e2f6fe 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -14,6 +14,10 @@ git clone https://$github/sbwml/default-settings package/new/default-settings -b # wwan git clone https://$github/sbwml/wwan-packages package/new/wwan --depth=1 +# bluetooth +git clone https://$github/sbwml/luci-app-bluetooth package/new/luci-app-bluetooth +git clone https://$github/sbwml/package_new_bluez-alsa package/new/bluez-alsa + # bandix git clone https://$github/timsaya/openwrt-bandix package/new/bandix --depth=1 git clone https://$github/timsaya/luci-app-bandix package/new/luci-app-bandix --depth=1 From fc7222aa947f6fe6ddc83de02e81a9db75402abe Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 14 Mar 2026 13:59:21 +0800 Subject: [PATCH 381/425] linux-6.18: bump to 6.18.18 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 071d198b6..f63f5207d 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .16 -LINUX_KERNEL_HASH-6.18.16 = 4f21c01f4d04c1d1b3ed794153f8900802c92497be620b07c4869530f2d28ee3 +LINUX_VERSION-6.18 = .18 +LINUX_KERNEL_HASH-6.18.18 = f4855f382c1b735c84072bdef36db5bcd5dc7b0c37e42f5104317149a0a486ef From 497dce01b8fcff20a42c8caa6604a258fbcc2205 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 14 Mar 2026 14:00:24 +0800 Subject: [PATCH 382/425] ci: fix node20 workflow warning Signed-off-by: sbwml --- .github/workflows/build-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index cf10fe31b..2249388aa 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -177,7 +177,7 @@ jobs: - name: Upload Cached (releases - ccache) if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device == 'armv8' || github.event.inputs.device == 'nanopi-r4s' }} continue-on-error: true - uses: ncipollo/release-action@v1.14.0 + uses: ncipollo/release-action@main with: name: ccache allowUpdates: true @@ -225,7 +225,7 @@ jobs: - name: Create release continue-on-error: true - uses: ncipollo/release-action@v1 + uses: ncipollo/release-action@main with: name: ${{ env.latest_release }} allowUpdates: true From f4c5d223d717f245ea7f39c92a10c59dd85dd6ec Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 18 Mar 2026 01:52:27 +0800 Subject: [PATCH 383/425] x64/config-6.18: Add Maximum Number of CPUs Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/x86/64/config-6.18 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openwrt/patch/openwrt-6.x/x86/64/config-6.18 b/openwrt/patch/openwrt-6.x/x86/64/config-6.18 index 7bfb6e30a..084717ca2 100644 --- a/openwrt/patch/openwrt-6.x/x86/64/config-6.18 +++ b/openwrt/patch/openwrt-6.x/x86/64/config-6.18 @@ -399,7 +399,10 @@ CONFIG_NET_FAILOVER=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NET_PTP_CLASSIFY=y # CONFIG_NITRO_ENCLAVES is not set -# CONFIG_NO_PAGE_MAPCOUNT is not set +CONFIG_NR_CPUS=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 # CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set CONFIG_NVME_CORE=y CONFIG_NVME_HWMON=y From 7091876197a36d6a4e0535d4815ac007ab58e28c Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 19 Mar 2026 06:19:10 +0800 Subject: [PATCH 384/425] config-common: add luci-theme-aurora Signed-off-by: sbwml --- openwrt/25-config-common | 2 ++ openwrt/25-config-std-common | 2 ++ openwrt/scripts/02-prepare_package.sh | 2 ++ 3 files changed, 6 insertions(+) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index cb92a14ec..68b675fec 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -55,6 +55,7 @@ CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_luci-proto-wireguard=y CONFIG_PACKAGE_luci-theme-argon=y +CONFIG_PACKAGE_luci-theme-aurora=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set @@ -79,6 +80,7 @@ CONFIG_NGINX_STREAM_REAL_IP=y CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y +CONFIG_PACKAGE_luci-app-aurora-config=y CONFIG_PACKAGE_luci-app-autoreboot=y # CONFIG_PACKAGE_luci-app-bandix is not set CONFIG_PACKAGE_luci-app-commands=y diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index cd583deac..b18d07a46 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -44,6 +44,7 @@ CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_luci-proto-wireguard=y CONFIG_PACKAGE_luci-theme-argon=y +CONFIG_PACKAGE_luci-theme-aurora=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set @@ -68,6 +69,7 @@ CONFIG_NGINX_STREAM_REAL_IP=y CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y +CONFIG_PACKAGE_luci-app-aurora-config=y CONFIG_PACKAGE_luci-app-autoreboot=y # CONFIG_PACKAGE_luci-app-bandix is not set CONFIG_PACKAGE_luci-app-commands=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index a80e2f6fe..b40ea4b8e 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -123,6 +123,8 @@ sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new # Theme git clone https://$github/sbwml/luci-theme-argon -b openwrt-25.12 package/new/luci-theme-argon --depth=1 +git clone https://$github/eamonxg/luci-theme-aurora package/new/luci-theme-aurora --depth=1 +git clone https://$github/eamonxg/luci-app-aurora-config package/new/luci-app-aurora-config --depth=1 # Mosdns git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 From 314daacad312e3fb3ec16821c4602452d135eaa4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 19 Mar 2026 06:19:17 +0800 Subject: [PATCH 385/425] OpenWrt v25.12.1 Signed-off-by: sbwml --- tags/v25 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v25 b/tags/v25 index df030b74a..ef8738c6e 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.0 +25.12.1 From f26bffc3535ebb9ea0239d4a77f23f63a63f6e96 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 23 Mar 2026 14:24:34 +0800 Subject: [PATCH 386/425] linux-6.18: bump to 6.18.19 Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 2 ++ tags/kernel-6.18 | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index b40ea4b8e..df4d48010 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -125,6 +125,8 @@ sed -i 's/解除网易云音乐播放限制/网易云音乐解锁/g' package/new git clone https://$github/sbwml/luci-theme-argon -b openwrt-25.12 package/new/luci-theme-argon --depth=1 git clone https://$github/eamonxg/luci-theme-aurora package/new/luci-theme-aurora --depth=1 git clone https://$github/eamonxg/luci-app-aurora-config package/new/luci-app-aurora-config --depth=1 +rm -rf package/new/luci-theme-aurora/root/etc/uci-defaults +sed -i 's/100/91/g' package/new/luci-app-aurora-config/root/usr/share/luci/menu.d/luci-app-aurora.json # Mosdns git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index f63f5207d..227e8f201 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .18 -LINUX_KERNEL_HASH-6.18.18 = f4855f382c1b735c84072bdef36db5bcd5dc7b0c37e42f5104317149a0a486ef +LINUX_VERSION-6.18 = .19 +LINUX_KERNEL_HASH-6.18.19 = eaaf78271cd07c68ad9c4c9a70c72718b33abbd716239d82bac96b1751eb090c From 1b7c0b74be99e6b7ba49f72aac2191f630efcca8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 1 Apr 2026 00:04:57 +0800 Subject: [PATCH 387/425] linux-6.18: bump to 6.18.20 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 227e8f201..5cd89cd49 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .19 -LINUX_KERNEL_HASH-6.18.19 = eaaf78271cd07c68ad9c4c9a70c72718b33abbd716239d82bac96b1751eb090c +LINUX_VERSION-6.18 = .20 +LINUX_KERNEL_HASH-6.18.20 = 837a5abd98e46078a0ae1400e2daad89ece45cc3209037b09c2265dab2393553 From 365297b8aa813554844fa9fbf333a7a9072eb36a Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 1 Apr 2026 00:05:08 +0800 Subject: [PATCH 388/425] OpenWrt v25.12.2 Signed-off-by: sbwml --- openwrt/patch/mt76/Makefile | 23 +- ...-fix-NULL-pointer-dereference-in-vif.patch | 76 ------ ...-fix-missing-mutex-protection-in-res.patch | 57 ---- ...-fix-missing-mutex-protection-in-run.patch | 71 ----- ...-add-NULL-checks-in-MCU-STA-TLV-func.patch | 48 ---- ...-add-NULL-checks-for-link_conf-and-m.patch | 122 --------- ...-add-error-handling-for-AMPDU-MCU-co.patch | 64 ----- ...-add-error-handling-for-BSS-info-MCU.patch | 40 --- ...-add-error-handling-for-BSS-info-in-.patch | 35 --- ...-add-NULL-checks-in-MLO-link-and-cha.patch | 104 ------- ...-fix-NULL-pointer-dereference-in-TX-.patch | 70 ----- ...-add-lockdep-assertions-for-mutex-ve.patch | 52 ---- ...-fix-key-removal-failure-during-MLO-.patch | 54 ---- ...-fix-kernel-warning-in-MLO-ROC-setup.patch | 69 ----- ...-add-NULL-checks-for-MLO-link-pointe.patch | 83 ------ ...-fix-firmware-reload-failure-after-p.patch | 53 ---- ...-add-mutex-protection-in-resume-path.patch | 32 --- ...-add-NULL-checks-for-link-pointers-i.patch | 48 ---- ...-fix-BA-session-teardown-during-beac.patch | 45 ---- ...-fix-deadlock-in-sta-removal-ROC-abo.patch | 143 ---------- ...25-fix-ROC-timer-race-during-suspend.patch | 47 ---- ...-add-ROC-rate-limiting-to-mitigate-M.patch | 254 ------------------ ...-improve-error-handling-and-code-cle.patch | 184 ------------- ...7925-fix-deadlock-and-WCID-leak-bugs.patch | 169 ------------ ...-fix-race-condition-in-async-ROC-abo.patch | 147 ---------- openwrt/scripts/01-prepare_base-mainline.sh | 24 -- openwrt/scripts/02-prepare_package.sh | 2 +- tags/v25 | 2 +- 28 files changed, 22 insertions(+), 2096 deletions(-) delete mode 100644 openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch delete mode 100644 openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch delete mode 100644 openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch delete mode 100644 openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch delete mode 100644 openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch delete mode 100644 openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch delete mode 100644 openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch delete mode 100644 openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch delete mode 100644 openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch delete mode 100644 openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch delete mode 100644 openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch delete mode 100644 openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch delete mode 100644 openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch delete mode 100644 openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch delete mode 100644 openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch delete mode 100644 openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch delete mode 100644 openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch delete mode 100644 openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch delete mode 100644 openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch delete mode 100644 openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch delete mode 100644 openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch delete mode 100644 openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch delete mode 100644 openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch delete mode 100644 openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 39057b8c2..6f4e029eb 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2026-01-28 -PKG_SOURCE_VERSION:=b2fe7f1463526572f01731db8440c10e393fd09f -PKG_MIRROR_HASH:=ea2408d5bfa331598bd0f2fb40516ecbd718d3903a4f43ca0a2d1fc66e8fb6b6 +PKG_SOURCE_DATE:=2026-03-21 +PKG_SOURCE_VERSION:=018f60316d4dd6b4e741874eda40e2dfaa29df3b +PKG_MIRROR_HASH:=54a8125453a6fe04c89cf5335bdf0ea16c409361e1e5a79fb339d67cee26df0e PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 @@ -325,6 +325,12 @@ define KernelPackage/mt7996e AUTOLOAD:=$(call AutoProbe,mt7996e) endef +define KernelPackage/mt7990-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7990 firmware + DEPENDS+=+kmod-mt7996e +endef + define KernelPackage/mt7992-firmware $(KernelPackage/mt76-default) TITLE:=MediaTek MT7992 firmware @@ -662,6 +668,16 @@ define KernelPackage/mt7925-firmware/install $(1)/lib/firmware/mediatek/mt7925 endef +define KernelPackage/mt7990-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom_2i5i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_rom_patch.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_wm.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + define KernelPackage/mt7992-firmware/install $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 cp \ @@ -766,6 +782,7 @@ $(eval $(call KernelPackage,mt7921e)) $(eval $(call KernelPackage,mt7925u)) $(eval $(call KernelPackage,mt7925e)) $(eval $(call KernelPackage,mt7996e)) +$(eval $(call KernelPackage,mt7990-firmware)) $(eval $(call KernelPackage,mt7992-firmware)) $(eval $(call KernelPackage,mt7992-23-firmware)) $(eval $(call KernelPackage,mt7996-firmware-common)) diff --git a/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch b/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch deleted file mode 100644 index 97ca319e8..000000000 --- a/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch +++ /dev/null @@ -1,76 +0,0 @@ -From c0cffda0635828184cae6b8e2f91827deaff5062 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 16:51:17 -0800 -Subject: [PATCH 01/24] wifi: mt76: mt7925: fix NULL pointer dereference in vif - iteration - -Add NULL checks for bss_conf in all loops that iterate over valid_links -and call mt792x_vif_to_bss_conf(). This prevents kernel panics when the -link configuration in mac80211 is not yet set up even though the driver's -valid_links bitmap has the link marked as valid. - -This can happen during HW reset when link state is inconsistent, or during -MLO operations where the driver's link tracking is ahead of mac80211's -BSS configuration. - -Reported-by: Zac Bowling -Tested-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/mac.c | 6 ++++++ - mt7925/main.c | 8 ++++++++ - 2 files changed, 14 insertions(+) - ---- a/mt7925/mac.c -+++ b/mt7925/mac.c -@@ -1276,6 +1276,12 @@ mt7925_vif_connect_iter(void *priv, u8 * - bss_conf = mt792x_vif_to_bss_conf(vif, i); - mconf = mt792x_vif_to_link(mvif, i); - -+ /* Skip links that don't have bss_conf set up yet in mac80211. -+ * This can happen during HW reset when link state is inconsistent. -+ */ -+ if (!bss_conf) -+ continue; -+ - mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76, - &mvif->sta.deflink.wcid, true); - mt7925_mcu_set_tx(dev, bss_conf); ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -1312,6 +1312,8 @@ mt7925_mlo_pm_iter(void *priv, u8 *mac, - mt792x_mutex_acquire(dev); - for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { - bss_conf = mt792x_vif_to_bss_conf(vif, i); -+ if (!bss_conf) -+ continue; - mt7925_mcu_uni_bss_ps(dev, bss_conf); - } - mt792x_mutex_release(dev); -@@ -1646,6 +1648,8 @@ static void mt7925_ipv6_addr_change(stru - - for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { - bss_conf = mt792x_vif_to_bss_conf(vif, i); -+ if (!bss_conf) -+ continue; - __mt7925_ipv6_addr_change(hw, bss_conf, idev); - } - } -@@ -1886,6 +1890,8 @@ static void mt7925_vif_cfg_changed(struc - if (changed & BSS_CHANGED_ARP_FILTER) { - for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { - bss_conf = mt792x_vif_to_bss_conf(vif, i); -+ if (!bss_conf) -+ continue; - mt7925_mcu_update_arp_filter(&dev->mt76, bss_conf); - } - } -@@ -1901,6 +1907,8 @@ static void mt7925_vif_cfg_changed(struc - } else if (mvif->mlo_pm_state == MT792x_MLO_CHANGED_PS) { - for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { - bss_conf = mt792x_vif_to_bss_conf(vif, i); -+ if (!bss_conf) -+ continue; - mt7925_mcu_uni_bss_ps(dev, bss_conf); - } - } diff --git a/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch b/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch deleted file mode 100644 index 83aac4a89..000000000 --- a/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch +++ /dev/null @@ -1,57 +0,0 @@ -From b597a5c4c11574a15db2a0a8f8fc07eaa869ccda Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 16:51:29 -0800 -Subject: [PATCH 02/24] wifi: mt76: mt7925: fix missing mutex protection in - reset and ROC abort - -During firmware recovery and ROC (Remain On Channel) abort operations, -the driver iterates over active interfaces and calls MCU functions that -require the device mutex to be held, but the mutex was not acquired. - -This causes system-wide hangs where network commands hang indefinitely, -processes get stuck in uninterruptible sleep (D state), and the system -becomes completely unresponsive requiring force reboot. - -Add mutex protection around interface iteration in: -- mt7925_mac_reset_work(): Called during firmware recovery after MCU - timeouts to reconnect all interfaces -- PCI suspend path: Wrap mt7925_roc_abort_sync() call with mutex - -Note: The mutex is added at the call site in pci.c rather than inside -mt7925_roc_abort_sync() because this function is also called from the -station remove path which already holds the mutex. - -Reported-by: Zac Bowling -Tested-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/mac.c | 2 ++ - mt7925/pci.c | 2 ++ - 2 files changed, 4 insertions(+) - ---- a/mt7925/mac.c -+++ b/mt7925/mac.c -@@ -1336,9 +1336,11 @@ void mt7925_mac_reset_work(struct work_s - dev->hw_full_reset = false; - pm->suspended = false; - ieee80211_wake_queues(hw); -+ mt792x_mutex_acquire(dev); - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7925_vif_connect_iter, NULL); -+ mt792x_mutex_release(dev); - mt76_connac_power_save_sched(&dev->mt76.phy, pm); - - mt7925_regd_change(&dev->phy, "00"); ---- a/mt7925/pci.c -+++ b/mt7925/pci.c -@@ -455,7 +455,9 @@ static int mt7925_pci_suspend(struct dev - cancel_delayed_work_sync(&pm->ps_work); - cancel_work_sync(&pm->wake_work); - -+ mt792x_mutex_acquire(dev); - mt7925_roc_abort_sync(dev); -+ mt792x_mutex_release(dev); - - err = mt792x_mcu_drv_pmctrl(dev); - if (err < 0) diff --git a/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch b/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch deleted file mode 100644 index 81b4521cc..000000000 --- a/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch +++ /dev/null @@ -1,71 +0,0 @@ -From d50a5ea85f9f33b7127a26b12327ae622c1b45fd Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 16:51:37 -0800 -Subject: [PATCH 03/24] wifi: mt76: mt7925: fix missing mutex protection in - runtime PM and MLO PM - -Two additional code paths iterate over active interfaces and call MCU -functions without proper mutex protection: - -1. mt7925_set_runtime_pm(): Called when runtime PM settings change. - The ieee80211_iterate_active_interfaces() call invokes - mt7925_pm_interface_iter() which calls mt7925_mcu_set_beacon_filter(). - -2. mt7925_mlo_pm_work(): Workqueue function for MLO power management. - The iterator callback mt7925_mlo_pm_iter() calls mt7925_mcu_uni_bss_ps(). - -Add mutex protection around the iterate calls in both functions. For -mt7925_mlo_pm_iter(), move the mutex from inside the callback to the -caller (mt7925_mlo_pm_work) for consistency with other patterns. - -This matches the pattern used in the older mt7615 driver and other -wireless drivers like iwlwifi. - -Reported-by: Zac Bowling -Tested-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -759,9 +759,11 @@ void mt7925_set_runtime_pm(struct mt792x - bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); - - pm->enable = pm->enable_user && !monitor; -+ mt792x_mutex_acquire(dev); - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7925_pm_interface_iter, dev); -+ mt792x_mutex_release(dev); - pm->ds_enable = pm->ds_enable_user && !monitor; - mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); - } -@@ -1309,14 +1311,12 @@ mt7925_mlo_pm_iter(void *priv, u8 *mac, - if (mvif->mlo_pm_state != MT792x_MLO_CHANGED_PS) - return; - -- mt792x_mutex_acquire(dev); - for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { - bss_conf = mt792x_vif_to_bss_conf(vif, i); - if (!bss_conf) - continue; - mt7925_mcu_uni_bss_ps(dev, bss_conf); - } -- mt792x_mutex_release(dev); - } - - void mt7925_mlo_pm_work(struct work_struct *work) -@@ -1325,9 +1325,11 @@ void mt7925_mlo_pm_work(struct work_stru - mlo_pm_work.work); - struct ieee80211_hw *hw = mt76_hw(dev); - -+ mt792x_mutex_acquire(dev); - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7925_mlo_pm_iter, dev); -+ mt792x_mutex_release(dev); - } - - void mt7925_scan_work(struct work_struct *work) diff --git a/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch b/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch deleted file mode 100644 index c91b3e412..000000000 --- a/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch +++ /dev/null @@ -1,48 +0,0 @@ -From f6d73e60d473f84899ec8973d5b4c59520a1041b Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 17:09:05 -0800 -Subject: [PATCH 04/24] wifi: mt76: mt7925: add NULL checks in MCU STA TLV - functions - -Add NULL pointer checks for link_conf and mconf in: -- mt7925_mcu_sta_phy_tlv(): builds PHY capability TLV for station record -- mt7925_mcu_sta_rate_ctrl_tlv(): builds rate control TLV for station record - -Both functions call mt792x_vif_to_bss_conf() and mt792x_vif_to_link() -which can return NULL during MLO link state transitions when the link -configuration in mac80211 is not yet synchronized with the driver's -link tracking. - -Without these checks, the driver will crash with a NULL pointer -dereference when accessing link_conf->chanreq.oper or link_conf->basic_rates. - -Reported-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/mcu.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - ---- a/mt7925/mcu.c -+++ b/mt7925/mcu.c -@@ -1778,6 +1778,10 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *s - - link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); - mconf = mt792x_vif_to_link(mvif, link_sta->link_id); -+ -+ if (!link_conf || !mconf) -+ return; -+ - chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : - &link_conf->chanreq.oper; - -@@ -1856,6 +1860,10 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_b - - link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); - mconf = mt792x_vif_to_link(mvif, link_sta->link_id); -+ -+ if (!link_conf || !mconf) -+ return; -+ - chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : - &link_conf->chanreq.oper; - band = chandef->chan->band; diff --git a/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch b/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch deleted file mode 100644 index 2c1e5e197..000000000 --- a/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 36afd6a3968570e92101e3599fa5a28bc943f915 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 17:10:57 -0800 -Subject: [PATCH 05/24] wifi: mt76: mt7925: add NULL checks for link_conf and - mlink in main.c - -Add NULL pointer checks throughout main.c for functions that call -mt792x_vif_to_bss_conf(), mt792x_vif_to_link(), and mt792x_sta_to_link() -without verifying the return value before dereferencing. - -Functions fixed: -- mt7925_set_key(): Check link_conf, mconf, and mlink before use -- mt7925_mac_link_sta_add(): Check link_conf before BSS info update -- mt7925_mac_link_sta_assoc(): Check mlink and link_conf before use -- mt7925_mac_link_sta_remove(): Check mlink and link_conf, add goto - label for proper cleanup path -- mt7925_change_vif_links(): Check link_conf before adding BSS - -These functions can receive NULL when the link configuration in mac80211 -is not yet synchronized with the driver's link tracking during MLO -operations or state transitions. - -Without these checks, the driver will crash with NULL pointer -dereferences during station add/remove/association operations. - -Reported-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 27 +++++++++++++++++++++++---- - 1 file changed, 23 insertions(+), 4 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -612,6 +612,10 @@ static int mt7925_set_link_key(struct ie - link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; - mconf = mt792x_vif_to_link(mvif, link_id); - mlink = mt792x_sta_to_link(msta, link_id); -+ -+ if (!link_conf || !mconf || !mlink) -+ return -EINVAL; -+ - wcid = &mlink->wcid; - wcid_keyidx = &wcid->hw_key_idx; - -@@ -897,6 +901,8 @@ static int mt7925_mac_link_sta_add(struc - MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - - link_conf = mt792x_vif_to_bss_conf(vif, link_id); -+ if (!link_conf) -+ return -EINVAL; - - /* should update bss info before STA add */ - if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { -@@ -1042,6 +1048,8 @@ static void mt7925_mac_link_sta_assoc(st - - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); -+ if (!mlink) -+ return; - - mt792x_mutex_acquire(dev); - -@@ -1051,12 +1059,13 @@ static void mt7925_mac_link_sta_assoc(st - link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); - } - -- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { -+ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { - struct mt792x_bss_conf *mconf; - - mconf = mt792x_link_conf_to_mconf(link_conf); -- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -- link_conf, link_sta, true); -+ if (mconf) -+ mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -+ link_conf, link_sta, true); - } - - ewma_avg_signal_init(&mlink->avg_ack_signal); -@@ -1103,6 +1112,8 @@ static void mt7925_mac_link_sta_remove(s - - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_id); -+ if (!mlink) -+ return; - - mt7925_roc_abort_sync(dev); - -@@ -1116,10 +1127,12 @@ static void mt7925_mac_link_sta_remove(s - - link_conf = mt792x_vif_to_bss_conf(vif, link_id); - -- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { -+ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { - struct mt792x_bss_conf *mconf; - - mconf = mt792x_link_conf_to_mconf(link_conf); -+ if (!mconf) -+ goto out; - - if (ieee80211_vif_is_mld(vif)) - mt792x_mac_link_bss_remove(dev, mconf, mlink); -@@ -1127,6 +1140,7 @@ static void mt7925_mac_link_sta_remove(s - mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, - link_sta, false); - } -+out: - - spin_lock_bh(&mdev->sta_poll_lock); - if (!list_empty(&mlink->wcid.poll_list)) -@@ -2050,6 +2064,11 @@ mt7925_change_vif_links(struct ieee80211 - mlink = mlinks[link_id]; - link_conf = mt792x_vif_to_bss_conf(vif, link_id); - -+ if (!link_conf) { -+ err = -EINVAL; -+ goto free; -+ } -+ - rcu_assign_pointer(mvif->link_conf[link_id], mconf); - rcu_assign_pointer(mvif->sta.link[link_id], mlink); - diff --git a/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch b/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch deleted file mode 100644 index 55e1884c1..000000000 --- a/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 110376227cac0081a5e137ae1f74ac1a766fcd62 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 17:20:50 -0800 -Subject: [PATCH 06/24] wifi: mt76: mt7925: add error handling for AMPDU MCU - commands - -Check return values of mt7925_mcu_uni_rx_ba() and mt7925_mcu_uni_tx_ba() -in mt7925_ampdu_action() and propagate errors to the caller. - -Previously, failures in these MCU commands were silently ignored, which -could leave block aggregation in an inconsistent state between the driver -and firmware. - -For IEEE80211_AMPDU_TX_STOP_CONT, only call the completion callback -ieee80211_stop_tx_ba_cb_irqsafe() if the MCU command succeeded, to avoid -signaling completion when the firmware operation failed. - -Reported-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 13 +++++++------ - 1 file changed, 7 insertions(+), 6 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -1279,22 +1279,22 @@ mt7925_ampdu_action(struct ieee80211_hw - case IEEE80211_AMPDU_RX_START: - mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn, - params->buf_size); -- mt7925_mcu_uni_rx_ba(dev, params, true); -+ ret = mt7925_mcu_uni_rx_ba(dev, params, true); - break; - case IEEE80211_AMPDU_RX_STOP: - mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); -- mt7925_mcu_uni_rx_ba(dev, params, false); -+ ret = mt7925_mcu_uni_rx_ba(dev, params, false); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - mtxq->aggr = true; - mtxq->send_bar = false; -- mt7925_mcu_uni_tx_ba(dev, params, true); -+ ret = mt7925_mcu_uni_tx_ba(dev, params, true); - break; - case IEEE80211_AMPDU_TX_STOP_FLUSH: - case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: - mtxq->aggr = false; - clear_bit(tid, &msta->deflink.wcid.ampdu_state); -- mt7925_mcu_uni_tx_ba(dev, params, false); -+ ret = mt7925_mcu_uni_tx_ba(dev, params, false); - break; - case IEEE80211_AMPDU_TX_START: - set_bit(tid, &msta->deflink.wcid.ampdu_state); -@@ -1303,8 +1303,9 @@ mt7925_ampdu_action(struct ieee80211_hw - case IEEE80211_AMPDU_TX_STOP_CONT: - mtxq->aggr = false; - clear_bit(tid, &msta->deflink.wcid.ampdu_state); -- mt7925_mcu_uni_tx_ba(dev, params, false); -- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); -+ ret = mt7925_mcu_uni_tx_ba(dev, params, false); -+ if (!ret) -+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - } - mt792x_mutex_release(dev); diff --git a/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch b/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch deleted file mode 100644 index 2f5977723..000000000 --- a/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 4173078c845d19e66fc025abd26154ee22718a3f Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 17:21:34 -0800 -Subject: [PATCH 07/24] wifi: mt76: mt7925: add error handling for BSS info MCU - command in sta_add - -Check return value of mt7925_mcu_add_bss_info() in mt7925_mac_link_sta_add() -and propagate errors to the caller. - -BSS info must be set up before adding a station record. If this MCU -command fails, continuing with station add would leave the firmware in -an inconsistent state with a station but no BSS configuration. - -Reported-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -907,11 +907,14 @@ static int mt7925_mac_link_sta_add(struc - /* should update bss info before STA add */ - if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { - if (ieee80211_vif_is_mld(vif)) -- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -- link_conf, link_sta, link_sta != mlink->pri_link); -+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -+ link_conf, link_sta, -+ link_sta != mlink->pri_link); - else -- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -- link_conf, link_sta, false); -+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -+ link_conf, link_sta, false); -+ if (ret) -+ return ret; - } - - if (ieee80211_vif_is_mld(vif) && diff --git a/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch b/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch deleted file mode 100644 index 1b5537335..000000000 --- a/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0ed559511504baf62cfe5d714d9d7e2ca219fd7a Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 17:21:51 -0800 -Subject: [PATCH 08/24] wifi: mt76: mt7925: add error handling for BSS info in - key setup - -Check return value of mt7925_mcu_add_bss_info() in mt7925_set_key_link() -when setting up cipher for the first time and propagate errors. - -The BSS info update with cipher information must succeed before key -programming can proceed. If this MCU command fails, continuing with -key setup would program keys into the firmware for a BSS that doesn't -have the correct cipher configuration. - -Reported-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -645,8 +645,10 @@ static int mt7925_set_link_key(struct ie - struct mt792x_phy *phy = mt792x_hw_phy(hw); - - mconf->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); -- mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf, -- link_sta, true); -+ err = mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf, -+ link_sta, true); -+ if (err) -+ goto out; - } - - if (cmd == SET_KEY) diff --git a/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch b/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch deleted file mode 100644 index 29ff2b231..000000000 --- a/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 17e94c11b17adcede06bf43deca351a2a5163705 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 17:32:55 -0800 -Subject: [PATCH 09/24] wifi: mt76: mt7925: add NULL checks in MLO link and - chanctx functions - -Add NULL pointer checks for mconf and link_conf in several functions -that were missing validation after calling mt792x_vif_to_link() and -mt792x_vif_to_bss_conf(). - -Functions fixed: -- mt7925_mac_set_links(): Check both primary and secondary link_conf - before dereferencing chanreq.oper for band selection -- mt7925_link_info_changed(): Check mconf before using it to get - link_conf, prevents NULL dereference chain -- mt7925_assign_vif_chanctx(): Check mconf before use, return -EINVAL - if NULL; check pri_link_conf before passing to MCU function -- mt7925_unassign_vif_chanctx(): Check mconf before dereferencing, - return early if NULL during MLO cleanup - -These functions handle MLO (Multi-Link Operation) scenarios where link -configurations may not be fully set up when called, particularly during -rapid link state transitions or error recovery paths. - -Reported-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 36 +++++++++++++++++++++++++++++------- - 1 file changed, 29 insertions(+), 7 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -1014,18 +1014,29 @@ mt7925_mac_set_links(struct mt76_dev *md - { - struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; -- struct ieee80211_bss_conf *link_conf = -- mt792x_vif_to_bss_conf(vif, mvif->deflink_id); -- struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; -- enum nl80211_band band = chandef->chan->band, secondary_band; -+ struct ieee80211_bss_conf *link_conf; -+ struct cfg80211_chan_def *chandef; -+ enum nl80211_band band, secondary_band; -+ u16 sel_links; -+ u8 secondary_link_id; -+ -+ link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); -+ if (!link_conf) -+ return; - -- u16 sel_links = mt76_select_links(vif, 2); -- u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); -+ chandef = &link_conf->chanreq.oper; -+ band = chandef->chan->band; -+ -+ sel_links = mt76_select_links(vif, 2); -+ secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); - - if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2) - return; - - link_conf = mt792x_vif_to_bss_conf(vif, secondary_link_id); -+ if (!link_conf) -+ return; -+ - secondary_band = link_conf->chanreq.oper.chan->band; - - if (band == NL80211_BAND_2GHZ || -@@ -1951,6 +1962,8 @@ static void mt7925_link_info_changed(str - struct mt792x_bss_conf *mconf; - - mconf = mt792x_vif_to_link(mvif, info->link_id); -+ if (!mconf) -+ return; - - mt792x_mutex_acquire(dev); - -@@ -2155,9 +2168,14 @@ static int mt7925_assign_vif_chanctx(str - - if (ieee80211_vif_is_mld(vif)) { - mconf = mt792x_vif_to_link(mvif, link_conf->link_id); -+ if (!mconf) { -+ mutex_unlock(&dev->mt76.mutex); -+ return -EINVAL; -+ } -+ - pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); - -- if (vif->type == NL80211_IFTYPE_STATION && -+ if (pri_link_conf && vif->type == NL80211_IFTYPE_STATION && - mconf == &mvif->bss_conf) - mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf, - NULL, true); -@@ -2186,6 +2204,10 @@ static void mt7925_unassign_vif_chanctx( - - if (ieee80211_vif_is_mld(vif)) { - mconf = mt792x_vif_to_link(mvif, link_conf->link_id); -+ if (!mconf) { -+ mutex_unlock(&dev->mt76.mutex); -+ return; -+ } - - if (vif->type == NL80211_IFTYPE_STATION && - mconf == &mvif->bss_conf) diff --git a/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch b/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch deleted file mode 100644 index a6ceabbb5..000000000 --- a/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 1521b28edece1801c7e2edc657b456721720022c Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 17:38:26 -0800 -Subject: [PATCH 10/24] wifi: mt76: mt792x: fix NULL pointer dereference in TX - path - -Add NULL pointer checks in mt792x_tx() to prevent kernel crashes when -transmitting packets during MLO link removal. - -The function calls mt792x_sta_to_link() which can return NULL if the -link is being removed, but the return value was dereferenced without -checking. Similarly, the RCU-protected link_conf and link_sta pointers -were used without NULL validation. - -This race can occur when: -1. A packet is queued for transmission -2. Concurrently, the link is being removed (mt7925_mac_link_sta_remove) -3. mt792x_sta_to_link() returns NULL for the removed link -4. Kernel crashes on wcid = &mlink->wcid dereference - -Fix by: -- Check mlink return value before dereferencing wcid -- Check RCU-dereferenced conf and link_sta before use -- Free the SKB and return early if any pointer is NULL - -This affects both MT7921 and MT7925 drivers as mt792x_core.c is shared. - -Reported-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt792x_core.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - ---- a/mt792x_core.c -+++ b/mt792x_core.c -@@ -95,6 +95,8 @@ void mt792x_tx(struct ieee80211_hw *hw, - IEEE80211_TX_CTRL_MLO_LINK); - sta = (struct mt792x_sta *)control->sta->drv_priv; - mlink = mt792x_sta_to_link(sta, link_id); -+ if (!mlink) -+ goto free_skb; - wcid = &mlink->wcid; - } - -@@ -113,9 +115,12 @@ void mt792x_tx(struct ieee80211_hw *hw, - link_id = wcid->link_id; - rcu_read_lock(); - conf = rcu_dereference(vif->link_conf[link_id]); -- memcpy(hdr->addr2, conf->addr, ETH_ALEN); -- - link_sta = rcu_dereference(control->sta->link[link_id]); -+ if (!conf || !link_sta) { -+ rcu_read_unlock(); -+ goto free_skb; -+ } -+ memcpy(hdr->addr2, conf->addr, ETH_ALEN); - memcpy(hdr->addr1, link_sta->addr, ETH_ALEN); - - if (vif->type == NL80211_IFTYPE_STATION) -@@ -136,6 +141,10 @@ void mt792x_tx(struct ieee80211_hw *hw, - } - - mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); -+ return; -+ -+free_skb: -+ ieee80211_free_txskb(hw, skb); - } - EXPORT_SYMBOL_GPL(mt792x_tx); - diff --git a/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch b/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch deleted file mode 100644 index d2c2d5f3e..000000000 --- a/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch +++ /dev/null @@ -1,52 +0,0 @@ -From e92c47a90205ce125af3d0b6f21d008f8e816aa8 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 31 Dec 2025 21:31:51 -0800 -Subject: [PATCH 11/24] wifi: mt76: mt7925: add lockdep assertions for mutex - verification - -Add lockdep_assert_held() calls to critical MCU functions to help catch -mutex violations during development and debugging. This follows the -pattern used in other mt76 drivers (mt7996, mt7915, mt7615). - -Functions with new assertions: -- mt7925_mcu_add_bss_info(): Core BSS configuration MCU command -- mt7925_mcu_sta_update(): Station record update MCU command -- mt7925_mcu_uni_bss_ps(): Power save state MCU command - -These functions modify firmware state and must be called with the -device mutex held to prevent race conditions. - -Signed-off-by: Zac Bowling ---- - mt7925/mcu.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/mt7925/mcu.c -+++ b/mt7925/mcu.c -@@ -1532,6 +1532,8 @@ int mt7925_mcu_uni_bss_ps(struct mt792x_ - }, - }; - -+ lockdep_assert_held(&dev->mt76.mutex); -+ - if (link_conf->vif->type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - -@@ -2042,6 +2044,8 @@ int mt7925_mcu_sta_update(struct mt792x_ - struct mt792x_sta *msta; - struct mt792x_link_sta *mlink; - -+ lockdep_assert_held(&dev->mt76.mutex); -+ - if (link_sta) { - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); -@@ -2848,6 +2852,8 @@ int mt7925_mcu_add_bss_info(struct mt792 - struct mt792x_link_sta *mlink_bc; - struct sk_buff *skb; - -+ lockdep_assert_held(&dev->mt76.mutex); -+ - skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, - MT7925_BSS_UPDATE_MAX_SIZE); - if (IS_ERR(skb)) diff --git a/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch b/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch deleted file mode 100644 index 3fdecd1c8..000000000 --- a/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 22e6df471b3f7f60cb947f9e71e0188ef07abea0 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Thu, 1 Jan 2026 12:09:42 -0800 -Subject: [PATCH 12/24] wifi: mt76: mt7925: fix key removal failure during MLO - roaming - -During MLO roaming, mac80211 may request key removal after the link state -has already been torn down. The current code returns -EINVAL when -link_conf, mconf, or mlink is NULL, causing 'failed to remove key from -hardware (-22)' errors in the kernel log. - -This is a race condition where: -1. MLO link teardown begins, cleaning up driver state -2. mac80211 requests group key removal for the old link -3. mt792x_vif_to_bss_conf() or related functions return NULL -4. Driver returns -EINVAL, confusing upper layers - -The fix: When removing a key (cmd != SET_KEY), if the link state is -already gone, return success (0) instead of error. The key is effectively -removed when the link was torn down. - -This prevents the following errors during roaming: - wlp192s0: failed to remove key (1, ff:ff:ff:ff:ff:ff) from hardware (-22) - wlp192s0: failed to remove key (4, ff:ff:ff:ff:ff:ff) from hardware (-22) - -And the associated wpa_supplicant warnings: - nl80211: kernel reports: link ID must for MLO group key - -Reported-by: Zac Bowling -Tested-by: Zac Bowling -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -613,8 +613,15 @@ static int mt7925_set_link_key(struct ie - mconf = mt792x_vif_to_link(mvif, link_id); - mlink = mt792x_sta_to_link(msta, link_id); - -- if (!link_conf || !mconf || !mlink) -+ if (!link_conf || !mconf || !mlink) { -+ /* During MLO roaming, link state may be torn down before -+ * mac80211 requests key removal. If removing a key and -+ * the link is already gone, consider it successfully removed. -+ */ -+ if (cmd != SET_KEY) -+ return 0; - return -EINVAL; -+ } - - wcid = &mlink->wcid; - wcid_keyidx = &wcid->hw_key_idx; diff --git a/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch b/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch deleted file mode 100644 index b881eb966..000000000 --- a/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch +++ /dev/null @@ -1,69 +0,0 @@ -From c3304a1b31fe91c3b79e4e8263ced6ace1d21052 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Thu, 1 Jan 2026 12:36:10 -0800 -Subject: [PATCH 13/24] wifi: mt76: mt7925: fix kernel warning in MLO ROC setup - when channel not configured - -mt7925_mcu_set_mlo_roc() uses WARN_ON_ONCE() to check if link_conf or -channel is NULL. However, during MLO AP setup, it's normal for the -channel to not be configured yet when this function is called. The -WARN_ON_ONCE triggers a kernel warning/oops that makes the system -appear to have crashed, even though it's just a timing issue. - -Replace WARN_ON_ONCE with regular NULL checks and return -ENOLINK to -indicate the link isn't fully configured yet. This allows the upper -layers to retry when the link is ready, without spamming the kernel -log with warnings. - -Also add a check for mconf in the first loop to match the pattern -used in the second loop, preventing potential NULL dereference. - -This fixes kernel oops reported during MLO AP setup on OpenWrt with -MT7925E hardware. - -Signed-off-by: Zac Bowling ---- - mt7925/mcu.c | 20 ++++++++++++++------ - 1 file changed, 14 insertions(+), 6 deletions(-) - ---- a/mt7925/mcu.c -+++ b/mt7925/mcu.c -@@ -1341,15 +1341,23 @@ int mt7925_mcu_set_mlo_roc(struct mt792x - for (i = 0; i < ARRAY_SIZE(links); i++) { - links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) : - mconf->link_id; -+ - link_conf = mt792x_vif_to_bss_conf(vif, links[i].id); -- if (WARN_ON_ONCE(!link_conf)) -- return -EPERM; -+ if (!link_conf) -+ return -ENOLINK; - - links[i].chan = link_conf->chanreq.oper.chan; -- if (WARN_ON_ONCE(!links[i].chan)) -- return -EPERM; -+ if (!links[i].chan) -+ /* Channel not configured yet - this can happen during -+ * MLO AP setup when links are being added sequentially. -+ * Return -ENOLINK to indicate link not ready. -+ */ -+ return -ENOLINK; - - links[i].mconf = mt792x_vif_to_link(mvif, links[i].id); -+ if (!links[i].mconf) -+ return -ENOLINK; -+ - links[i].tag = links[i].id == mconf->link_id ? - UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK; - -@@ -1364,8 +1372,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x - type = MT7925_ROC_REQ_JOIN; - - for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) { -- if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan)) -- continue; -+ if (!links[i].mconf || !links[i].chan) -+ return -ENOLINK; - - chan = links[i].chan; - center_ch = ieee80211_frequency_to_channel(chan->center_freq); diff --git a/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch b/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch deleted file mode 100644 index 84028f1c7..000000000 --- a/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 3f898f3367d6f211e8c40aa6d9144a45eb47b066 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Mon, 5 Jan 2026 13:17:14 -0800 -Subject: [PATCH 14/24] wifi: mt76: mt7925: add NULL checks for MLO link - pointers in MCU functions - -Several MCU functions dereference pointers returned by mt792x_sta_to_link() -and mt792x_vif_to_link() without checking for NULL. During MLO state -transitions, these functions can return NULL when link state is being -set up or torn down, causing kernel NULL pointer dereferences. - -Add NULL checks in the following functions: - -- mt7925_mcu_sta_hdr_trans_tlv(): Check mlink before dereferencing wcid -- mt7925_mcu_wtbl_update_hdr_trans(): Check mlink and mconf before use -- mt7925_mcu_sta_amsdu_tlv(): Check mlink before setting amsdu flag -- mt7925_mcu_sta_mld_tlv(): Check mconf and mlink in link iteration loop -- mt7925_mcu_sta_update(): Initialize mlink to NULL and check both - link_sta and mlink in the ternary condition - -Signed-off-by: Zac Bowling ---- - mt7925/mcu.c | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - ---- a/mt7925/mcu.c -+++ b/mt7925/mcu.c -@@ -1087,6 +1087,8 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_b - struct mt792x_link_sta *mlink; - - mlink = mt792x_sta_to_link(msta, link_sta->link_id); -+ if (!mlink) -+ return; - wcid = &mlink->wcid; - } else { - wcid = &mvif->sta.deflink.wcid; -@@ -1120,6 +1122,9 @@ int mt7925_mcu_wtbl_update_hdr_trans(str - link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); - mconf = mt792x_vif_to_link(mvif, link_id); - -+ if (!mlink || !mconf) -+ return -EINVAL; -+ - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, - &mlink->wcid, - MT7925_STA_UPDATE_MAX_SIZE); -@@ -1756,6 +1761,8 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff - amsdu->amsdu_en = true; - - mlink = mt792x_sta_to_link(msta, link_sta->link_id); -+ if (!mlink) -+ return; - mlink->wcid.amsdu = true; - - switch (link_sta->agg.max_amsdu_len) { -@@ -1958,6 +1965,9 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *s - - mconf = mt792x_vif_to_link(mvif, i); - mlink = mt792x_sta_to_link(msta, i); -+ if (!mconf || !mlink) -+ continue; -+ - mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); - mld->link[cnt++].bss_idx = mconf->mt76.idx; - -@@ -2050,7 +2060,7 @@ int mt7925_mcu_sta_update(struct mt792x_ - .rcpi = to_rcpi(rssi), - }; - struct mt792x_sta *msta; -- struct mt792x_link_sta *mlink; -+ struct mt792x_link_sta *mlink = NULL; - - lockdep_assert_held(&dev->mt76.mutex); - -@@ -2058,7 +2068,7 @@ int mt7925_mcu_sta_update(struct mt792x_ - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); - } -- info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid; -+ info.wcid = (link_sta && mlink) ? &mlink->wcid : &mvif->sta.deflink.wcid; - info.newly = state != MT76_STA_INFO_STATE_ASSOC; - - return mt7925_mcu_sta_cmd(&dev->mphy, &info); diff --git a/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch b/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch deleted file mode 100644 index be6f50d39..000000000 --- a/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 59e0921dd7e913052f2b69b93ea544417595f118 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Thu, 1 Jan 2026 14:01:50 -0800 -Subject: [PATCH 15/24] wifi: mt76: mt792x: fix firmware reload failure after - previous load crash - -If the firmware loading process crashes or is interrupted after -acquiring the patch semaphore but before releasing it, subsequent -firmware load attempts will fail with 'Failed to get patch semaphore' -because the semaphore is still held. - -This issue manifests as devices becoming unusable after suspend/resume -failures or firmware crashes, requiring a full hardware reboot to -recover. This has been widely reported on MT7921 and MT7925 devices. - -Apply the same fix that was applied to MT7915 in commit 79dd14f: -1. Release the patch semaphore before starting firmware load (in case - it was held by a previous failed attempt) -2. Restart MCU firmware to ensure clean state -3. Wait briefly for MCU to be ready - -This fix applies to both MT7921 and MT7925 drivers which share the -mt792x_load_firmware() function. - -Fixes: 'Failed to get patch semaphore' errors after firmware crash -Signed-off-by: Zac Bowling ---- - mt792x_core.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - ---- a/mt792x_core.c -+++ b/mt792x_core.c -@@ -935,6 +935,20 @@ int mt792x_load_firmware(struct mt792x_d - { - int ret; - -+ /* Release semaphore if taken by previous failed load attempt. -+ * This prevents "Failed to get patch semaphore" errors when -+ * recovering from firmware crashes or suspend/resume failures. -+ */ -+ ret = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); -+ if (ret < 0) -+ dev_dbg(dev->mt76.dev, "Semaphore release returned %d (may be expected)\n", ret); -+ -+ /* Always restart MCU to ensure clean state before loading firmware */ -+ mt76_connac_mcu_restart(&dev->mt76); -+ -+ /* Wait for MCU to be ready after restart */ -+ msleep(100); -+ - ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); - if (ret) - return ret; diff --git a/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch b/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch deleted file mode 100644 index 3c8205f4c..000000000 --- a/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c99b552b61470ff398b632fea8fcc4b5ee253223 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Wed, 14 Jan 2026 19:54:46 -0800 -Subject: [PATCH 16/24] wifi: mt76: mt7925: add mutex protection in resume path - -Add mutex protection around mt7925_mcu_set_deep_sleep() and -mt7925_regd_update() calls in the resume path to prevent -potential race conditions during resume operations. - -These MCU operations require serialization, and the resume -path was the only call site missing mutex protection. - -Signed-off-by: Zac Bowling ---- - mt7925/pci.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/mt7925/pci.c -+++ b/mt7925/pci.c -@@ -584,10 +584,12 @@ static int _mt7925_pci_resume(struct dev - } - - /* restore previous ds setting */ -+ mt792x_mutex_acquire(dev); - if (!pm->ds_enable) - mt7925_mcu_set_deep_sleep(dev, false); - - mt7925_mcu_regd_update(dev, mdev->alpha2, dev->country_ie_env); -+ mt792x_mutex_release(dev); - failed: - pm->suspended = false; - diff --git a/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch b/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch deleted file mode 100644 index 751a05fa6..000000000 --- a/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch +++ /dev/null @@ -1,48 +0,0 @@ -From d4e0c1a849c99da51e6926947b1bd4c4757801e9 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Mon, 5 Jan 2026 13:19:02 -0800 -Subject: [PATCH 17/24] wifi: mt76: mt7925: add NULL checks for link pointers - in sta_add and conf_tx - -Add NULL pointer checks for mt792x_sta_to_link() and mt792x_vif_to_link() -results in mt7925_mac_link_sta_add() and mt7925_conf_tx() to prevent -kernel crashes during MLO operations. - -The init.c changes from the original patch are not needed as the -mt7925_regd_update() function was refactored in 6.19-rc4. - -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -879,12 +879,17 @@ static int mt7925_mac_link_sta_add(struc - - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_id); -+ if (!mlink) -+ return -EINVAL; - - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); - if (idx < 0) - return -ENOSPC; - - mconf = mt792x_vif_to_link(mvif, link_id); -+ if (!mconf) -+ return -EINVAL; -+ - mt76_wcid_init(&mlink->wcid, 0); - mlink->wcid.sta = 1; - mlink->wcid.idx = idx; -@@ -1751,6 +1756,9 @@ mt7925_conf_tx(struct ieee80211_hw *hw, - [IEEE80211_AC_BK] = 1, - }; - -+ if (!mconf) -+ return -EINVAL; -+ - /* firmware uses access class index */ - mconf->queue_params[mq_to_aci[queue]] = *params; - diff --git a/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch b/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch deleted file mode 100644 index 6c9c625d8..000000000 --- a/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 593bb9c6da996644f40acf32abe5f1ae7fe406c3 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Thu, 15 Jan 2026 16:35:55 -0800 -Subject: [PATCH 18/24] wifi: mt76: mt7925: fix BA session teardown during - beacon loss - -The ieee80211_stop_tx_ba_cb_irqsafe() callback was conditionally called -only when the MCU command succeeded. However, during beacon connection -loss, the MCU command may fail because the AP is no longer reachable. - -If the callback is not called, mac80211's BA session state machine gets -stuck in an intermediate state. When mac80211 later tries to tear down -all BA sessions during disconnection, it hits a WARN in -__ieee80211_stop_tx_ba_session() due to the inconsistent state. - -Fix by making the callback unconditional, matching the behavior of -mt7921 and mt7996 drivers. The MCU command failure is acceptable during -disconnection - what matters is that mac80211 is notified to complete -the session teardown. - -Reported-by: Sean Wang -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -1331,9 +1331,13 @@ mt7925_ampdu_action(struct ieee80211_hw - case IEEE80211_AMPDU_TX_STOP_CONT: - mtxq->aggr = false; - clear_bit(tid, &msta->deflink.wcid.ampdu_state); -- ret = mt7925_mcu_uni_tx_ba(dev, params, false); -- if (!ret) -- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); -+ /* MCU command may fail during beacon loss, but callback must -+ * always be called to complete the BA session teardown in -+ * mac80211. Otherwise the state machine gets stuck and triggers -+ * WARN in __ieee80211_stop_tx_ba_session(). -+ */ -+ mt7925_mcu_uni_tx_ba(dev, params, false); -+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - } - mt792x_mutex_release(dev); diff --git a/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch b/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch deleted file mode 100644 index 066d3b5ce..000000000 --- a/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 95dc76b6053151eeedaaa1477ffa26990fdb5fc8 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Fri, 16 Jan 2026 21:59:42 -0800 -Subject: [PATCH 19/24] wifi: mt76: mt7925: fix deadlock in sta removal ROC - abort path - -Fix a mutex deadlock that occurs during station removal when -cancel_work_sync() is called while already holding the device mutex. - -The deadlock occurs in the following scenario: - -Thread A (mac80211 sta_state callback): - mt76_sta_state() - -> mt76_sta_remove() - -> mutex_lock(&dev->mutex) // ACQUIRES MUTEX - -> __mt76_sta_remove() - -> mt7925_mac_sta_remove() - -> mt7925_mac_sta_remove_links() - -> mt7925_mac_link_sta_remove() - -> mt7925_roc_abort_sync() - -> cancel_work_sync(&roc_work) - // WAITS for roc_work - -Thread B (workqueue): - mt7925_roc_work() - -> mt792x_mutex_acquire() // BLOCKED waiting for mutex - -This results in a classic AB-BA deadlock where Thread A holds the mutex -and waits for roc_work to complete, while roc_work (Thread B) is blocked -waiting for the same mutex. - -From user reports (Framework Laptop 16 with MT7925, NixOS, kernel 6.18.5): - - INFO: task kworker/u128:0:48737 blocked for more than 122 seconds. - Workqueue: mt76 mt7925_mac_reset_work [mt7925_common] - Call Trace: - - __schedule+0x426/0x12c0 - schedule+0x27/0xf0 - schedule_preempt_disabled+0x15/0x30 - __mutex_lock.constprop.0+0x3d0/0x6d0 - mt7925_mac_reset_work+0x85/0x170 [mt7925_common] - ... - - Showing all locks held in the system: - 1 lock held by kworker/u128:5/48827: - #0: ffff9fff8179d930 (&dev->mutex){+.+.}-{4:4}, at: mt76_sta_remove - -The deadlock is triggered by roaming events (moving away from AP, BSSID -changes) when ROC work is pending and station removal occurs. - -The fix introduces an asynchronous ROC abort mechanism: - -1. Add MT76_STATE_ROC_ABORT flag to signal abort request -2. Create mt7925_roc_abort_async() that sets the flag without blocking -3. Modify mt7925_roc_work() to check abort flag BEFORE acquiring mutex -4. Use async abort in mt7925_mac_link_sta_remove() instead of sync - -The key insight is that if roc_work sees the abort flag before trying -to acquire the mutex, it can clean up and exit without blocking. This -breaks the deadlock chain while still ensuring proper ROC cleanup. - -Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") -Reported-by: Aritz Beobide-Cardinal -Signed-off-by: Zac Bowling ---- - mt76.h | 1 + - mt7925/main.c | 40 +++++++++++++++++++++++++++++++++++++++- - 2 files changed, 40 insertions(+), 1 deletion(-) - ---- a/mt76.h -+++ b/mt76.h -@@ -525,6 +525,7 @@ enum { - MT76_STATE_POWER_OFF, - MT76_STATE_SUSPEND, - MT76_STATE_ROC, -+ MT76_STATE_ROC_ABORT, - MT76_STATE_PM, - MT76_STATE_WED_RESET, - }; ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -457,6 +457,29 @@ static void mt7925_roc_iter(void *priv, - mt7925_mcu_abort_roc(phy, &mvif->bss_conf, phy->roc_token_id); - } - -+/* Async ROC abort - safe to call while holding mutex. -+ * Sets abort flag and lets roc_work handle cleanup without blocking. -+ * This prevents deadlock when called from sta_remove path which holds mutex. -+ */ -+static void mt7925_roc_abort_async(struct mt792x_dev *dev) -+{ -+ struct mt792x_phy *phy = &dev->phy; -+ -+ /* Set abort flag first - roc_work checks this before acquiring mutex */ -+ set_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); -+ -+ /* Clear ROC state */ -+ clear_bit(MT76_STATE_ROC, &phy->mt76->state); -+ -+ /* Stop the timer - use non-sync version to avoid blocking */ -+ timer_delete(&phy->roc_timer); -+ -+ /* Do NOT call cancel_work_sync here - that would deadlock if -+ * roc_work is waiting for mutex that we (caller) already hold. -+ * The work will see the abort flag and clean up gracefully. -+ */ -+} -+ - void mt7925_roc_abort_sync(struct mt792x_dev *dev) - { - struct mt792x_phy *phy = &dev->phy; -@@ -481,6 +504,17 @@ void mt7925_roc_work(struct work_struct - phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, - roc_work); - -+ /* Check abort flag BEFORE acquiring mutex to prevent deadlock. -+ * If abort is requested while we're in the sta_remove path (which -+ * holds the mutex), we must not try to acquire it or we'll deadlock. -+ * Just clear the flags and notify mac80211 that ROC expired. -+ */ -+ if (test_and_clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state)) { -+ clear_bit(MT76_STATE_ROC, &phy->mt76->state); -+ ieee80211_remain_on_channel_expired(phy->mt76->hw); -+ return; -+ } -+ - if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - return; - -@@ -1143,7 +1177,11 @@ static void mt7925_mac_link_sta_remove(s - if (!mlink) - return; - -- mt7925_roc_abort_sync(dev); -+ /* Use async abort to prevent deadlock - this function is called from -+ * mt76_sta_remove() which already holds dev->mt76.mutex. Using the -+ * sync version would deadlock if roc_work is waiting for the same mutex. -+ */ -+ mt7925_roc_abort_async(dev); - - mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); - mt76_connac_pm_wake(&dev->mphy, &dev->pm); diff --git a/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch b/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch deleted file mode 100644 index 35c260284..000000000 --- a/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 428960f8f65f3be6a11910eba3e1f1000a80c4f6 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Mon, 19 Jan 2026 12:28:11 -0800 -Subject: [PATCH 20/24] wifi: mt76: mt7925: fix ROC timer race during suspend - -Cancel ROC timer and work in mt7925_suspend() (mac80211 callback) -before mac80211 finishes quiescing. Previously this was only done -in mt7925_pci_suspend() which is called later. - -The race condition: -1. mac80211 sets quiescing=true -2. mac80211 calls mt7925_suspend() - ROC timer still active -3. ROC timer fires, calls ieee80211_queue_work() -> warning -4. Later, mt7925_pci_suspend() cancels ROC timer (too late) - -This can leave the driver in an inconsistent state causing freezes -on resume. By canceling the ROC work early in the mac80211 suspend -callback, we ensure no ROC operations are pending when quiescing -begins. - -Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -1584,6 +1584,18 @@ static int mt7925_suspend(struct ieee802 - cancel_delayed_work_sync(&dev->pm.ps_work); - mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); - -+ /* Cancel ROC timer and work before mac80211 finishes quiescing. -+ * This must happen here, not in pci_suspend, because mac80211 -+ * sets quiescing=true before calling this callback. If the ROC -+ * timer fires after quiescing starts, ieee80211_queue_work() will -+ * fail and leave the driver in an inconsistent state. -+ * -+ * IMPORTANT: Must be called BEFORE mutex_acquire to avoid deadlock. -+ * If roc_work is running and waiting for mutex, cancel_work_sync -+ * would block forever if we already hold the mutex. -+ */ -+ mt7925_roc_abort_sync(dev); -+ - mt792x_mutex_acquire(dev); - - clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); diff --git a/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch b/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch deleted file mode 100644 index 511a636a6..000000000 --- a/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch +++ /dev/null @@ -1,254 +0,0 @@ -From 846ac23af31d165ce310257c91052518730d1604 Mon Sep 17 00:00:00 2001 -From: Zac Bowling -Date: Mon, 19 Jan 2026 12:32:01 -0800 -Subject: [PATCH 21/24] wifi: mt76: mt7925: add ROC rate limiting to mitigate - MLO auth failures - -Add exponential backoff rate limiting for ROC (Remain On Channel) -commands to prevent MCU overload during rapid reconnection cycles. - -Problem: -When MLO (Multi-Link Operation) authentication fails due to an upper -layer race condition, the driver enters a rapid reconnection loop that -overwhelms the MCU with ROC commands, causing timeouts and firmware -resets. - -Root Cause (upper layer bug, not fixed by this patch): -The kernel's nl80211 layer at net/wireless/nl80211.c:4828 requires -link_id for group key operations when MLO is active (wdev->valid_links -is set). During Fast Transition (802.11r) roaming: - -1. Device is connected in MLO mode (wdev->valid_links = bitmask) -2. FT roaming begins to new AP -3. wpa_supplicant attempts to set group keys without link_id -4. Disconnect hasn't completed yet - valid_links still set -5. nl80211 validation fails: "link ID must for MLO group key" -6. This triggers reconnection attempts with ROC commands -7. MCU overwhelmed -> timeouts -> firmware reset -> cycle repeats - -The race is between disconnect (which clears valid_links in -cfg80211's __cfg80211_disconnected at sme.c:1359) and key setup. - -This Mitigation: -- Track consecutive ROC timeouts in mt792x_phy structure -- Implement exponential backoff: 100ms, 200ms, 400ms, 800ms, 1600ms -- Reset backoff after 10 seconds of no timeouts -- Log warning after 5 consecutive timeouts to help identify the issue -- Short backoffs (<200ms) wait inline; longer ones return -EBUSY - -This doesn't fix the root cause but prevents the system from becoming -unresponsive during the failure cycle, giving users time to work around -the issue (e.g., disable MLO or use single-link WiFi 7). - -Upstream Bug Reports Needed: -- wpa_supplicant: MLO group key setup missing link_id during FT roaming -- mac80211/cfg80211: Race between disconnect and key setup sequencing - -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-- - mt792x.h | 7 +++ - 2 files changed, 136 insertions(+), 4 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -542,14 +542,108 @@ static int mt7925_abort_roc(struct mt792 - return err; - } - -+/* ROC rate limiting constants - exponential backoff to prevent MCU overload -+ * when upper layers trigger rapid reconnection cycles (e.g., MLO auth failures). -+ * Max backoff ~1.6s, resets after 10s of no timeouts. -+ */ -+#define MT7925_ROC_BACKOFF_BASE_MS 100 -+#define MT7925_ROC_BACKOFF_MAX_MS 1600 -+#define MT7925_ROC_TIMEOUT_RESET_MS 10000 -+#define MT7925_ROC_TIMEOUT_WARN_THRESH 5 -+ -+/* Check if ROC should be throttled due to recent timeouts. -+ * Returns delay in jiffies if throttling, 0 if OK to proceed. -+ */ -+static unsigned long mt7925_roc_throttle_check(struct mt792x_phy *phy) -+{ -+ unsigned long now = jiffies; -+ -+ /* Reset timeout counter if it's been a while since last timeout */ -+ if (phy->roc_timeout_count && -+ time_after(now, phy->roc_last_timeout + -+ msecs_to_jiffies(MT7925_ROC_TIMEOUT_RESET_MS))) { -+ phy->roc_timeout_count = 0; -+ phy->roc_backoff_until = 0; -+ } -+ -+ /* Check if we're still in backoff period */ -+ if (phy->roc_backoff_until && time_before(now, phy->roc_backoff_until)) -+ return phy->roc_backoff_until - now; -+ -+ return 0; -+} -+ -+/* Record ROC timeout and calculate backoff period */ -+static void mt7925_roc_record_timeout(struct mt792x_phy *phy) -+{ -+ unsigned int backoff_ms; -+ -+ phy->roc_last_timeout = jiffies; -+ phy->roc_timeout_count++; -+ -+ /* Exponential backoff: 100ms, 200ms, 400ms, 800ms, 1600ms (capped) */ -+ backoff_ms = MT7925_ROC_BACKOFF_BASE_MS << -+ min_t(u8, phy->roc_timeout_count - 1, 4); -+ if (backoff_ms > MT7925_ROC_BACKOFF_MAX_MS) -+ backoff_ms = MT7925_ROC_BACKOFF_MAX_MS; -+ -+ phy->roc_backoff_until = jiffies + msecs_to_jiffies(backoff_ms); -+ -+ /* Warn if we're seeing repeated timeouts - likely upper layer issue */ -+ if (phy->roc_timeout_count == MT7925_ROC_TIMEOUT_WARN_THRESH) -+ dev_warn(phy->dev->mt76.dev, -+ "mt7925: %u consecutive ROC timeouts, possible mac80211/wpa_supplicant issue (MLO key race?)\n", -+ phy->roc_timeout_count); -+} -+ -+/* Clear timeout tracking on successful ROC */ -+static void mt7925_roc_clear_timeout(struct mt792x_phy *phy) -+{ -+ phy->roc_timeout_count = 0; -+ phy->roc_backoff_until = 0; -+} -+ - static int mt7925_set_roc(struct mt792x_phy *phy, - struct mt792x_bss_conf *mconf, - struct ieee80211_channel *chan, - int duration, - enum mt7925_roc_req type) - { -+ unsigned long throttle; - int err; - -+ /* Check rate limiting - if in backoff period, wait or return busy */ -+ throttle = mt7925_roc_throttle_check(phy); -+ if (throttle) { -+ /* For short backoffs, wait; for longer ones, return busy */ -+ if (throttle < msecs_to_jiffies(200)) { -+ msleep(jiffies_to_msecs(throttle)); -+ } else { -+ dev_dbg(phy->dev->mt76.dev, -+ "mt7925: ROC throttled, %lu ms remaining\n", -+ jiffies_to_msecs(throttle)); -+ return -EBUSY; -+ } -+ } -+ -+ /* Clear any stale abort flag from previous ROC abort_async calls. -+ * If abort_async was called but roc_work never ran (timer was cancelled -+ * before firing), the abort flag would be stale and incorrectly abort -+ * this new ROC session. -+ */ -+ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); -+ -+ /* Cancel any pending roc_work from a previous async-aborted ROC. -+ * This prevents a race where stale work could abort our new ROC: -+ * 1. Previous ROC's roc_work clears ROC flag with test_and_clear -+ * 2. Work blocks waiting for mutex -+ * 3. abort_async called, sets abort flag -+ * 4. New ROC starts here, clears abort flag, sets ROC flag -+ * 5. Stale work gets mutex, calls mcu_abort_roc with NEW token -+ * Safe to call here since we don't hold the mutex yet. -+ */ -+ cancel_work_sync(&phy->roc_work); -+ - if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) - return -EBUSY; - -@@ -565,7 +659,11 @@ static int mt7925_set_roc(struct mt792x_ - if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { - mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); - clear_bit(MT76_STATE_ROC, &phy->mt76->state); -+ mt7925_roc_record_timeout(phy); - err = -ETIMEDOUT; -+ } else { -+ /* Successful ROC - reset timeout tracking */ -+ mt7925_roc_clear_timeout(phy); - } - - out: -@@ -576,8 +674,32 @@ static int mt7925_set_mlo_roc(struct mt7 - struct mt792x_bss_conf *mconf, - u16 sel_links) - { -+ unsigned long throttle; - int err; - -+ /* Check rate limiting - MLO ROC is especially prone to rapid-fire -+ * during reconnection cycles after MLO authentication failures. -+ */ -+ throttle = mt7925_roc_throttle_check(phy); -+ if (throttle) { -+ if (throttle < msecs_to_jiffies(200)) { -+ msleep(jiffies_to_msecs(throttle)); -+ } else { -+ dev_dbg(phy->dev->mt76.dev, -+ "mt7925: MLO ROC throttled, %lu ms remaining\n", -+ jiffies_to_msecs(throttle)); -+ return -EBUSY; -+ } -+ } -+ -+ /* Clear any stale abort flag from previous ROC abort_async calls */ -+ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); -+ -+ /* Cancel any pending roc_work from a previous async-aborted ROC. -+ * See comment in mt7925_set_roc for the race condition this prevents. -+ */ -+ cancel_work_sync(&phy->roc_work); -+ - if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) - return -EBUSY; - -@@ -592,7 +714,10 @@ static int mt7925_set_mlo_roc(struct mt7 - if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { - mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); - clear_bit(MT76_STATE_ROC, &phy->mt76->state); -+ mt7925_roc_record_timeout(phy); - err = -ETIMEDOUT; -+ } else { -+ mt7925_roc_clear_timeout(phy); - } - - out: -@@ -916,14 +1041,14 @@ static int mt7925_mac_link_sta_add(struc - if (!mlink) - return -EINVAL; - -- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); -- if (idx < 0) -- return -ENOSPC; -- - mconf = mt792x_vif_to_link(mvif, link_id); - if (!mconf) - return -EINVAL; - -+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); -+ if (idx < 0) -+ return -ENOSPC; -+ - mt76_wcid_init(&mlink->wcid, 0); - mlink->wcid.sta = 1; - mlink->wcid.idx = idx; ---- a/mt792x.h -+++ b/mt792x.h -@@ -186,6 +186,13 @@ struct mt792x_phy { - wait_queue_head_t roc_wait; - u8 roc_token_id; - bool roc_grant; -+ -+ /* ROC rate limiting to prevent MCU overload during rapid reconnection -+ * cycles (e.g., MLO authentication failures causing repeated ROC). -+ */ -+ u8 roc_timeout_count; /* consecutive ROC timeouts */ -+ unsigned long roc_last_timeout; /* jiffies of last timeout */ -+ unsigned long roc_backoff_until;/* don't issue ROC until this time */ - }; - - struct mt792x_irq_map { diff --git a/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch b/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch deleted file mode 100644 index 8ed74863f..000000000 --- a/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch +++ /dev/null @@ -1,184 +0,0 @@ -From 30c7e8a14f796c38176fe444e1d9af5900eed783 Mon Sep 17 00:00:00 2001 -From: Zac -Date: Mon, 19 Jan 2026 14:36:54 -0800 -Subject: [PATCH 22/24] wifi: mt76: mt7925: improve error handling and code - cleanup - -Address suggestions from code review: - -1. Remove redundant NULL check in mt7925_mcu_set_mlo_roc() - The check for links[i].mconf and links[i].chan at line 1375 was - redundant because the same check was already performed in the - initialization loop above. - -2. Add error logging for mt7925_mcu_add_bss_info() calls - Several call sites were not checking return values. While failures - in these paths often cannot be recovered from, logging helps with - debugging. Added dev_warn() logging in: - - beacon loss handler - - sta removal path - - link removal path - - stop_ap - - chanctx assign/unassign - -3. Add missing NULL check for mconf in link removal - mt792x_link_conf_to_mconf() can return NULL - add check before use. - -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 66 ++++++++++++++++++++++++++++++++++++++------------- - mt7925/mcu.c | 3 --- - 2 files changed, 49 insertions(+), 20 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -1248,11 +1248,17 @@ static void mt7925_mac_link_sta_assoc(st - - if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { - struct mt792x_bss_conf *mconf; -+ int ret; - - mconf = mt792x_link_conf_to_mconf(link_conf); -- if (mconf) -- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -- link_conf, link_sta, true); -+ if (mconf) { -+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -+ link_conf, link_sta, true); -+ if (ret) -+ dev_warn(dev->mt76.dev, -+ "failed to update BSS info during beacon loss (ret=%d)\n", -+ ret); -+ } - } - - ewma_avg_signal_init(&mlink->avg_ack_signal); -@@ -1320,16 +1326,21 @@ static void mt7925_mac_link_sta_remove(s - - if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { - struct mt792x_bss_conf *mconf; -+ int ret; - - mconf = mt792x_link_conf_to_mconf(link_conf); - if (!mconf) - goto out; - -- if (ieee80211_vif_is_mld(vif)) -+ if (ieee80211_vif_is_mld(vif)) { - mt792x_mac_link_bss_remove(dev, mconf, mlink); -- else -- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, -- link_sta, false); -+ } else { -+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -+ link_conf, link_sta, false); -+ if (ret) -+ dev_warn(dev->mt76.dev, -+ "failed to remove BSS info (ret=%d)\n", ret); -+ } - } - out: - -@@ -1349,6 +1360,7 @@ mt7925_mac_sta_remove_links(struct mt792 - struct mt76_dev *mdev = &dev->mt76; - struct mt76_wcid *wcid; - unsigned int link_id; -+ int ret; - - /* clean up bss before starec */ - for_each_set_bit(link_id, &old_links, IEEE80211_MLD_MAX_NUM_LINKS) { -@@ -1373,9 +1385,14 @@ mt7925_mac_sta_remove_links(struct mt792 - continue; - - mconf = mt792x_link_conf_to_mconf(link_conf); -+ if (!mconf) -+ continue; - -- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, -- link_sta, false); -+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, -+ link_conf, link_sta, false); -+ if (ret) -+ dev_warn(dev->mt76.dev, -+ "failed to remove link BSS info (ret=%d)\n", ret); - } - - for_each_set_bit(link_id, &old_links, IEEE80211_MLD_MAX_NUM_LINKS) { -@@ -1985,8 +2002,11 @@ mt7925_stop_ap(struct ieee80211_hw *hw, - if (err) - goto out; - -- mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, link_conf, -- NULL, false); -+ err = mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, -+ link_conf, NULL, false); -+ if (err) -+ dev_warn(dev->mt76.dev, -+ "failed to remove BSS info in stop_ap (ret=%d)\n", err); - - out: - mt792x_mutex_release(dev); -@@ -2357,6 +2377,7 @@ static int mt7925_assign_vif_chanctx(str - struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct ieee80211_bss_conf *pri_link_conf; - struct mt792x_bss_conf *mconf; -+ int ret; - - mutex_lock(&dev->mt76.mutex); - -@@ -2370,9 +2391,14 @@ static int mt7925_assign_vif_chanctx(str - pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); - - if (pri_link_conf && vif->type == NL80211_IFTYPE_STATION && -- mconf == &mvif->bss_conf) -- mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf, -- NULL, true); -+ mconf == &mvif->bss_conf) { -+ ret = mt7925_mcu_add_bss_info(&dev->phy, NULL, -+ pri_link_conf, NULL, true); -+ if (ret) -+ dev_warn(dev->mt76.dev, -+ "failed to add BSS info in chanctx assign (ret=%d)\n", -+ ret); -+ } - } else { - mconf = &mvif->bss_conf; - } -@@ -2393,6 +2419,7 @@ static void mt7925_unassign_vif_chanctx( - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt792x_bss_conf *mconf; -+ int ret; - - mutex_lock(&dev->mt76.mutex); - -@@ -2404,9 +2431,14 @@ static void mt7925_unassign_vif_chanctx( - } - - if (vif->type == NL80211_IFTYPE_STATION && -- mconf == &mvif->bss_conf) -- mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, -- NULL, false); -+ mconf == &mvif->bss_conf) { -+ ret = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, -+ NULL, false); -+ if (ret) -+ dev_warn(dev->mt76.dev, -+ "failed to remove BSS info in chanctx unassign (ret=%d)\n", -+ ret); -+ } - } else { - mconf = &mvif->bss_conf; - } ---- a/mt7925/mcu.c -+++ b/mt7925/mcu.c -@@ -1377,9 +1377,6 @@ int mt7925_mcu_set_mlo_roc(struct mt792x - type = MT7925_ROC_REQ_JOIN; - - for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) { -- if (!links[i].mconf || !links[i].chan) -- return -ENOLINK; -- - chan = links[i].chan; - center_ch = ieee80211_frequency_to_channel(chan->center_freq); - req.roc[i].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)); diff --git a/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch b/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch deleted file mode 100644 index b23613d77..000000000 --- a/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch +++ /dev/null @@ -1,169 +0,0 @@ -From e4c4a356794090e0a5b2dec0a5b8b40c80e60d84 Mon Sep 17 00:00:00 2001 -From: Zac -Date: Mon, 19 Jan 2026 15:00:33 -0800 -Subject: [PATCH 23/24] wifi: mt76: mt7925: fix deadlock and WCID leak bugs - -Fix two bugs identified by code review: - -1. Potential deadlock in ROC path: - cancel_work_sync() was called inside mt7925_set_roc() and - mt7925_set_mlo_roc() while the mutex was already held by the - caller (e.g., mt7925_remain_on_channel). If roc_work was waiting - for the mutex, this would deadlock. Move cancel_work_sync() to - callers, before they acquire the mutex. - -2. WCID resource leak in mt7925_mac_link_sta_add: - After WCID allocation and registration (rcu_assign_pointer), - multiple error paths returned without cleaning up the WCID index. - This could exhaust the WCID table over time. Add proper error - cleanup path that clears the wcid pointer and frees the index. - -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 59 +++++++++++++++++++++++++++++---------------------- - 1 file changed, 34 insertions(+), 25 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -630,20 +630,12 @@ static int mt7925_set_roc(struct mt792x_ - * If abort_async was called but roc_work never ran (timer was cancelled - * before firing), the abort flag would be stale and incorrectly abort - * this new ROC session. -+ * -+ * Note: cancel_work_sync must be called by our callers BEFORE they -+ * acquire the mutex, to prevent deadlock. See mt7925_remain_on_channel. - */ - clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); - -- /* Cancel any pending roc_work from a previous async-aborted ROC. -- * This prevents a race where stale work could abort our new ROC: -- * 1. Previous ROC's roc_work clears ROC flag with test_and_clear -- * 2. Work blocks waiting for mutex -- * 3. abort_async called, sets abort flag -- * 4. New ROC starts here, clears abort flag, sets ROC flag -- * 5. Stale work gets mutex, calls mcu_abort_roc with NEW token -- * Safe to call here since we don't hold the mutex yet. -- */ -- cancel_work_sync(&phy->roc_work); -- - if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) - return -EBUSY; - -@@ -692,13 +684,11 @@ static int mt7925_set_mlo_roc(struct mt7 - } - } - -- /* Clear any stale abort flag from previous ROC abort_async calls */ -- clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); -- -- /* Cancel any pending roc_work from a previous async-aborted ROC. -- * See comment in mt7925_set_roc for the race condition this prevents. -+ /* Clear any stale abort flag from previous ROC abort_async calls. -+ * Note: cancel_work_sync must be called by our callers BEFORE they -+ * acquire the mutex, to prevent deadlock. - */ -- cancel_work_sync(&phy->roc_work); -+ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); - - if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) - return -EBUSY; -@@ -734,6 +724,11 @@ static int mt7925_remain_on_channel(stru - struct mt792x_phy *phy = mt792x_hw_phy(hw); - int err; - -+ /* Cancel any pending ROC work BEFORE acquiring mutex to prevent -+ * deadlock. The work may be waiting for mutex we're about to take. -+ */ -+ cancel_work_sync(&phy->roc_work); -+ - mt792x_mutex_acquire(phy->dev); - err = mt7925_set_roc(phy, &mvif->bss_conf, - chan, duration, MT7925_ROC_REQ_ROC); -@@ -1068,14 +1063,16 @@ static int mt7925_mac_link_sta_add(struc - - ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); - if (ret) -- return ret; -+ goto err_wcid; - - mt7925_mac_wtbl_update(dev, idx, - MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - - link_conf = mt792x_vif_to_bss_conf(vif, link_id); -- if (!link_conf) -- return -EINVAL; -+ if (!link_conf) { -+ ret = -EINVAL; -+ goto err_wcid; -+ } - - /* should update bss info before STA add */ - if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { -@@ -1087,7 +1084,7 @@ static int mt7925_mac_link_sta_add(struc - ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, - link_conf, link_sta, false); - if (ret) -- return ret; -+ goto err_wcid; - } - - if (ieee80211_vif_is_mld(vif) && -@@ -1095,28 +1092,33 @@ static int mt7925_mac_link_sta_add(struc - ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, - MT76_STA_INFO_STATE_NONE); - if (ret) -- return ret; -+ goto err_wcid; - } else if (ieee80211_vif_is_mld(vif) && - link_sta != mlink->pri_link) { - ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, - true, MT76_STA_INFO_STATE_ASSOC); - if (ret) -- return ret; -+ goto err_wcid; - - ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, - MT76_STA_INFO_STATE_ASSOC); - if (ret) -- return ret; -+ goto err_wcid; - } else { - ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, - MT76_STA_INFO_STATE_NONE); - if (ret) -- return ret; -+ goto err_wcid; - } - - mt76_connac_power_save_sched(&dev->mphy, &dev->pm); - - return 0; -+ -+err_wcid: -+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL); -+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx); -+ return ret; - } - - static int -@@ -2096,6 +2098,8 @@ static void mt7925_mgd_prepare_tx(struct - u16 duration = info->duration ? info->duration : - jiffies_to_msecs(HZ); - -+ cancel_work_sync(&mvif->phy->roc_work); -+ - mt792x_mutex_acquire(dev); - mt7925_set_roc(mvif->phy, &mvif->bss_conf, - mvif->bss_conf.mt76.ctx->def.chan, duration, -@@ -2244,6 +2248,11 @@ mt7925_change_vif_links(struct ieee80211 - if (old_links == new_links) - return 0; - -+ /* Cancel any pending ROC work before acquiring mutex to prevent -+ * deadlock if mt7925_set_mlo_roc is called below. -+ */ -+ cancel_work_sync(&phy->roc_work); -+ - mt792x_mutex_acquire(dev); - - for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { diff --git a/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch b/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch deleted file mode 100644 index 4a1420290..000000000 --- a/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch +++ /dev/null @@ -1,147 +0,0 @@ -From a43924caa7a783b4371a03f8d663903015dfb2b1 Mon Sep 17 00:00:00 2001 -From: Zac -Date: Mon, 19 Jan 2026 15:29:29 -0800 -Subject: [PATCH 24/24] wifi: mt76: mt7925: fix race condition in async ROC - abort - -Fix multiple issues in the async ROC abort mechanism: - -1. Schedule roc_work after setting abort flag and deleting timer. - If the timer hasn't fired yet, roc_work would never be scheduled - and MT76_STATE_ROC would remain set permanently, causing future - ROC attempts to fail with -EBUSY. - -2. Remove the clear_bit(MT76_STATE_ROC) call to fix a race where - mac80211 might not receive the ROC expiry notification. - -3. Add missing power_save_sched call in WCID error cleanup path - to balance the pm_wake call and prevent power state imbalance. - -Also clean up verbose intermediate comments throughout ROC code. - -Reported-by: Cursor Bot (code review) -Reported-by: GitHub Copilot (code review) -Signed-off-by: Zac Bowling ---- - mt7925/main.c | 55 ++++++++++----------------------------------------- - 1 file changed, 10 insertions(+), 45 deletions(-) - ---- a/mt7925/main.c -+++ b/mt7925/main.c -@@ -465,19 +465,14 @@ static void mt7925_roc_abort_async(struc - { - struct mt792x_phy *phy = &dev->phy; - -- /* Set abort flag first - roc_work checks this before acquiring mutex */ -+ /* Set abort flag - roc_work checks this before acquiring mutex */ - set_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); - -- /* Clear ROC state */ -- clear_bit(MT76_STATE_ROC, &phy->mt76->state); -- -- /* Stop the timer - use non-sync version to avoid blocking */ -- timer_delete(&phy->roc_timer); -- -- /* Do NOT call cancel_work_sync here - that would deadlock if -- * roc_work is waiting for mutex that we (caller) already hold. -- * The work will see the abort flag and clean up gracefully. -+ /* Stop timer and schedule work to handle cleanup. -+ * Must schedule work since timer may not have fired yet. - */ -+ timer_delete(&phy->roc_timer); -+ ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); - } - - void mt7925_roc_abort_sync(struct mt792x_dev *dev) -@@ -626,14 +621,7 @@ static int mt7925_set_roc(struct mt792x_ - } - } - -- /* Clear any stale abort flag from previous ROC abort_async calls. -- * If abort_async was called but roc_work never ran (timer was cancelled -- * before firing), the abort flag would be stale and incorrectly abort -- * this new ROC session. -- * -- * Note: cancel_work_sync must be called by our callers BEFORE they -- * acquire the mutex, to prevent deadlock. See mt7925_remain_on_channel. -- */ -+ /* Clear stale abort flag from previous ROC */ - clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); - - if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) -@@ -684,10 +672,7 @@ static int mt7925_set_mlo_roc(struct mt7 - } - } - -- /* Clear any stale abort flag from previous ROC abort_async calls. -- * Note: cancel_work_sync must be called by our callers BEFORE they -- * acquire the mutex, to prevent deadlock. -- */ -+ /* Clear stale abort flag from previous ROC */ - clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state); - - if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) -@@ -724,11 +709,7 @@ static int mt7925_remain_on_channel(stru - struct mt792x_phy *phy = mt792x_hw_phy(hw); - int err; - -- /* Cancel any pending ROC work BEFORE acquiring mutex to prevent -- * deadlock. The work may be waiting for mutex we're about to take. -- */ - cancel_work_sync(&phy->roc_work); -- - mt792x_mutex_acquire(phy->dev); - err = mt7925_set_roc(phy, &mvif->bss_conf, - chan, duration, MT7925_ROC_REQ_ROC); -@@ -1118,6 +1099,7 @@ static int mt7925_mac_link_sta_add(struc - err_wcid: - rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx); -+ mt76_connac_power_save_sched(&dev->mphy, &dev->pm); - return ret; - } - -@@ -1310,10 +1292,7 @@ static void mt7925_mac_link_sta_remove(s - if (!mlink) - return; - -- /* Use async abort to prevent deadlock - this function is called from -- * mt76_sta_remove() which already holds dev->mt76.mutex. Using the -- * sync version would deadlock if roc_work is waiting for the same mutex. -- */ -+ /* Async abort - caller already holds mutex */ - mt7925_roc_abort_async(dev); - - mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); -@@ -1728,18 +1707,8 @@ static int mt7925_suspend(struct ieee802 - cancel_delayed_work_sync(&dev->pm.ps_work); - mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); - -- /* Cancel ROC timer and work before mac80211 finishes quiescing. -- * This must happen here, not in pci_suspend, because mac80211 -- * sets quiescing=true before calling this callback. If the ROC -- * timer fires after quiescing starts, ieee80211_queue_work() will -- * fail and leave the driver in an inconsistent state. -- * -- * IMPORTANT: Must be called BEFORE mutex_acquire to avoid deadlock. -- * If roc_work is running and waiting for mutex, cancel_work_sync -- * would block forever if we already hold the mutex. -- */ -+ /* Cancel ROC before quiescing starts */ - mt7925_roc_abort_sync(dev); -- - mt792x_mutex_acquire(dev); - - clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); -@@ -2248,11 +2217,7 @@ mt7925_change_vif_links(struct ieee80211 - if (old_links == new_links) - return 0; - -- /* Cancel any pending ROC work before acquiring mutex to prevent -- * deadlock if mt7925_set_mlo_roc is called below. -- */ - cancel_work_sync(&phy->roc_work); -- - mt792x_mutex_acquire(dev); - - for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index ae9de6117..ce4d4d2c5 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -159,30 +159,6 @@ curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile pushd package/kernel/mt76/patches curl -Os $mirror/openwrt/patch/mt76/patches/100-fix-build-with-linux-6.12rc2.patch curl -Os $mirror/openwrt/patch/mt76/patches/102-use-hrtimer_setup-in-mt76x02u-beacon-init.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0001-wifi-mt76-mt7925-fix-NULL-pointer-dereference-in-vif.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0002-wifi-mt76-mt7925-fix-missing-mutex-protection-in-res.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0003-wifi-mt76-mt7925-fix-missing-mutex-protection-in-run.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0004-wifi-mt76-mt7925-add-NULL-checks-in-MCU-STA-TLV-func.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0005-wifi-mt76-mt7925-add-NULL-checks-for-link_conf-and-m.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0006-wifi-mt76-mt7925-add-error-handling-for-AMPDU-MCU-co.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0007-wifi-mt76-mt7925-add-error-handling-for-BSS-info-MCU.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0008-wifi-mt76-mt7925-add-error-handling-for-BSS-info-in-.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0009-wifi-mt76-mt7925-add-NULL-checks-in-MLO-link-and-cha.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0010-wifi-mt76-mt792x-fix-NULL-pointer-dereference-in-TX-.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0011-wifi-mt76-mt7925-add-lockdep-assertions-for-mutex-ve.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0012-wifi-mt76-mt7925-fix-key-removal-failure-during-MLO-.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0013-wifi-mt76-mt7925-fix-kernel-warning-in-MLO-ROC-setup.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0014-wifi-mt76-mt7925-add-NULL-checks-for-MLO-link-pointe.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0015-wifi-mt76-mt792x-fix-firmware-reload-failure-after-p.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0016-wifi-mt76-mt7925-add-mutex-protection-in-resume-path.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0017-wifi-mt76-mt7925-add-NULL-checks-for-link-pointers-i.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0018-wifi-mt76-mt7925-fix-BA-session-teardown-during-beac.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0019-wifi-mt76-mt7925-fix-deadlock-in-sta-removal-ROC-abo.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0020-wifi-mt76-mt7925-fix-ROC-timer-race-during-suspend.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0021-wifi-mt76-mt7925-add-ROC-rate-limiting-to-mitigate-M.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0022-wifi-mt76-mt7925-improve-error-handling-and-code-cle.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0023-wifi-mt76-mt7925-fix-deadlock-and-WCID-leak-bugs.patch - curl -Os $mirror/openwrt/patch/mt76/patches/0024-wifi-mt76-mt7925-fix-race-condition-in-async-ROC-abo.patch popd # wireless-regdb diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index df4d48010..239e78388 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -126,7 +126,7 @@ git clone https://$github/sbwml/luci-theme-argon -b openwrt-25.12 package/new/lu git clone https://$github/eamonxg/luci-theme-aurora package/new/luci-theme-aurora --depth=1 git clone https://$github/eamonxg/luci-app-aurora-config package/new/luci-app-aurora-config --depth=1 rm -rf package/new/luci-theme-aurora/root/etc/uci-defaults -sed -i 's/100/91/g' package/new/luci-app-aurora-config/root/usr/share/luci/menu.d/luci-app-aurora.json +sed -i 's/100/85/g' package/new/luci-app-aurora-config/root/usr/share/luci/menu.d/luci-app-aurora.json # Mosdns git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 diff --git a/tags/v25 b/tags/v25 index ef8738c6e..e055000e0 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.1 +25.12.2 From 756a6d4d33893f0b67a57d9dbedfb648c4b91c9d Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 19 Apr 2026 12:07:02 +0800 Subject: [PATCH 389/425] linux-6.18: bump to 6.18.22 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 5cd89cd49..f5fce6483 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .20 -LINUX_KERNEL_HASH-6.18.20 = 837a5abd98e46078a0ae1400e2daad89ece45cc3209037b09c2265dab2393553 +LINUX_VERSION-6.18 = .22 +LINUX_KERNEL_HASH-6.18.22 = a23c92faf3657385c2c6b5f4edd8f81b808907ebe603fa30699eae224da55f59 From 54ada5f57793a1e768d429a192eafd29e2b8a309 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 19 Apr 2026 12:08:23 +0800 Subject: [PATCH 390/425] add luci-app-diskman js Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 239e78388..264e95010 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -22,6 +22,9 @@ git clone https://$github/sbwml/package_new_bluez-alsa package/new/bluez-alsa git clone https://$github/timsaya/openwrt-bandix package/new/bandix --depth=1 git clone https://$github/timsaya/luci-app-bandix package/new/luci-app-bandix --depth=1 +# luci-app-diskman +git clone https://$github/sbwml/luci-app-diskman package/new/diskman --depth=1 + # istore git clone https://$github/sbwml/package_new_istore package/new/istore --depth=1 From 3cdbaf690984c205feb81f9f1699689f465d63e1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 26 Apr 2026 10:59:23 +0800 Subject: [PATCH 391/425] linux-6.18: bump to 6.18.24 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index f5fce6483..5eb275ad2 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .22 -LINUX_KERNEL_HASH-6.18.22 = a23c92faf3657385c2c6b5f4edd8f81b808907ebe603fa30699eae224da55f59 +LINUX_VERSION-6.18 = .24 +LINUX_KERNEL_HASH-6.18.24 = c207c557ce58103b4dda30e26da5203f3d8467c6dadc53d709f6d83ae1d1255f From 1602846f54f51ad9feb94dd944e1a964751458e8 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 30 Apr 2026 21:09:34 +0800 Subject: [PATCH 392/425] busybox: drop history save path Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 6ed5d1fde..9bdcfc90a 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -289,6 +289,9 @@ mkdir -p files/root curl -so files/root/.bash_profile $mirror/openwrt/files/root/.bash_profile curl -so files/root/.bashrc $mirror/openwrt/files/root/.bashrc +# busybox +sed -i '/profile\.d/d' package/utils/busybox/Makefile + # rootfs files mkdir -p files/etc/sysctl.d curl -so files/etc/sysctl.d/10-default.conf $mirror/openwrt/files/etc/sysctl.d/10-default.conf From 7573dfb1f41ce21b0b9db731fa00f18fae13f037 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 30 Apr 2026 21:31:39 +0800 Subject: [PATCH 393/425] linux-6.18: bump to 6.18.26 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 5eb275ad2..f6c69e798 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .24 -LINUX_KERNEL_HASH-6.18.24 = c207c557ce58103b4dda30e26da5203f3d8467c6dadc53d709f6d83ae1d1255f +LINUX_VERSION-6.18 = .26 +LINUX_KERNEL_HASH-6.18.26 = 53772f5d3776e043767c8d81a32240d1f3eb64e822a5d7a510b55ca40707b0ec From 6f46c5c81329a238855df38ee50ce790efd1e183 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 30 Apr 2026 21:32:03 +0800 Subject: [PATCH 394/425] mt76: add MT7927 (Filogic 380) support Signed-off-by: sbwml --- openwrt/build.sh | 3 + openwrt/patch/mt76/Makefile | 15 +++ .../003-pass-LED-define-via-ccflags-y.patch | 26 ++++ ...stale-pointer-comparisons-in-change_.patch | 46 +++++++ ...-add-320MHz-bandwidth-to-bss_rlm_tlv.patch | 50 ++++++++ ...ndle-320MHz-bandwidth-in-RXV-and-TXS.patch | 56 +++++++++ ...pulate-EHT-320MHz-MCS-map-in-sta_rec.patch | 41 +++++++ ...rtise-EHT-320MHz-capabilities-for-6G.patch | 109 ++++++++++++++++ ...76-mt7925-add-MT7927-chip-ID-helpers.patch | 55 +++++++++ ...t76-mt7925-add-MT7927-firmware-paths.patch | 77 ++++++++++++ ...irq_map-for-chip-specific-interrupt-.patch | 116 ++++++++++++++++++ ...sable-ASPM-and-runtime-PM-for-MT7927.patch | 56 +++++++++ .../mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin | Bin 0 -> 299296 bytes .../mt7927/WIFI_RAM_CODE_MT6639_2_1.bin | Bin 0 -> 1596848 bytes openwrt/scripts/01-prepare_base-mainline.sh | 6 +- 15 files changed, 655 insertions(+), 1 deletion(-) create mode 100644 openwrt/patch/mt76/patches/003-pass-LED-define-via-ccflags-y.patch create mode 100644 openwrt/patch/mt76/patches/201-mt76-mt7925-fix-stale-pointer-comparisons-in-change_.patch create mode 100644 openwrt/patch/mt76/patches/202-mt76-mt7925-add-320MHz-bandwidth-to-bss_rlm_tlv.patch create mode 100644 openwrt/patch/mt76/patches/203-mt76-mt7925-handle-320MHz-bandwidth-in-RXV-and-TXS.patch create mode 100644 openwrt/patch/mt76/patches/204-mt76-mt7925-populate-EHT-320MHz-MCS-map-in-sta_rec.patch create mode 100644 openwrt/patch/mt76/patches/205-mt76-mt7925-advertise-EHT-320MHz-capabilities-for-6G.patch create mode 100644 openwrt/patch/mt76/patches/206-mt76-mt7925-add-MT7927-chip-ID-helpers.patch create mode 100644 openwrt/patch/mt76/patches/207-mt76-mt7925-add-MT7927-firmware-paths.patch create mode 100644 openwrt/patch/mt76/patches/208-mt76-mt7925-use-irq_map-for-chip-specific-interrupt-.patch create mode 100644 openwrt/patch/mt76/patches/209-mt76-mt7925-disable-ASPM-and-runtime-PM-for-MT7927.patch create mode 100644 openwrt/patch/mt76/src/firmware/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin create mode 100644 openwrt/patch/mt76/src/firmware/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin diff --git a/openwrt/build.sh b/openwrt/build.sh index fb1451cba..7c480584f 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -402,6 +402,9 @@ echo -e "CONFIG_GCC_USE_VERSION_${gcc_version}=y\n" >> .config # build wwan pkgs for openwrt_core [ "$OPENWRT_CORE" = "y" ] && curl -s $mirror/openwrt/generic/config-wwan >> .config +# build mt7927-firmware pkgs for openwrt_core +[ "$OPENWRT_CORE" = "y" ] && echo 'CONFIG_PACKAGE_kmod-mt7927-firmware=m' >> + # ccache if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then echo "CONFIG_CCACHE=y" >> .config diff --git a/openwrt/patch/mt76/Makefile b/openwrt/patch/mt76/Makefile index 6f4e029eb..20ef9113d 100644 --- a/openwrt/patch/mt76/Makefile +++ b/openwrt/patch/mt76/Makefile @@ -367,6 +367,12 @@ define KernelPackage/mt7925-firmware DEPENDS+=+kmod-mt7925e endef +define KernelPackage/mt7927-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7927 firmware + DEPENDS+=+kmod-mt7925e +endef + define KernelPackage/mt7925-common $(KernelPackage/mt76-default) TITLE:=MediaTek MT7925 wireless driver common code @@ -668,6 +674,14 @@ define KernelPackage/mt7925-firmware/install $(1)/lib/firmware/mediatek/mt7925 endef +define KernelPackage/mt7927-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7927 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin \ + $(PKG_BUILD_DIR)/firmware/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin \ + $(1)/lib/firmware/mediatek/mt7927 +endef + define KernelPackage/mt7990-firmware/install $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 cp \ @@ -772,6 +786,7 @@ $(eval $(call KernelPackage,mt7986-firmware)) $(eval $(call KernelPackage,mt7921-firmware)) $(eval $(call KernelPackage,mt7922-firmware)) $(eval $(call KernelPackage,mt7925-firmware)) +$(eval $(call KernelPackage,mt7927-firmware)) $(eval $(call KernelPackage,mt792x-common)) $(eval $(call KernelPackage,mt792x-usb)) $(eval $(call KernelPackage,mt7921-common)) diff --git a/openwrt/patch/mt76/patches/003-pass-LED-define-via-ccflags-y.patch b/openwrt/patch/mt76/patches/003-pass-LED-define-via-ccflags-y.patch new file mode 100644 index 000000000..243d4efee --- /dev/null +++ b/openwrt/patch/mt76/patches/003-pass-LED-define-via-ccflags-y.patch @@ -0,0 +1,26 @@ +From: Mieczyslaw Nalewaj +Date: Thu, 2 Apr 2026 19:01:10 +0200 +Subject: Subject: [PATCH] mt76: pass LED define via ccflags-y + +Replace the deprecated EXTRA_CFLAGS with ccflags-y so that +the -DCONFIG_MT76_LEDS define is applied correctly by the kernel +build system. EXTRA_CFLAGS is no longer honored by recent +kbuilds[1]; ccflags-y is the supported variable and works +on kernels 6.12 and 6.18. + +1. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v6.18.20&id=f77bf01425b11947eeb3b5b54685212c302741b8 + +Signed-off-by: Mieczyslaw Nalewaj +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Makefile ++++ b/Makefile +@@ -1,5 +1,5 @@ + # SPDX-License-Identifier: BSD-3-Clause-Clear +-EXTRA_CFLAGS += -Werror -DCONFIG_MT76_LEDS ++ccflags-y += -Werror -DCONFIG_MT76_LEDS + obj-m := mt76.o + obj-$(CONFIG_MT76_USB) += mt76-usb.o + obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o diff --git a/openwrt/patch/mt76/patches/201-mt76-mt7925-fix-stale-pointer-comparisons-in-change_.patch b/openwrt/patch/mt76/patches/201-mt76-mt7925-fix-stale-pointer-comparisons-in-change_.patch new file mode 100644 index 000000000..5b99ce3ea --- /dev/null +++ b/openwrt/patch/mt76/patches/201-mt76-mt7925-fix-stale-pointer-comparisons-in-change_.patch @@ -0,0 +1,46 @@ +From d0a6af22fb3ef8acd391bda3ea024738a0aca2f2 Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:25 -0600 +Subject: [PATCH 1/9] mt76: mt7925: fix stale pointer comparisons in + change_vif_links +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the error path of mt7925_change_vif_links(), the free: label iterates +over link_ids to clean up, but compares against `mconf` and `mlink` +which hold stale values from the last loop iteration rather than the +current link_id being freed. + +Use array-indexed access (mconfs[link_id] / mlinks[link_id]) to compare +against the correct per-link pointers. + +Fixes: 69acd6d910b0 ("mt76: mt7925: add mt7925_change_vif_links") +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Tested-by: 张旭涵 +Signed-off-by: Javier Tia +--- + mt7925/main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -2179,9 +2179,9 @@ free: + rcu_assign_pointer(mvif->link_conf[link_id], NULL); + rcu_assign_pointer(mvif->sta.link[link_id], NULL); + +- if (mconf != &mvif->bss_conf) ++ if (mconfs[link_id] != &mvif->bss_conf) + devm_kfree(dev->mt76.dev, mconfs[link_id]); +- if (mlink != &mvif->sta.deflink) ++ if (mlinks[link_id] != &mvif->sta.deflink) + devm_kfree(dev->mt76.dev, mlinks[link_id]); + } + diff --git a/openwrt/patch/mt76/patches/202-mt76-mt7925-add-320MHz-bandwidth-to-bss_rlm_tlv.patch b/openwrt/patch/mt76/patches/202-mt76-mt7925-add-320MHz-bandwidth-to-bss_rlm_tlv.patch new file mode 100644 index 000000000..def349557 --- /dev/null +++ b/openwrt/patch/mt76/patches/202-mt76-mt7925-add-320MHz-bandwidth-to-bss_rlm_tlv.patch @@ -0,0 +1,50 @@ +From 22045d299b64d853fcbaea5c201325f9b1fa6261 Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:26 -0600 +Subject: [PATCH 2/9] mt76: mt7925: add 320MHz bandwidth to bss_rlm_tlv +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +bss_rlm_tlv() in mt7925_mcu_bss_rlm_tlv() has no case for +NL80211_CHAN_WIDTH_320. When associated to a 320MHz BSS, the switch +falls through to default and sends bw=0 (CMD_CBW_20MHZ) to firmware +via BSS_RLM TLV. Firmware then configures the RX radio for 20MHz +and cannot decode the AP's 320MHz frames, resulting in complete data +path failure at 320MHz. + +Add the missing NL80211_CHAN_WIDTH_320 case with CMD_CBW_320MHZ and +center_chan2. + +Tested on ASUS RT-BE92U: 320MHz throughput goes from 0 Mbps to +841 Mbps (iperf3 -t30 -P8), PHY 4803 Mbps EHT-MCS11. + +Reported-by: 张旭涵 +Closes: https://github.com/openwrt/mt76/issues/927 +Tested-by: 张旭涵 +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Signed-off-by: Javier Tia +--- + mt7925/mcu.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/mt7925/mcu.c ++++ b/mt7925/mcu.c +@@ -2334,6 +2334,10 @@ void mt7925_mcu_bss_rlm_tlv(struct sk_bu + case NL80211_CHAN_WIDTH_160: + req->bw = CMD_CBW_160MHZ; + break; ++ case NL80211_CHAN_WIDTH_320: ++ req->bw = CMD_CBW_320MHZ; ++ req->center_chan2 = ieee80211_frequency_to_channel(freq2); ++ break; + case NL80211_CHAN_WIDTH_5: + req->bw = CMD_CBW_5MHZ; + break; diff --git a/openwrt/patch/mt76/patches/203-mt76-mt7925-handle-320MHz-bandwidth-in-RXV-and-TXS.patch b/openwrt/patch/mt76/patches/203-mt76-mt7925-handle-320MHz-bandwidth-in-RXV-and-TXS.patch new file mode 100644 index 000000000..f4b66438f --- /dev/null +++ b/openwrt/patch/mt76/patches/203-mt76-mt7925-handle-320MHz-bandwidth-in-RXV-and-TXS.patch @@ -0,0 +1,56 @@ +From fba3bc87e92a96faab126a0840bde11eab384f54 Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:27 -0600 +Subject: [PATCH 3/9] mt76: mt7925: handle 320MHz bandwidth in RXV and TXS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The RX vector (RXV) and TX status (TXS) parsing in mac.c lack handling +for 320MHz channel width. When the hardware reports 320MHz in the +bandwidth field, mt7925_mac_fill_rx_rate() returns -EINVAL and +mt7925_mac_add_txs_skb() records no bandwidth stats. + +Add IEEE80211_STA_RX_BW_320 cases to both functions. The RXV parser +also handles BW_320+1 since the hardware can report 320MHz in two +adjacent encoding positions. + +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Tested-by: 张旭涵 +Signed-off-by: Javier Tia +--- + mt7925/mac.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/mt7925/mac.c ++++ b/mt7925/mac.c +@@ -339,6 +339,11 @@ mt7925_mac_fill_rx_rate(struct mt792x_de + case IEEE80211_STA_RX_BW_160: + status->bw = RATE_INFO_BW_160; + break; ++ /* RXV can report 320 in two positions */ ++ case IEEE80211_STA_RX_BW_320: ++ case IEEE80211_STA_RX_BW_320 + 1: ++ status->bw = RATE_INFO_BW_320; ++ break; + default: + return -EINVAL; + } +@@ -997,6 +1002,10 @@ mt7925_mac_add_txs_skb(struct mt792x_dev + stats->tx_mode[mode]++; + + switch (FIELD_GET(MT_TXS0_BW, txs)) { ++ case IEEE80211_STA_RX_BW_320: ++ rate.bw = RATE_INFO_BW_320; ++ stats->tx_bw[4]++; ++ break; + case IEEE80211_STA_RX_BW_160: + rate.bw = RATE_INFO_BW_160; + stats->tx_bw[3]++; diff --git a/openwrt/patch/mt76/patches/204-mt76-mt7925-populate-EHT-320MHz-MCS-map-in-sta_rec.patch b/openwrt/patch/mt76/patches/204-mt76-mt7925-populate-EHT-320MHz-MCS-map-in-sta_rec.patch new file mode 100644 index 000000000..915ec6697 --- /dev/null +++ b/openwrt/patch/mt76/patches/204-mt76-mt7925-populate-EHT-320MHz-MCS-map-in-sta_rec.patch @@ -0,0 +1,41 @@ +From 9c8af5c5d5c2dd6ad0d8529be1c65682c6afd6ec Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:28 -0600 +Subject: [PATCH 4/9] mt76: mt7925: populate EHT 320MHz MCS map in sta_rec +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The sta_rec_eht structure has a mcs_map_bw320 field, and the channel +width mapping includes NL80211_CHAN_WIDTH_320, but the 320MHz MCS/NSS +map was never copied from the station's EHT capabilities to the MCU TLV. +This prevents negotiation of 320MHz channel width even when both the +hardware and firmware advertise support for it. + +Add the missing memcpy for the 320MHz MCS map, matching the existing +pattern for BW20, BW80, and BW160. + +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Tested-by: 张旭涵 +Signed-off-by: Javier Tia +--- + mt7925/mcu.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/mt7925/mcu.c ++++ b/mt7925/mcu.c +@@ -1667,6 +1667,7 @@ mt7925_mcu_sta_eht_tlv(struct sk_buff *s + memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20)); + memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80)); + memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160)); ++ memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320)); + } + + static void diff --git a/openwrt/patch/mt76/patches/205-mt76-mt7925-advertise-EHT-320MHz-capabilities-for-6G.patch b/openwrt/patch/mt76/patches/205-mt76-mt7925-advertise-EHT-320MHz-capabilities-for-6G.patch new file mode 100644 index 000000000..43e04dfc9 --- /dev/null +++ b/openwrt/patch/mt76/patches/205-mt76-mt7925-advertise-EHT-320MHz-capabilities-for-6G.patch @@ -0,0 +1,109 @@ +From c1c5fed5ea3c6c42236b125ea4129578c15ea247 Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:29 -0600 +Subject: [PATCH 5/9] mt76: mt7925: advertise EHT 320MHz capabilities for 6GHz + band +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mt7925_init_eht_caps() only populates EHT MCS/NSS maps for BW <= 80 +and BW = 160, but never sets BW = 320. This means iw phy shows no +320MHz MCS map entries even though the hardware supports 320MHz +operation in the 6GHz band. + +Add the missing 320MHz capability bits for 6GHz: + - PHY_CAP0: IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ + - PHY_CAP1: beamformee SS for 320MHz + - PHY_CAP2: sounding dimensions for 320MHz + - PHY_CAP6: MCS15 support for 320MHz width + - MCS/NSS: populate bw._320 maps for 6GHz band + +Introduce is_320mhz_supported() to gate 320MHz on MT7927 only, since +MT7925 does not support 320MHz operation. + +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Tested-by: 张旭涵 +Signed-off-by: Javier Tia +--- + mt76_connac.h | 5 +++++ + mt7925/main.c | 22 +++++++++++++++++++++- + 2 files changed, 26 insertions(+), 1 deletion(-) + +--- a/mt76_connac.h ++++ b/mt76_connac.h +@@ -177,6 +177,11 @@ static inline bool is_mt7925(struct mt76 + return mt76_chip(dev) == 0x7925; + } + ++static inline bool is_320mhz_supported(struct mt76_dev *dev) ++{ ++ return mt76_chip(dev) == 0x7927; ++} ++ + static inline bool is_mt7920(struct mt76_dev *dev) + { + return mt76_chip(dev) == 0x7920; +--- a/mt7925/main.c ++++ b/mt7925/main.c +@@ -183,6 +183,10 @@ mt7925_init_eht_caps(struct mt792x_phy * + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + ++ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76)) ++ eht_cap_elem->phy_cap_info[0] |= ++ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; ++ + eht_cap_elem->phy_cap_info[0] |= + u8_encode_bits(u8_get_bits(sts - 1, BIT(0)), + IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK); +@@ -193,10 +197,20 @@ mt7925_init_eht_caps(struct mt792x_phy * + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK); + ++ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76)) ++ eht_cap_elem->phy_cap_info[1] |= ++ u8_encode_bits(sts - 1, ++ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK); ++ + eht_cap_elem->phy_cap_info[2] = + u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK) | + u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK); + ++ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76)) ++ eht_cap_elem->phy_cap_info[2] |= ++ u8_encode_bits(sts - 1, ++ IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK); ++ + eht_cap_elem->phy_cap_info[3] = + IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | + IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | +@@ -217,7 +231,8 @@ mt7925_init_eht_caps(struct mt792x_phy * + u8_encode_bits(u8_get_bits(0x11, GENMASK(1, 0)), + IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK); + +- val = width == NL80211_CHAN_WIDTH_160 ? 0x7 : ++ val = width == NL80211_CHAN_WIDTH_320 ? 0xf : ++ width == NL80211_CHAN_WIDTH_160 ? 0x7 : + width == NL80211_CHAN_WIDTH_80 ? 0x3 : 0x1; + eht_cap_elem->phy_cap_info[6] = + u8_encode_bits(u8_get_bits(0x11, GENMASK(4, 2)), +@@ -239,6 +254,11 @@ mt7925_init_eht_caps(struct mt792x_phy * + eht_nss->bw._160.rx_tx_mcs9_max_nss = val; + eht_nss->bw._160.rx_tx_mcs11_max_nss = val; + eht_nss->bw._160.rx_tx_mcs13_max_nss = val; ++ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76)) { ++ eht_nss->bw._320.rx_tx_mcs9_max_nss = val; ++ eht_nss->bw._320.rx_tx_mcs11_max_nss = val; ++ eht_nss->bw._320.rx_tx_mcs13_max_nss = val; ++ } + } + + int mt7925_init_mlo_caps(struct mt792x_phy *phy) diff --git a/openwrt/patch/mt76/patches/206-mt76-mt7925-add-MT7927-chip-ID-helpers.patch b/openwrt/patch/mt76/patches/206-mt76-mt7925-add-MT7927-chip-ID-helpers.patch new file mode 100644 index 000000000..6724a2b85 --- /dev/null +++ b/openwrt/patch/mt76/patches/206-mt76-mt7925-add-MT7927-chip-ID-helpers.patch @@ -0,0 +1,55 @@ +From 56209dc45e762dafef428908877d634eeb0c4bcd Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:30 -0600 +Subject: [PATCH 6/9] mt76: mt7925: add MT7927 chip ID helpers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The MediaTek MT7927 (Filogic 380) combo chip uses MT7927 WiFi silicon +that is architecturally compatible with MT7925. Extend is_mt7925() to +match chip ID 0x7927, and add is_mt7927() for code paths that need +MT7927-specific handling. + +Also add 0x7927 to is_mt76_fw_txp() to match MT7925's TXP format. + +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Tested-by: 张旭涵 +Signed-off-by: Javier Tia +--- + mt76_connac.h | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/mt76_connac.h ++++ b/mt76_connac.h +@@ -174,9 +174,14 @@ extern const struct wiphy_wowlan_support + + static inline bool is_mt7925(struct mt76_dev *dev) + { +- return mt76_chip(dev) == 0x7925; ++ return mt76_chip(dev) == 0x7925 || mt76_chip(dev) == 0x7927; + } + ++static inline bool is_mt7927(struct mt76_dev *dev) ++{ ++ return mt76_chip(dev) == 0x7927; ++ } ++ + static inline bool is_320mhz_supported(struct mt76_dev *dev) + { + return mt76_chip(dev) == 0x7927; +@@ -284,6 +289,7 @@ static inline bool is_mt76_fw_txp(struct + case 0x7922: + case 0x7902: + case 0x7925: ++ case 0x7927: + case 0x7663: + case 0x7622: + return false; diff --git a/openwrt/patch/mt76/patches/207-mt76-mt7925-add-MT7927-firmware-paths.patch b/openwrt/patch/mt76/patches/207-mt76-mt7925-add-MT7927-firmware-paths.patch new file mode 100644 index 000000000..c1a27f566 --- /dev/null +++ b/openwrt/patch/mt76/patches/207-mt76-mt7925-add-MT7927-firmware-paths.patch @@ -0,0 +1,77 @@ +From 4dde052ea50e332d7db57efb959a89899fc9bb9a Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:31 -0600 +Subject: [PATCH 7/9] mt76: mt7925: add MT7927 firmware paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add firmware path definitions for MT7927 WiFi firmware (WIFI_RAM_CODE +and PATCH_MCU) and the corresponding MODULE_FIRMWARE declarations. Add +MT7927 cases to mt792x_ram_name() and mt792x_patch_name() so the driver +loads the correct firmware for the 0x7927 chip ID. + +PCI device table entries are deferred to a later patch to allow +infrastructure setup before device enablement. + +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Tested-by: 张旭涵 +Signed-off-by: Javier Tia +--- + mt7925/pci.c | 2 ++ + mt792x.h | 6 ++++++ + 2 files changed, 8 insertions(+) + +--- a/mt7925/pci.c ++++ b/mt7925/pci.c +@@ -633,6 +633,8 @@ module_pci_driver(mt7925_pci_driver); + MODULE_DEVICE_TABLE(pci, mt7925_pci_device_table); + MODULE_FIRMWARE(MT7925_FIRMWARE_WM); + MODULE_FIRMWARE(MT7925_ROM_PATCH); ++MODULE_FIRMWARE(MT7927_FIRMWARE_WM); ++MODULE_FIRMWARE(MT7927_ROM_PATCH); + MODULE_AUTHOR("Deren Wu "); + MODULE_AUTHOR("Lorenzo Bianconi "); + MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver"); +--- a/mt792x.h ++++ b/mt792x.h +@@ -46,12 +46,14 @@ + #define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" + #define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin" + #define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin" ++#define MT7927_FIRMWARE_WM "mediatek/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin" + + #define MT7902_ROM_PATCH "mediatek/WIFI_MT7902_patch_mcu_1_1_hdr.bin" + #define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin" + #define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" + #define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin" + #define MT7925_ROM_PATCH "mediatek/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin" ++#define MT7927_ROM_PATCH "mediatek/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin" + + #define MT792x_SDIO_HDR_TX_BYTES GENMASK(15, 0) + #define MT792x_SDIO_HDR_PKT_TYPE GENMASK(17, 16) +@@ -459,6 +461,8 @@ static inline char *mt792x_ram_name(stru + return MT7922_FIRMWARE_WM; + case 0x7925: + return MT7925_FIRMWARE_WM; ++ case 0x7927: ++ return MT7927_FIRMWARE_WM; + default: + return MT7921_FIRMWARE_WM; + } +@@ -475,6 +479,8 @@ static inline char *mt792x_patch_name(st + return MT7922_ROM_PATCH; + case 0x7925: + return MT7925_ROM_PATCH; ++ case 0x7927: ++ return MT7927_ROM_PATCH; + default: + return MT7921_ROM_PATCH; + } diff --git a/openwrt/patch/mt76/patches/208-mt76-mt7925-use-irq_map-for-chip-specific-interrupt-.patch b/openwrt/patch/mt76/patches/208-mt76-mt7925-use-irq_map-for-chip-specific-interrupt-.patch new file mode 100644 index 000000000..953d2bb28 --- /dev/null +++ b/openwrt/patch/mt76/patches/208-mt76-mt7925-use-irq_map-for-chip-specific-interrupt-.patch @@ -0,0 +1,116 @@ +From f25ff46ec53ee1a1f55bc457c77c184d48570a2f Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:32 -0600 +Subject: [PATCH 8/9] mt76: mt7925: use irq_map for chip-specific interrupt + handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The mac_reset and resume paths use the hardcoded MT_INT_RX_DONE_ALL +constant (bits 0-2) to re-enable RX interrupts. This is correct for +MT7925 (RX rings 0, 1, 2) but wrong for chips using different ring +indices. + +Define a per-chip irq_map with the correct RX interrupt enable bits and +replace hardcoded MT_INT_RX_DONE_ALL with irq_map field reads in the +resume and mac_reset paths. Add the MT7927 irq_map with interrupt bits +matching its RX ring layout (rings 4, 6, 7), selected at probe time +based on PCI device ID. + +This ensures the correct interrupt bits are enabled regardless of the +chip variant. + +Tested-by: Marcin FM +Tested-by: Cristian-Florin Radoi +Tested-by: George Salukvadze +Tested-by: Evgeny Kapusta <3193631@gmail.com> +Tested-by: Samu Toljamo +Tested-by: Ariel Rosenfeld +Tested-by: Chapuis Dario +Tested-by: Thibaut François +Tested-by: 张旭涵 +Signed-off-by: Javier Tia +--- + mt7925/pci.c | 21 +++++++++++++++++++-- + mt7925/pci_mac.c | 5 ++++- + mt792x_regs.h | 3 +++ + 3 files changed, 26 insertions(+), 3 deletions(-) + +--- a/mt7925/pci.c ++++ b/mt7925/pci.c +@@ -266,6 +266,18 @@ static int mt7925_dma_init(struct mt792x + return mt792x_dma_enable(dev); + } + ++static const struct mt792x_irq_map mt7927_irq_map = { ++ .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, ++ .tx = { ++ .all_complete_mask = MT_INT_TX_DONE_ALL, ++ .mcu_complete_mask = MT_INT_TX_DONE_MCU, ++ }, ++ .rx = { ++ .data_complete_mask = MT7927_RX_DONE_INT_ENA4, ++ .wm_complete_mask = MT7927_RX_DONE_INT_ENA6, ++ .wm2_complete_mask = MT7927_RX_DONE_INT_ENA7, ++ }, ++}; + static int mt7925_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { +@@ -310,6 +322,7 @@ static int mt7925_pci_probe(struct pci_d + struct mt76_bus_ops *bus_ops; + struct mt792x_dev *dev; + struct mt76_dev *mdev; ++ bool is_mt7927_hw; + u8 features; + int ret; + u16 cmd; +@@ -358,7 +371,8 @@ static int mt7925_pci_probe(struct pci_d + dev = container_of(mdev, struct mt792x_dev, mt76); + dev->fw_features = features; + dev->hif_ops = &mt7925_pcie_ops; +- dev->irq_map = &irq_map; ++ is_mt7927_hw = (pdev->device == 0x6639 || pdev->device == 0x7927); ++ dev->irq_map = is_mt7927_hw ? &mt7927_irq_map : &irq_map; + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); + +@@ -549,7 +563,10 @@ static int _mt7925_pci_resume(struct dev + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + mt76_connac_irq_enable(&dev->mt76, + dev->irq_map->tx.all_complete_mask | +- MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); ++ dev->irq_map->rx.data_complete_mask | ++ dev->irq_map->rx.wm_complete_mask | ++ dev->irq_map->rx.wm2_complete_mask | ++ MT_INT_MCU_CMD); + mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); + + /* put dma enabled */ +--- a/mt7925/pci_mac.c ++++ b/mt7925/pci_mac.c +@@ -118,7 +118,10 @@ int mt7925e_mac_reset(struct mt792x_dev + + mt76_wr(dev, dev->irq_map->host_irq_enable, + dev->irq_map->tx.all_complete_mask | +- MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); ++ dev->irq_map->rx.data_complete_mask | ++ dev->irq_map->rx.wm_complete_mask | ++ dev->irq_map->rx.wm2_complete_mask | ++ MT_INT_MCU_CMD); + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + + err = mt792xe_mcu_fw_pmctrl(dev); +--- a/mt792x_regs.h ++++ b/mt792x_regs.h +@@ -310,6 +310,9 @@ + #define HOST_RX_DONE_INT_ENA1 BIT(1) + #define HOST_RX_DONE_INT_ENA2 BIT(2) + #define HOST_RX_DONE_INT_ENA3 BIT(3) ++#define MT7927_RX_DONE_INT_ENA4 BIT(12) ++#define MT7927_RX_DONE_INT_ENA6 BIT(14) ++#define MT7927_RX_DONE_INT_ENA7 BIT(15) + #define HOST_TX_DONE_INT_ENA0 BIT(4) + #define HOST_TX_DONE_INT_ENA1 BIT(5) + #define HOST_TX_DONE_INT_ENA2 BIT(6) diff --git a/openwrt/patch/mt76/patches/209-mt76-mt7925-disable-ASPM-and-runtime-PM-for-MT7927.patch b/openwrt/patch/mt76/patches/209-mt76-mt7925-disable-ASPM-and-runtime-PM-for-MT7927.patch new file mode 100644 index 000000000..925d9fe6b --- /dev/null +++ b/openwrt/patch/mt76/patches/209-mt76-mt7925-disable-ASPM-and-runtime-PM-for-MT7927.patch @@ -0,0 +1,56 @@ +From c2e9c5bde7646f97bb8a2298872bf8a34b693d6b Mon Sep 17 00:00:00 2001 +From: Javier Tia +Date: Thu, 26 Mar 2026 15:12:33 -0600 +Subject: [PATCH 9/9] mt76: mt7925: disable ASPM and runtime PM for MT7927 + +Disable PCIe ASPM unconditionally for MT7927. The CONNINFRA power +domain and WFDMA register access are unreliable with PCIe L1 active, +causing throughput to drop from 1+ Gbps to ~200 Mbps. + +Disable runtime PM and deep sleep for MT7927. The combo chip shares +a CONNINFRA power domain between WiFi (PCIe) and BT (USB). +SET_OWN/CLR_OWN transitions on the LPCTL register crash the BT +firmware, requiring a full power cycle to recover. PM enablement will +be addressed in a follow-up once safe power state transitions are +determined. + +Signed-off-by: Javier Tia +--- + mt7925/init.c | 3 ++- + mt7925/pci.c | 6 ++++-- + 2 files changed, 6 insertions(+), 3 deletions(-) + +--- a/mt7925/init.c ++++ b/mt7925/init.c +@@ -232,7 +232,8 @@ int mt7925_register_device(struct mt792x + dev->pm.idle_timeout = MT792x_PM_TIMEOUT; + dev->pm.stats.last_wake_event = jiffies; + dev->pm.stats.last_doze_event = jiffies; +- if (!mt76_is_usb(&dev->mt76)) { ++ /* MT7927: runtime PM crashes BT firmware on the shared CONNINFRA domain */ ++ if (!mt76_is_usb(&dev->mt76) && !is_mt7927(&dev->mt76)) { + dev->pm.enable_user = true; + dev->pm.enable = true; + dev->pm.ds_enable_user = true; +--- a/mt7925/pci.c ++++ b/mt7925/pci.c +@@ -350,7 +350,10 @@ static int mt7925_pci_probe(struct pci_d + if (ret) + goto err_free_pci_vec; + +- if (mt7925_disable_aspm) ++ is_mt7927_hw = (pdev->device == 0x6639 || pdev->device == 0x7927); ++ ++ /* MT7927: ASPM L1 causes unreliable WFDMA register access */ ++ if (mt7925_disable_aspm || is_mt7927_hw) + mt76_pci_disable_aspm(pdev); + + ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7925_ops, +@@ -371,7 +374,6 @@ static int mt7925_pci_probe(struct pci_d + dev = container_of(mdev, struct mt792x_dev, mt76); + dev->fw_features = features; + dev->hif_ops = &mt7925_pcie_ops; +- is_mt7927_hw = (pdev->device == 0x6639 || pdev->device == 0x7927); + dev->irq_map = is_mt7927_hw ? &mt7927_irq_map : &irq_map; + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); diff --git a/openwrt/patch/mt76/src/firmware/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin b/openwrt/patch/mt76/src/firmware/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin new file mode 100644 index 0000000000000000000000000000000000000000..1840d90d80ea39ed22242a6ad64c708eb6535e36 GIT binary patch literal 299296 zcma&MQ;aW6@GUyFJ+sHQZQHhO`!}|2+qP}n++%x>&-cG4Ip@CJyB=z-s$|teC)G)H znwgQAjgg&^otcr5i;2kyMo3msB?>7D>GwYX{RdGNV&wk_?0@us009E}-}V2U{{M)e z|KkBV00Jfj0!sK#{l~!n$M*lI|C|1w`u|J(j~|%y00`7p@Zf(s{m1{;@c-@CcBQK8 zN#|nG+(j%vT@OCphAr_7dt%20h=Dc+1ZPyIPF}^Bp_#nCrZvdNIYC7wi9YrGO{kv^ zFztY_jMF{JQ*$@Gl5>q0VgX7%!9UY8yT& z7{N#AsEa-YAew(7NAt-P$Y%}hvWQfy^w}(HDuI_S77H2@3_bavruEEyCyHgRX;gwq zEn3qUOH!aY`|B|gTROWCAD$6r#*=yU8)2|Nvd#R!>g%}rjFcrQWE7YK-L#a=tg~>& zpYk}u@+mM&HIApLO$GZ3Po4%wwRww*@35w_xukk4At3|4cP~Z8dqX~?*&AV5;FONA z0A)F{7(_TtzHb?}pW%)KTs@J@Akz&O7aEC@*nF~E=e`I$j9hpSUmHpSJK7Dc*}mTy z2DI%1)Wjz@su#mb|CYaC1~jvEPpI^-hVM)a=2Ni8aB0GYeMw)A83#+39qH%%%SZvV zaP17z@6kiR7w>3c*i@!uSECe?ry_p;48a@?&Q%&zycT_2Y3nJjo@O9TEgvpQ`Z6p2 z%UIUbfI+N-y*HMpQ(p_3K~{X8#YN_|R*49!2HDEwHRr~4fR4&xC=!7_G+j9~FM6{x z${qW>c1%e_>yoYWL9(ji?y$184lSmRy_QBOnmh?aoa`IonOJZm%BXy|s!!Dw9fVo&Xj@&*19EJ7 z3~=W=Rs-3Zwy5YN;@SCnb@=YyTLCB)49jI_j4OV_>`Fx!Yb&?8qBtdN;PfXv)(cKC{w>IKROS_GZOj%fzXlpFB*%&OXj zgDm!^B!EHDjNFjGJec0|rgB{J$eRmHEpfLc)|?&giV4kO28+DvPZtXx4(rYmAq3fY z1Z}fYOy{GQ>_;4=Z5EFU3tFYN*7xVu6qF+%;*5ZkeKPdyLD1hA>=cE;EcvyXWy(w4 z^wN2&F7=-rjA1n91P?C3X5e7;+h+sTo&OkMg&}7YqjA|KZ)Sn~m}fix5kX#qM1@Iq zI~KD3ZDHEMqdrRd4fxE8c=9%+qZ;=6= zj3VfwHGrVj^dqQk^@&^heFg6`uZ3G}s4T%J z3-$d%yZbm@UP5=0XX9lNQv4t>lJnrHiJcuC&PNeq%WJUBx@4=ms(9m3aFqr3svpC8 z^&p4tcx5xFd9l``y22Sjle2b!<^bNOjZhcwgvdC$t>TE1W@2~PPEKGNB(lV7qoev; z(SuraVq>=wz{)YS7@=-SU|u?-Sd=9uB+KMN|}>X_971UZL3 z7qpQoMFrBZYR4V2c!OeM*eHhJ4$${gUCGE zDNnX*=heEd|A>aJI}(;>4;s*4h00~lrsQfxR#Hd?oUDLr=c!U$(*W6Sm|QgTC}+!^ ze8t^emz1kj<1l)0V_YTbk;_V~4`+McI@?}=30{lP0nvMG#3^mRCgM;2sjQEkrDRaT zc>ib`5>%XL=L>>!kwzSE#EjV|9FC`9LQvlTY$u^9f0r{pI49A3)CwYRP_G~5p9k^I zRY8?33z8S-sRLff-xUKj^|j4?0_I@#7sTyHC*1sB zk)e?B6yv+*p`9Hkf$=T7$mc&}W+{VhlXqh3##!vuZQIO`3H>Rwe&xK$kP6-Ugcnxi zehMe$pOMVUAa75frf$Xz#ETOetM4n?iViaC6p1D*Or`y6a5d8)ib_I~Ap}UJM~RDJ z1_S8mz2fMH+6PU#f3MDK!v@IOit9kXp4fnkNqq6N6Ag&DvMb*vX%_6%t{1Gp^|6GQ zG>4@kV+Zq>V%AWF0y$NmA)N}hdPFts{NHFjZ=>dJsH22U=mZwm?R&Ja@qw$F4Y$}J zuq;pKw}~kA&WOb^;dsehtP~rH;A~{IyNT_ap+KUxKLv{nlqJ@elOKLPoG*u!DDt8- zzO6~gWzY_ZYL<$nd4#Fy4I16zz1u?h`?L6$i2N`%(S7H@>Z{K8++0!DsJFia+H^7K zahPpgDo@LjT?DKjJoPuW3b^{X5m!nYt(l@3EZOeczH#h-KsW!Qj^|nX^|wfsKj_0F zt&-dSksF&S(HMyeJO?p97BV|f$&8$#*h6B0JFej*4u0WCE zkc4-W6Rie!kPRqmrNUd;O_>u}0%DW^p_YlF)f&G=79Nx;bq2l*VS68ebUFz1M^`xj zgQOte^`~^zCOaW=YQ0-X$Za^>pY+vue}aQ@mnlU8lI0LzWA+$a-j=6lF+t+KWcxBz zQ;f+jgAd2(ZZ7w=On)a;7beG?c0q*wmg=^Xeo!k=Q)0(6%tV@w?&gfxW{EQ%au`Lq zoDS^_BKFz?mio$yv%KCm-T97mEKJl3Qsn)`W0!3{56`8i*Y?{R*HApisG0?*1o|v{Bo3mVDtSlzCS8J-nPCsK7G*U8s*j-h zIoRz}DUs);2SYR8)??XpdWTco<{G2NYaZWQJY6BHg6 z{q4_Y?(6x7^!JtDPRwWgGVLmFCT&f(?l;WDY9~p+jSJ6FOjx^xLE-GTB@pBEA>SJM z?Dlkk4R$NH{0H!a>}V=GdJ=<2w3*Z{+gl-SRThR8SY=^ytL5tlSI;UAn4N=j7XTn; zFMV|hiYvoY`Dof1#$j9=8hO#Kwn`C2`H{h-Nu{M)%YKS=>i$(cgK^Iq`m|T+xFgBW zLg=S$C z9dST>1-oeGFg~4TsPLMZ4V@!m>&mBx7`ZkS#pD89GtC(m2PtihMd*u}MqVb3N?*w1 zR_otF(5_`5TDBsK5F>sBR?39-1XTmf9uPL*8i?vAr5)e=clGmhn<>_F)KatzPwIm5 z1&$2+W{(EGv(i=L-A252j)76Va{Rb>5g8Uf&Ok%4d}$l)w)?7pK$5;7_+XIX{!P=G*EoNHX&nHBcK(|LkVkd6OVS$ift;{acsK&ev*? z??ASXU^r4wJRttPVte}>i|#)Bm{^GF?YTwlxfGJ|NMOXUE3B5$6v$m3?X{vv$o%yA zG^P2cgD^h^vTd#`9P9?IVHTZ~rY_jaO<5J5f(BQ_xey|NN`K#S=90VQ`xD*wup52h zRS&tEY!nejBuop1$6|MqA7(SFuDde|Cywy8c@KLflEvivJ4mU}m2rIs_B!~djLp%z zJXDTp=v@dXI#xB5`|@Fc2{O+7Po55(uM|qO>d&t{9`wNdu%D9vQ`&(e8Psw~3M zioESX&fm_baj?&Nl+`PDb3pr1a7#qQCB9D-SKN(IU}DZ%*Dad78bnJzqtFTXiRQVo zqAkzaEZ-EYg#o!3Hxan{h_;uDsi$(o8<6$S) zHP{>U5Q;<_sR)A!k}=nJ&V~%-==;@4>CG-w_E&GpA7?*MHs(e>FEmMng9-@&7tDZK zM7!cJ9wKauQX9hb!=YX~aYM4#By8D~B4vlfysjDW>EFafOss#QESF@vK!IyKA9g8H>mB z;1!ueSH60{b&^WzQ&*oV^KZgyax8v{YI%3kas8o}aey~FsDqsG1O;7(wG)e)_q=lZ zVP5ZY$M$a4dR_xvoi{C>^EFtHbR#<%%W1zf=f|Y+R<0{V<8!GxeiF=QZ;)3L>u9A; zeP2w@=u6!}75)*Z(R=VKXWOyO{!4O<9_DsP?NVtIT9#50NUHAcmXyL?!Ze(LUqy!w zMyzSn2eNO|pUnDxcsQ-VDgOZ=Nthh#Id^_4hxR2F4aShs?hRIg`~Aict94re2tZn> zYSvO2i93GV`-0LaL7ECwOvvggQmx>&$NJ}2jI>6b9y!y$>!rHcw$glVZi0J zrX{eV0Q2z9r49Wf&RyylQ-6oJ6nr*esKDxmJE}T@L1)eFZjdr~dJCD4MM_0r2{V0x zEIur-%Zt#TRuR#+J##GAu=mfy1HV>-@BT8dRb{qdY zM2%M@FlTtPr!InqpqjANpzSC>pl8Rzo0ynEpx5_%n7CK(Wa^AY(g?oU0I;*bm~wxH z(pF`^yqR?9o1^pH@{G+==Wqese9F>^%EFgMB`6bM-bGd?jO~1r6c>EVovvtM?8sDm zc45-M;|G#DVL8HBnwDcu9wkZi-+vVWJy?6-XfF%L<#q+!dW3k${mIGuGDE~Dzj#z8 zKKYt{7d`sG z!!YMgynhGpV5Zrk>~u@=Fw$7`*_={9S6_xZ^wa+!USA1A0Bi=YK`+1QlQe~qjeB`e zLUCp|Bx6$lmUNRFdBE+)UtsVbMP0KT1D{djwS2Wa@IK#X)_{S1`{Be*ewgitY!~N%iF#>8)NQN3F`sx z326+7><{L2c$RQL+S;9n0jW^CGoZ4E5{8+8Um)M}@#b+7I!_bLFcc8aI{XIZ0HGOY zuL49V;kw5iza3iP0aY7LG2+o``Jw8okQ^H@Rec=eY5`uLI9c*DjvT+QU_V|YGvPH}2*Jm57j;qHCr z(tyw=1ijp+kw;&x+gvzgg0Lq5Eo-D=vYKdX6~83WA!hhTSL5$uO^Uf}8*V)Ekc)Rv za*G>zt?$sng$0>daKT6FG_pP)=2oj`&#E~s6N%5xZ5?INs7gCpdFWLmn3Es{G=I>I zsqPLmE&6KmO$>*`0vH2QzD`oZYO%R>{r|650^^vlc4dx>Tnh z-_&86P@l^2;T84-u5xHJlrEO+GkekqLZCI*UHlsuY(J`h(s`4XZ{1G?+_z(DqfwKj zM-@&37(2{SHXv=PocdhzWDkc+@-|;)th`CSZ;%k9d_=55NH)-L3npku#go_?R6C-8 zuX_69693{=XrVp{Xs2x04zc|4c(|k@pNK19a*el3WxlyH_=TsS@J$rl&GCNji0gD$ z9)-|3jwmV0Z5@1x*s=(@>rR}VTY2&rzs+$>HXNPkjg@6fFk;;&rakwGx~vd7Vp^t>Q7XM%BfEp1pfGr}FB_m~=@G zYWZR|t4aqMm+T6H&EvUSn|e{5=r@zt;7+$y-^s~qx-?IMK-Ki=iEWit_9oP0tAi@> zvEjB(oT#hcnhr=@$SUu^5xdbGstcFqB>3iG!lOfJpe=1=QY;-qo&m)}U%kj3ACI5V z0&_{?P|prjnmNClAb}YV_ytk1iTN|b)1o^}YEL5C=LMx^wqowd?5jm=ON~vStrF0M zkhB&HtPDI??FOO3J9~RhL_dl4N~Er{!}GSM4D?j6`0^Z4N6?+5GUNWGxN>{(lO0K9 z-l7ym1<`JLB2;ez52D*@TN-XaU2nC(v}fnGere?SNOHm74Z3~O3GZRe2v6<)a%2OGzt(h*H{*(4Se7rX6o_d$jmwh|# zj`#^md(-4;FcZ>Rvgvws2TQrufoHkSDGiAY^fq>hY1}cUcDx>4{-;LjlpEl3B}8M? zrLJrIt1!5hVGpgukf*AFY0jdR^XzMIIv1f5LbT6X+BqGKSm^Icfhy?ez;7*WC_QdibPW^4ygkn3_g*Q&`nv&%OEh2 z|2--ac7~l^6LjfFLU@A0ac;4$*%^aMnb)-R zz^!R2r;?$LS&m<)n}$MQT5_X|@eqfgv=zCUyY$KuaY)eEK6HYd#>Vm4zlzaV7#Y2+ zVqgUD(oEUNt?`7k^>N-22D{R~*#l2ws4+5tauU`rc!5HCiGL0;g~=90-WCoLkN7Ys zML>Hq*BDAa7%2fn$z#kI8|NOcBGlV%6UBI2UNEcv6S|{VUM&f2uP>QtWwCLh*%|2* zSaAisMQ5o}lI!T7f~NCL29oLJWU4mznE6>ajBA)g11a9MPIyeYk~^O}={8psU#>m4 zOsz~<1aZE97WKl=D@W^oA$?w6jdB#8$?~wAmY(jdZdzUAu(zsa;;g;du#twW+Ke8v zAfcD95-)P%2-k>MuT)c%ImTIO7<^j?ai}1Wj@evOh9KFYe1CyT0ddy!z0^TtqHHla zSv`sQ*cHGBSd%L_#SjYq>?0+Darl|sF#ZwrXp1JaolYH z&cVWbWg=uxH5)sXco>My;^|9ybQeaH^p~IZUrQj&zq=5O=!xJ(+|&iIm0x7) z_p1sxmVE!nvnF8^Lp<~VShP`Ox>_j!G4dOmw|t*+67f{p^$={}S+3;Uho$sQOohk9IdO zFXFZ`6yxi{VK-o_!lP<$n$N*4Ff63%h(+-dYD%aCuq;0-d=;^T-vwN=f0XP z)lZN@l-u02IgXWQK3gEGaXsezMpjI_SjP^3IRz&GR#Q|Q=?qV<+H7{v{O_eLZ7dGu zf$Pha&!Ki@xTLTbg&(Q^mT1NaU{u_(@M9Bo%cv7CTjNPFE&G~}Odou(jQF~`?nV4@ z^E;rQx1-?1k0KC2Eh7~7;0IslDy&5tg(*HF;Tz4U(?|Pqruu;Ff!^9R9y?SKZ5NFsaUyr~AW$P%TPj2IaxwC<3 zq?ueH`P~v;&BL$zl{jp$UCT~w?Q0H}NIzsjCr@==3CG1J!WDEc45*~PG|XcmmG=tgKW#$*f(#Hp4UJ%z-J zN57r%Rl$^+2H29*7nvKTsrh7wI(9%W@O$laz2EQuSU;Q!ceAYVlPp(tgj>$p60jCz zCI3Uy%T;6dDckz;?ZqMEtA1HgJl~k0^=qG=W*IH|aTs!PN+O~#G@}y>z1)=`#|tQk z6-iKM%=Z>+H4G@CF~Ab<#hr#(WhYj^q;nSGCIH6@Jy7{e@y;u5at=3=QQssb3d)Ec zgFTCl_SsRGWIlf7nkd*ApcNIHw}hl$8FI8D?kqtmtSQXM8{<#6}n zjtH(Okb_=IQjOM#IOpb%_*x0c0w@uy?ww^B$0e|kZ|C5m9+4(~Ag^Vt53L~AG9;Q0 z0Fp5}Bm+suK{X+ZFe6{2H~ukE#6I{8%8ET=pZg{#a5&Wm(?hh z(Bim_wmgU+Zr9xtoEKUQOpoX69>g!m`DV=r;E*FS zPn~>oiJsXIFm7&;31TR!vqynXD=tGXTD#?^D3x&2VI!0unSvGZoO~y_UwRV2!^8Za-=VM@*^RKst z5A8yVf!>A0?V)#Y?2MK-RgRY({of1j8nsoKm z0AX7;Di~1*x1knn_u1T5ja5gMmWE|}jzh|r^|m`MSl`L^N=D!|;RhN2jbeu%xbz@( zvR~CFMZ(_QigabdA;9-Zcw0bm1Tr9g0+Q(A)Z0)02K>!oo^jQWB|V;{i#g0>$^`mp z!!+j-;?rnjv6`N~Pn2bstKrrC$IV-KQL-VO^wE_R#MV8aKkicm%f$^D&k83rE4#W4*_9CGv7x1pwH_LUw%=T$WSj1Ju~gx0xK?EdoNeby7;p|p zOP(wRd106)@+GimU<5)kGT?$EDaHwK0Zye=k~WP1U_$ae5< z=VIl=uC8VPfZlA*gVz>m*RFBe&~SR!sF>%x(OE*F4sh!6;Txz*&oCY?J)@PA@7QXR zD>a&VB?HTDGPa)qMrdRJB9)NxZsBCD_5^bR6B7o-vgP_S=oaohV=%?u+oWQ8=S6=O zAl^@{is54xS=4Xcx+>+0?VL6&YJcyzF-DNPG63AMn@=vB(d1FpT%eUh6GU zhbUJ&4%JbhOdYC1)|^e%6c0l&)N-ecPR9RM;#duy7qu9K<6iz)$({E`cnTa~NcLfZ ziiv=A7vIt{PDiJIm6Qg^bTM&J$_v`1+Zi`=v{)V%v7XU3x!=UBz>QbQ`@!nEauS0c znRSMz&f=6*5*=arJwQ?(g>7Z|tC#+3oX)*(sCDgpP)b0a(0tnHT9muc9KTRV|r3F#wF}!mM5d>?4Iz{_P zAK&)qU`Q>xIC9=vwYpL48(_X{y9tFazs%)MC8Om5qcl{uiw$$PKIc9H14r}S#!#Kk@O0sB5a&mWeN!b)`+mb`Mz@0?%FN;iPp(` zuip>b;j&VW2F>D|lCGbdi)!A~a56_yy^WrI(d1+!_7C!H=yA<3N;YosOb91tyo z?ef3*j1pXK`|V4wARnkXAcS~d6pCXj1BH%ZO~b58OX64Wbt8yW^ycryOeaT%ClIsP z8Lfx?DY(3mne#!|58F0>ZjJ@6jwwqy{6n=Z4R7I+#2F4A)XzFRdXKupeO0Ml4f^yqf>vVOZzF0_LS#nO0pp3F6G990s zTHGTI(4h7WL+ow`d7EaTCXB~oHAIvRHXeH|`MKuCGXo2TR5hwc??_4&_QA}4D$Ike zN4APxqy-u!9?J_@z-zO-jUarc2<5YIeq?0e=@6b}>P!4QX}A$7ZZHpYW_olO2|%?k z=vOP#Cv_h;#Qb#5xABX4{BJhN?~GiR3932`HC0S6aCJ#;%j1jE6a5Q&;JNplab2mE z0vLX<92te87k6!Aj#eb5#^?u3`AscIF`S$(^pQN- za2CbiDY5aD4Ab3}qD*)Z<7H+I?<8|0`_{^+b9ulyU{xo~Eo0g6{WcRm!1FH-*5BL< z9kms0DYjis=h@9GzcyDjd-NM8BqBqwmM%>*XM}jx@bUAE!Nts@lIA+VaL-u1YY6DG zpsKF*wPsvhxrKD({S-i|JV=mwSW-6d%4cE?dd+7XxBT9zVue;7<-2<$0E?W+Ak~(t zFu4&$Oj+4?YLl3ZnqARD+QhlkVJI>Qe~Uqk4hQzIs9Dp-mGgGBr_|>*J9{<)=LA(1 zzUNxy*@?j?5EjDC5wo->)=ycki(JAY+Kq6g4!<3lmFQz-@uf@$HCgHcP21cuC@3jt zBOs7J^7O2^9eLA~OA*;fEul<%5Mi2{H1edd*igSFKsA{};fKjlcI8HaaX=7UH9{fr zui*hg_EY=*@>8VR5L!jF4?b7vR_PM2+!?tx*RnOMD^|&anH>uK@nYvhfn(hu6X9@wtg~-erSJ5y1zBJC4Ie?l@t`ez z?ulqmw1v8ZjQun-HbkY&4zLKvL z-l|4#LAkqk*kGJCU7GSNC7E+`WW9y=y^D(?T{mQW5Wn{i-y*$P*T__tFX<<`{|#F> zMZ5cYF4tGKdeyIn?E?%pl4#XGr4%sj3Ahy~DhtlptzjJvCv^(}>)h9w{0wN|Ii$O# zc~0)UyijGH!O73dWf1RS>weq)fvuV7cpF)ibnqXdWhdHEh@gD-`2gj;e>Nf08Qi8u#Q)HH{j5nLa@iyhTf~to z4WLI5N%2yquGZ%j(!D@F!ZU z@1Tee3@DCYo!!_WJ|f$ROw(IK4{YlQ(;dB(i}0U9Zq<#6oZKl`Zh{KNjej_*KBm%Y z3YIrm6G2y!cFO7#+@^$>46TkQ1KRc3!Ob>GaTC-7tl8PZ`N1`HyV&wWSHLu}(f*+O zl(vK?P1P1&X*Pk}yiF-@kt~Ob<+i3x=h=#ERO8w1i_xi29pTkF^Kb8x=Pdw(HM{-8BBRJS39};gI*)b1~llx#dTE z1q|aQTOJsMvKhhfoJDrNK$9M_9tOODlp33_B96(smB$KBN)P`UR`!D^LA^z`G2XfLc7ePvocKC3egj$L!oQE*UX5TLkDi9Im=%B9Ut^4#E4OqPGxlt1$p;JR@Zfy)=aPR z1aW61)_QNYWo5HWBnkMYaD}_Z{Z7hH-o-wH3J;gNs&&YH5+yFj5&GBLU2kfjr^BB} zqQ(GEwhxFboA}bH@Px1eM<%(5wTpptCE8;?SF{}gPsZ|Gi5-mFVv{Q2xb*l=O6~;X zGP-*KT)e(lgn=jw)m#(iSr8%K@Z_HJ2a#>ebO#VuyX!s(9}%|QeighPVV#>f9qR{ssqxBU@-I}=B#P?(vM>P!q%od6qG2#bL!iS+YDJ?KoX7~M4!Z#C3O0vY2o>zXj z9G#l`p=?7Y@9W}0qjUT`)Kcee0NUGLvytZt&PtIkViN^)T8MlD4XKTqm7(LqblhhJ zfKJ-%F#{#dP`p8!Z!3Ba;c=mkwS)B?xMbd_`~hI)>JD1Um8l-xA7{v$cZH*$ueVo? zs)`!j8#{M5rWrwzEqPKUef|j@-4I38klX(b>c17Ih)w|em>~ly^5&muqGdUjk0of2 zqnJhlU#`^X&O#-OCbOXN_daq0JR_H_$BJq$lY>7w)SI^TT`9gk(Lpsevd-Vo=`v9O zy|E8wm}QYsi4JQB_BLJ3&z0`I*N}o#)e|-*W1csaoUmimy}~rS*{zfG^h=WbV#J63 zO?BlbA?FTOXNF3@-SV+72K4SRN0f_0Tl;}hR!b_L#5SM;1B8n{f}e@CfL+(4;=ZZ! z4Yl#Ynb`Gu%dVv_O#B(A+ItcD5Kx=qHA2aSO?zX)O;bTdTCtDGmB=a%w`r)NcXx&K8Os)`;Q&8!$9LA=+@6N-U)vOQ^oUz zum`KinO@%C_p@d!3X5j0|HGsFgnF%5K2tG-~F%e0mc51*^szzni0 z(a2w%frjLIz0S~{7}63DuV!hrCR;m`KNsB$#4NtvYOhMp0-~f45yEJu^TC+zj6)KO z2J!1-Bc^6frSc6Bm_QalHq5?2gYMZT z^dt~URBEHfe+NEYvmJTo*tVX;s0g>X)i>_5iGd^DLJ5#Ia{f^9Ye5ru78}2~Hq$q6OAVGEw=KU22)3MYwLJ3(4rgvU(L0XYkf)bG!o|1p(pRNc_@;3y!o~DvH}vO>j0$tB^?3oJcj-y=L`Zbr6+>9T$|xUzT5 zc-~dgSO)us&Euy$2pLM!(glr`{|dZy#Y<(N)WO@y%pN`n(IcuX9L(^%Ss3F43^+Gn z?F(@6qRl+Jjlq;AzpZMLWm!S%&#jfsYv4I)w%RiM2!G4)G2$g{cp9rJ=`0aYahMgu zKCU}LwjfU9I6K$15}E0o&!O?Dz1WOf&(K@WJl4Uj#z@Bo<@)KuhXv_R5p+PPSbi5= zP%uFzhD7@W@Qf1gIA4|qXw7M#rEnPp&;?&%-1yI)en_Zv{yTjW|0SRw!Vw{@Sejv4 z^xhwV%7>iC1NsT}-S4B90NAi_${yBvHNo@1blSY^qVl`f3^_m}>nSC&Z9)-|kvObizPjw|X^%sSI)d%QLdjkOrFJneKV6Ex&g7JH=p~ecu z%+V>Ch*I5#Y7D^pUiQHmd>VskMP7hZvIv-r3`~Q6CK&?VfWGVYzge-dz>*|+J~tYAhHm+)RSIKndO%)leKG)O|XX?bG)P;sah?J?|kb_cOum>%jw z6G`*ELaqxQyfq@62z_qOv|9nMgF=9M&Bce|qcns*qB*K4?U2MO4 zSa|`cXUw6(t<(d%If>dc%dglmTjTuGwa8DQDT_@)0$vQs zn3w5&nfe$3KM}1vr)W_|nhBzRQUOJ9|7!}rM8XVsY{A<3w+xFtzBrf#)gvXo?I=_Um3=bQEpn zrs}^fnaNS=7MT0LXttcASo~@7(lA!WTxk@QAVPX~E{t-#eIGN=d6IA^z;r-sE7qFD z<__a9LOnClr>7@YkBLMCD8UJx8UyH;zq- z18}Yet0ckUyVHog^5A=-G0Z({_i$ad-#%z1IS6Z&(bg%;_>UX`hFgMstE=gayq@Z` z#bJ__9Slwmf;;UCw6Gmx0%E;s+*T8yGFaDNvauP!{llf-aIeokziEO+)Psoek+)Oc z%)Mc=P)V1nt!dPENP4T%0NDI+id<|iGg&%cIlMR>(PTHR7UMHw9}VyAiDs;pMIT~1 z!n7v+b8N0V^ZDTDVi-WOEB$)C3SI4uT}fK_cs!gC&p*2+nCaZG@K2qT84Fl#Pmr!tM+(JMTh zT;_VdcKo?003Gc0E{5vyD)x=iHiG{I^1(nC`*hR3FK}8CXuvD$*$`#Gq`Y&^)$)kZ zsf64q%>RT*(_TPbg{Fx6xqHwq3?Q_pIp1>pFzog_#Hcz+CKk_u${J!j%({g?Rd1s< z|66i0s-sU=%JGR@c1vSfr1j6Ptg#fd>)YH(?(u&6GIf;T5xUC@{CW`YN^I|j*BDyz za;oHg1#)!(w8h>>Zo=#1Srn5elHx~ z%Mm>n-yq^E$pw6hHd+cuxN$Ir3hCuMg!n4+lLhoqGHb(1@%&C)H+JN0CKCDw1fV=ii?ggC!+B+DGA}TBYh+aCL9J(jN;mw~_JwgWzCYp=v)PA5}O>XMc*ff>_BWVFZ(S-bTT>?RxP}qtdNeUlc06LxZ)1 zASPwi7;rk!w~?aQKe03gyu9*mfaa3_reJt&_A%%#W8q;TZlY$QZ6!RA(gxIN6t!)* z-+yUXPr6wN;o*kYE1gMpCqlJaVO*07sg5PMh=r6Gbva->Bjrx>1+DW5^eoXSb_%d> zFbMI|;wrITfU*N3I=*?i87v>H)T331`t?(iFdZGbri+j4H(9WGebbPz0`i#QPGD-! zJj^f*O2H5DPTYf#u#Hbv-ngU#Mpke9C^ixHobI3hVpda|geLqq_9dkVfAS`0@~AvQ zKQ+*6N=DgBb82o@k!~Kxrx$U(pNC?yoCL^N|m8v zzAfI^c%Gx^CF>(0w~;01U!LAoqt&Qt@kdqIHZ)Fq`y$8&E2o*I5c=LqMy(Q@B*LQ> zxalj=GM6l%DW*b$DbBLwZ6XgTCX|tEOSAITbMO6md?>tL+zUSvY%CN_If$j$qt3`O z+!yQc;FFto_%UGjTAdEp=a8*?-NjQ&M?I7wyr#~ceA>?eSr%XKdX4bG3*3y_$gN zp-=XzXlI!2H#CxGF7Grzoe)#zswDC=?9a3yKiXn;f8Hf7Jr5L_esq{5TGKH00PxkF zavM?yPg=Cy{P$M{4-dZf4-4)(p2I13im^Zw|NHAMZU>Fw6Rs@7Hl9H1w!qaytd_H+p1cK?a>QiMv>|V#nsO( zsu17(Gga=p@bq7kx`!5ty58=1v3`Xv&AQQw=qvD*QT`~qX_+F% zZx^5F=!iCd8r$YwkDMpmDC@?bkVC7M3YnGX+F2+C$FCOc)>MV8;px2D?ZOcZ z$@Or|T-7c1VNqG<8$1E9HGfoOGV>TGM18t zNx!8yVSZIfc)?C!Pz8Pk{3uPsO6IKMr!f7IVW8I3@b?%C)GowsuUl_`v6k>oE|bCv3DYOv^2 zi~#|6xTbM8k^}O)kz4n0Z{p>N(nql?4{F1V(P+)&@4A@-&G;Wwdta9YCvV0QSndmb`sxCz==RG6 z@-PAVa(+^cc0~F1)gL7jKi7&#IjG_P>Xj>Csf3rAuJJdhOl}lv_Xc}vO*)*7H)M-I zIH&4#OxyAhOGI0BIs!+9i)Q+1i0VTU<-$(D?OBi;L$lNnUxHSX6Rt7Q)`Er%3OT+X zf04=kp@Ge(SMBW(5lbTZG25cX!T3%&Qgg@PU#XuRWOweF5HE6-^ZSX%yNxKH5^Tb$ z;dzpqmZo8f~tpnSBXKcrv_`r4u#{k)kC>XOnsd zJwWYR__)WgGd9^qq9(DE#Ar>zA04zu+29|K#OMvRx(G=qg$sR%Pb4?-+PYHy7XT?h z*1w+c#t5WqybXU!WReC`vt@bBR*DwepLQL#{J>R??dm;8&HOUqG^zZS>zLf_9Sw`x zUoH?1tIj-b*ftQ$cMZJry)t~LXcnjOjd2jYunXzrvATp9ek3E07&!DO3ni#Rp2tko z74KVWxheoSCp6d(zPYxkOG#(E)>O&VU7eS=rO3Endl8U0ic!c*o~|Nyx&bS&B@+<< zka_AQLrrSc&F#x2+cq6=^f%6d5yPu&FB#S~=`|m)(r}NuznfX@STzt`!`q8e35EGr zV$GeL-!`;7gF&27l|fwZY*NjtXan*u%~J>VC3$TBOT)wtom$?1TnTa>6AUqp{3p{oPR|s$_^A1jZ@UP$GXs!C z8nwSBpR(wa?-&)DcG6zU4Oejw7x+P~7>kEhr6*&>nyY1sc+gvfl%sw3qc*?D9?a7$L8`!F_KzYuD!sJR5(7< zYgpRyk3a?DYYSbi|D)-g(~xqXQ$p>+ila7@k7LaED-`IiGu+Xo^4&HPgVBSbUoP#K z>}6MqNOJ8m=GKK(9iu={U2IS{b9g!Ju(d5FVAaiiQZ1NZVQF!qj!{}M_Gvl^BaGV| z-)IJnUAFV>`Sq{ReTfpsCz(xBdt2@B;gPY{MI{U2iKwz@QY(L40hKx8k^eRn1@H5Y zBRu_2UVg5&J*73)?59@_*3j@Q%4IlH9Wu4{X` zjid$DG{6u8Exy9D&p!{F4lo!qrt(qbzYjrTDp17t%|V*M@QWvcUQwM`svF3@;(9)o z_0{E|*NP1HZ-y$cC`Gg(i1H`2RpR!0tI8VBh#T%$RXY-Oy)#c}b7UGlOrW zB1Ej+xf`e(N2}1jem_xC3 z-(Z4_Cq^*Yb68>J0PWj=R^d`b+q6Za;}htez|CWZY=yFxhk5I7)Y_OM_V-k3UJ-#u z480Hf+^jIs%mQHkHd7L`6d+7cW&}$mM{CSw;96?4@*p0oso_DL>|$vfE2tph`*Fyk zP0#+Az{#C*Dz-5K?-L$iDy?d#M#31^SBS#>wI@tRr4ailQRi`L54CMDlL5gnM$#UZ z!EsPDEMtCHMx(3K`Dxb zWQe6oo@IkWo5#AE78MBbK9b^Uw>fZbzTJ3M*+GmORFK$xvo6dw0=#D<$Vzj)KWMcR zJ0M^0?dZlY_VNirpb`Z~#qPl?R(Wy>gsLr~>Ky|eBJqm{=$UEmxk^HCrt>LF!+R-m zS5#n`z$FxJC`4moS{V-uEFx!;0CZFn9+TuHwwn+LUUBy zVK)k*?;&{eYlhftPh(&SI3!Y;$G-rX$J*lM@%VETd%gc(CWx-@5&xQM75jd1YvArS zW)*T#u18&iQhcR5kFRXk`Fvzu2xECFJN|;&Sa+DXDtg{kY6tnIHS%F3?=!h66onuO zKdD`p6_UtPUM=Wy6iA%vxDP!t?@5ROeO?+5b|YG?w0JPLkevXvUgPQrI_17K_sS99 zJlp|X3Fx36UT4e?ax&62+AB>Y88mf@1Xcm!G92KNkeIe;FZ#ct)x))?UY^%{}qM5^1y0kWUDybKEv2s4h% zwZ|SkIABNOmM2%z(6$<+Qj4wX5R$nn4#{TQg1N_gBltom=U)*15WbVmJAi{ni90I; z0zFus6?V(PqDY6LE%VmVXB{a~CEZWsho0GAIt;i?WHFuZ2`7JE;wQNyGq)_WZz%U- z`;~aeZhO!(bh@ZpNRqg&|#Ye#C$P3K0KX0@iEZH^aq{da_tYC+he5L%eEI1{%D^3AqU z335%k8!K)QE-yHzf7qR0oNx;Qm?j8LEGZ_CO@#gzOYati#w|_^PZZ85JG7G8^|W^s zs^-&;d5`ijG3K+GKA)@03H@gGTeVg=fz}P(dSX%8`R-#l7l!7`LcBrHZ$f-}D}B+CExt`13yPIqM|(bdE^1 z|ADfBCvv74A}A{cx7@-Y-C90U?8aO$__-gX)o-~G80Ou4<}JW=uT4TOGpxs1`7k?O zc!b~gHsN@i<;8SSokH${!>d}_r}Y#JWsXMS-Z(Q-gO86Vj~ODTU87t9!Ajr?tD6+2 zkc{MB(;nD#nuJ`|K@UNyi$a917SBflhqK?5`-9Zmcp`!)*m} zE{ka1QU$JGSMgGI{(aEr+yE*Osq|j{^zq5Om*gl-b8i?DjcuC#dkHQ>dP`OFyimKP z1s^zWHf-1Al@8)ZujbKljYGEHV7bjs+BF-}aCVWgaU{2NKvt+yT8rH$IYYfCW0Qck zJB{*C$2sf0Z@ZT^sGXqNRiXZ3eC(R~yd!O;$R^_%)nAl7SlI?`tmng(*L27&NwT{(HH$UyHK+0`f|0Z19J^Z)`v}^LB*ylVnzM zAJ@s00?@h4P_-!iNUZdxwS(Al8Z8e6M+~TL9{e?p-CEAhR*8-m201@!*35SfkOukU zdGp?ODv@VXD0+=&fC9K8{Xt;RS+vE8{94K`yp10_-}U`@qXpYAMwCQrYT#=UU>vdr zDBOkqD`Qt&(2SYL>v4T^Q8gng)ir;S6 zU5GPh*QTi2@n|7pGvq{~;!NHoyrmKPSDFsbcbfBy2?qT4ietoH1iF16F}MGfF$7b? zq`=8drQe^d?I3@_eh^7P=z1&)*16K$5h_o@=^nS_KcHmID}(ARHB=Ic{{>Y1QM=|+ z*#y>H8SO_PkI90YymWWvHd%)?0LD$>lAcK;HNc1X{4KH;&ph35fE=`I<13Ss=(!9= z>=*uT>J7t!I$j{+M_Rp;aiY&L+5FNH6$0J7`4UXdPvgGT}%RAp*)J zbm8h#D}+;b4j4;sZZtL_eYT1{eqV}mvghVQ5k<>!f;VFzTPa|@LeAzL*YP$DjNWh$ zCd8Hwt<-k|19u1OT53o|$`O5pY*c!S<}NXFT@*NUI_;NXGH0l!e)smB^p!f_9?AhT zF(oB~Azg=e0NX~M{Jwhgu6 zWXYp*(rUo!UD^;H@-5>oAfnM2u_ieGfX54b0ajJ;k3MK@9LgCYcn2dbu2oir@Zh0(5j;oGAX;+h7g(t0>%>;Y@1 zo8j(s_!Zn|e2mt(jI$_XHgN&>@_k-rX$0rw>Vop70AJ$eC_u{?CWs$o%ZCHPFExlk zNN`8jR#W(+l5>(>^TXPkz}`JB;+#rC(@a@*N92ltLTyOf^WQR(u?2#}>JA( z+e}nu!C2xXcmbWvh8uj46a*vLtXrWe5FUnFn-R)o6%o}!xG$>bKE&!4UF#XiPLUrxpx)H%=i2>#8`!nWhE@eK zf2;yn$FDEk$wba>V6DpmwxmU^n4=9*Yh{RJ54D=vaD< zRlW`e{W}bwA?6qW6G=$rwr9a?$W?CtH(Am$Q(YqQgy?c2I3n2m| zE-tiS=NAc!kHGkmhST14(K4xLJHtV?_vW8&wjfa3#$izuer`Mi_K$Yv@@pag&)cP= ztv&D5MrHhfUEK}9f`BCBKN(CW7tkTRu9+3C%@O)2e0El_cEvMbu_s7+g^>c21_%fK z7@K`6E)rs-@E#138vcOJNe9T!7*uqCJX?bXlhv&xoNhr958a$?V@f(^2u;wD`-{Ve zHnSFNcS^vmu~4>70nW}Rzc6thqjU&O_o>wNEDv4by+2Hg2!@E)l+>4Iv8rP;a)yVt za(KgD6CeFy_zpszuKHw;VP%a6k1%zB9qBk?O_>Y6A$kWX}orVy%9#6~rF zSOOMbpSJc+_Sg9aQzNRfHBByP+X40&)xoq|SJRLhA#Q$IBubIx=Fvc?8Of}FC2xz^ zK&`X5U43l{iC=CvPReJtr(Qh}@hsrMvGT0mUm*;F>xTw;%~08NxbH*5s{plHd#=u_~x7*B9uW0BtTcSQ0i0;d#0a!s#E7xv# zkzhzF0$+OlXAI)p3J>11vojIJ_WJYRl3%PZX~0j~%%y6Ho6 z*YiS{8PmT+4R7aq{lB?722NdFo(2nR%61Pf;7^$M$vDQ8<^F4;h{)#93g+DtFK>iP z@?>b@Y~nUY%2P!&vZc3H+RCzg_<$*tWGS|eYM3q72wxH}0(f$5YlMd5z$+bKQHx`q~D3c zF6p=iESI`Azxj+$`2F&XmQ|&RTWD;1htTh`gxOVTC0`QP!n#Iwy~-TJA8eiSvIX>j z-^`R|FOD=MbhXx`Sfl_Sc?1rsqzYqVmpuXBF&nu+T45hBmz|(_z(P3B477ovHQq#vI zJ<$YoN}6EvH?HPADGRDfjBLE4KSPt2YRQ-_UKLT#6R>@JLbW_WCmSc%`Bf<)tYNHO}5@9(&^xzGR-p-$8M={{Ny;}b-pYGBtu7Wjjl?GU@u1oSqROP zQ)4@0-KtxEZPgqnTNF1g3~7=4)R}^AuYLVO?z$8j@gmdh$4%r9*sz=Z&~U9{kF*9f zSR!Rb_qS5I;7qu5_|FdsNgiP89Nt@02#O2w89_%ocMIhxuGWpNO`PNnz(<0U!Yt2C zFi_3{bQv|=2)%vXd7x2B5I5t42R^kMKRCDRAweObbz0(rcB9Ccz(DhVPZ;rP0*^-8 z3jW*K1$*beXZW@6k>QvOWcVvwvO(K`u1^w^0H~~dbt%A!49=Yj`8t^^PMORTw|dZ% z8ig});w)e0{NyD-w^ISK*f*MY7>#F42=RM4;pR;mH1-r+qPRLZ%z-H=`X%x36KAiENj@O(07S;GnG(QRG)Oa%OHb zGvwy61Ra`?$2Mm&qQrxuxUPR_KW0Ib%ABjXI|nic_RBDWgnI)j&l~MD7m=)qw_#(5B$P*V z$o30aPeq{Vi2~je$C>32{W7EZG;yL3F)#@-q~Wn8A)Jxih@May zK8-p9SNZJvq)|sC`zk2|4;tAexe!&4;yNE|s|O(b0NKb2*pIVUIT%Im_~bd+hJqh- zYQWCAPcEEq3Xt9VpQoFjIbuLTom9B=>s_5u7k?0gt!`@|&DnkiYZVAb$}s-N&OuF09#%2r`lhuWweKee=X$UpE zf@CQg9&z16t0}FdP+41HRJg-5QsX)Rj!g*YzcQVwCSJPVhSn!Y29=HvL@)+Vqfz&= zxJao}wp|43qwUzQy&I9bQZbx1)nFyqStcl=&Im`A>81B@j3F)lLoa$fbB7V}0=H5S zC2#Ym6bkVCFgeca8})~Ovn9(wWbBA=Dni0O<(sRA=Wjee@t+#$(2iN}<5kJ*JU+%# zf#t^$)DTL$Ynmb6XUg9JXeBQc_}z*|><{2E3r)fYlo*DyeXevJG0YrQ*KQ#90oLvQ zYs<60;qNkfG=SCj=SB~O;-ruR;Qo3yj!J%HD1GzWq4ln~3D_38FR(SZtIe^jGR`IP zuK)sb$eroITR#k7%p!QGo0Mh*;`~b&jkXR#O7qU>Gr^s<;UL0~h6PT$ssgvImhQa! z=)l}^dz!kKrAr@6pAEq=IZuE8ZUjcevudWbj-MlmLU|w`RV%ug|4m_s^_cK`{+Lo6 zYp`IwjoFta=sd$vM^+fz^Xz6McJ;GI9sevsr;1qY^?VUJlw_uHGn&5O;E%hXwSF-)6u=w=~>X$Mu%R{=W=k06?<;`hghDx5RUu)%0W6vWC?vn%#GLG4pEKvC-Q4y zS}h2}Gcvh+I7W7aA(fGI1vDqlV)c#dX@$VG* zt(eg6OxLL%%5?r}T+hq)&0&h(_*(cOA%pYLiw~ z$|PgiA9jb{L1fuKqFJ6_4C;2)T^Wkt+>u(SIfC;f% zxCpya3DfpyAOmAEhV;L9whQ+_i;mkqtGOkL6o*>qZbx>+<7OT=19J_t+SQJb4k>IQ zzND!%f|jRGw&hj9oZl9LVP)4lgnQ!ii_`KvD9TdqOKk_^Lu%bOli5*fN~Z`47Mt4f zRM41F0-}dEtO5bhG$QSYqaRSzV)w*SrRVLzlknF zB{sBYzMH^5IchA^(X<@6Itz)Ks@fEsEHlcJ-XTcVszO6@!rB*hKj|ne+Q)z0v`J>U z2gM-gN|>S+Zr>G)lQYhF&dtn|y9ba^1#i@M2%*#&_5*x5tXtR##_qb_)L!5_B51O= z`g~70*sS`6pP^4)-QbT+IREd$)BV>5!-iI8<$|FA#tQEi9+7a5$QW56P%K&c9WAPw@pbKE(GSa^csHD?Z?>A1L8)46 z1Q^cR1qx{t{x?#c0?M$n1?7;ZEuFkNlotThDEOh0^@T6=E*Y&4<>1t6FWr>;eCsUC zFQ3ErPlT=UVY}Q14gy9A!O(xXxsuO?rP#_98+_9r{K z2()%`wn`E@ZT|MZWyz$QVL2YkU#9(QX0?~|$bqmZ%lk*ZpT>NMzJvh{Eu%^~gJ8*2 zgqsE3IDQbUH^~VkObQeV44c_?Vz-tQqQFtP<}(PH&@yCxC#E3`hdU?YS#9*M(J^o? zBN~MQ464lKFr@9WGH?c6NDSQt?DY8ROTt&bvz4>g_%+VT1u^hrZVm%+Zwh)@I^Z;X zERKVJxdONctD5)zl|E8$NJ=?m!rT9p9x0yHklZ*we2q;S=bFaYMt20K{;&LK-Q0uY(=$n<6-~} z$}2w^`DdZ)THnVQyCn+zOCaASlbY>yiNt0MF)Hp0#odp5Ck854*7D$z2&sPI1(lxW z(xYys$d5P>DV}{;=0ES~T7(Drv()cqd?Z&on#JwDicdyIcDce4 zxld{Yy8ng9iZ7|UXsU$H><{reBQPfE1lm>_FKLB4rZ39@%t*yNgJ>IT`w~l?niUr~ z$; z`H@gxV{HAIYi_-y4gC?o61lC$3Jehh+AgUJa{UTDYp~B@X{=ql3F5y#SYSwZ7q`#i zLcLHlqxdnw4XdykEj_N@Xuk~4dTwEZ(v}V&jH={|0*;@s16#V5BA|$9%!o|e<&hyW zY1T-!3}5)nlcBl}>AavIWnvxQiw&D$Yo9yhaQw}~Hn8R82aXdVeZubKGKYblXhF3r zXiF;nM1<5ZjkO(~`pY{=*zNYCcNuZw-b~(ViTO;fQzm^12xwH$A$v1aoi?2tLg#W% zl^G_|*sC9gks<5M8J#;iMrDE+K)x)IDiS35LjGc-aXVm3hBiox1yMW{N-?KHN1>d3 zV!z$S#WvFtImfk2dJcTNd{)wXr!zgRN4VE{znW3I#PBxOXvz2@+5L z+x>5&i2a?7!^YAZ+X=mJLxA&rdYp(OIv{pN6L={CL5pm@9#F9?jf4IRLH9kMw=MIS zKIYiukJYM5WP~Yp5)OPc-{05+!3QpAv=%~#P?GswnKw|&??W6advWW(fNh{@nB~KI zd@Acn>%?-@YLNt{Zq(OuvVf3zh06>o?@S6*<^Ap0Pp$wlz*6Ei-uyV?&brm*PM6ph zl-_WDBciU;BfFT!HtUoTN+KSwQcL;RlBwviH^Pq$50>l;1Izaj_EnOAI`k}=BY43) zvs`(ILrj@OldwTY5aIRizbMwcmA~S{kG@`y!9`s(tWJ9bJEhb#gi=7D#|XH@A>r)f z<4&3DG?Pp8yYEjNue2y4(4JE@A!rP1kp zyC_;sDYBNK1ChdDTII(Y;;Z=R9X?!Re?2^n?;0j2rEW+co>T?%SDuo=N`%KQ?u#de z3pUVL2ME56PDU%Ja!{-KQqhaiSkHtFOC9D6-_sK3{pEi<%oZ)#6Sh9<%1Ou8$<R)?Dk{6+bWforlo|w0q}^{Fl=kYFUnFn4 zOB}P2ki}IEeRoN8!OztnUqZJN2U_J~=NE7Aa4e#P*BFr|Z_X8Mnq|85qTq_6cp6sN z)%voP>`DJ~VHM7nQ~3ip*nNj3QTD#!{deysESg|;{#)}l@5496T#pmS##RR_!6}!K zJ4_z_-SY`4IrIW!7<*cS|0%VT5N}+hXc5xdGy6LNkY)-1=56JJ$HL*>+iJmRMF^c$ zj9FU5>J#A=1w7%G5k{=ZUdvUf_N;;v4F4osrg2CfHD)~GZhIAbOx$_yM=igjN%@Yc5|_>M`Z1f`doC({z*N%JY{TYdUo;A_pFIIc5<1j~FyWg^@JH9+ zY~zXiXpORMhSu95GpRHUTSm!dHy*KVhxm&o=+(xfI6ttH=p_-CN#roH3+{A~;&#aK z7J+pl&ev9|o1Y40toaoyr#6|rO?;`(LQ)a4wz)0(T7fLPCs@TdsxE#RwTqEpe_+wk z&489UE2bleIT553t()7k9T-;zNZyZfs)amm<<$7BH7q@1&CgLitFuD*ej|FEMf?Qh?}^@NXvU{RIMs3U9ww|@~Hvw zLPEobK1C6ADt77ug zBbY&prAU60`mtwF28k@T-oc3(8{#} z74IP688QGPFc=+;idrNuf%WcR%Z5jgS3B|?j@3_aWPIr~IXOTD`z*Vg<~^v)JHoq^ zUfd5CKb}giXX>768iKXHDo&Z^OGW*ihM6hE>YWKb1i=_#Q0Wd4WR4F*J+pJ1@fCU@G2Qo&){eCiPz#n#h}xNt90(GJOmxR&b+Mg?Ad|0vPSU z6Ct2{^-4ts zKy*JK%QiNw9GdTatikxt-(tCCdr9WEO6y&W;F?;A%uh~ zLFX))gJnUsDAkCEMs#|n#vN3uVzQE6j*Oc-#3%ArK(acR|AU|SRnr>~utcsdYi4W{ zbjz(9z^*IKr%rH=KNmv@hrE>Ff8C+S1;9fm@sx^*rh!Y&+88BnyknkTx5F+-vXJO{ z4V!ZO90==2ptS>D>>5FnK1tYkK8m~x z9}NnEg2?qVbTR9e8-tzf)x13~CwI3!RH3c(wQ$c!<1SUZmePs6REANO?R-K%<3NY4 zZ1+ChTWmnIulno%246);%P?ecx~hBQgp7e$)j4BOZk%_eS)GA2$VNJEY2+S&>6H`z z5{i;LK5(h&+&Xswg0s+UJ@Od0H)w|ELv(9PImj+<{WpnjSG2yB)Q+btQ(4ai3oF(Q zbXov>p|sEGCnfgLMdx&p#nm4uUNs1Fk{7l&t}Z{dVp+buE@9xqRr;X4&Pu;q zgv5N?*Bc3ivAA;I%KF8v(24`_k$pKXla4{jd?CqA1UnTE`?{ouBdpuMqCm)| zEHfF~yM*5k@v!V4>Ym+zCmUaKpW?@-;8|~_wzp-;J~>|dd|&!~u|gscrBE+IKdzEp zw_uy}FwDGtrQJ#rfRJmy(nd{Y%0xy6gsn0N6iV9oiWVTl=(IWzMUft@?D>ltbG`a0 z$IWDsNtYWlvzz~V4)I4*Y5?%dO&)<>h?#ifGw?I}8gk^EQ7-c)Dg;RJ| zOPZN#?VchccQNM#J@R(~-KOHN&Co491r{Kx>$*eYRJ-&-X$g5^rF^;ND4%Z_h(HsN zrrpxe#?Ov@VjiDP0jEWo3NSMJ65n3Fc;ctERIsAA_B&b~i`f9ErHMQrCW%Zpx8x|m zjn9tD0ERZE4_ReAFGqMKYCN4Gd%q}EV*s$*@vQyvU?n>oJM?V`mP@m{)Y~!ehm&^j zIEPNqpR~(lZ?GM)dm62PiM3y+;>TaTl9oNTM?6a+@b`-Eik)5xNZ*~Y4t^%`@Dsc0 zBdFp6ICcNx?sEd6AA`#RaP0TGx02p2KefW09<;DPQ&IplLzG%-?^mdfJ!Y|hdVwyF zuPQY!`Prd`6O|sCozBqMirC*=qr{N*0qeav6uL~Dc?DfyquUs_GfSs}@exh9T;%W2 zm}FB9z5(YYT@2$lD%+maF-#Dmp4us3p7ll#HAsEiDUaB-gduUBM9krZj^#370pKYn zCh9Yg@VjhM@-qYHWbL2vuO<-t&yT|7 zRlxn$lm+qhV~_a41ahmRGnaLu$N|@c+`+1T%8xi_a{D}eg{8kvVU+qSgw4WVn#y$% z2O}s~RnfE)E6Ns6Fdw+h>ItgOx9C`ev3F0p#^AqLUO_1>D0~!*=f@F%A^N(N73&Bt z6SugY2f!K0Mxp*%KPjxA9M`GFWh4cdq>dRok~)Fs^R9Tk?Y(LG_8({t*fh`WA&L^( z#yFV2HpZn#&vUsM3r%-{eQ#8@QQ@+N&HnD+UHFR-P1kK~V&LwTHgXLU!;7Vj5Wof= z$jcuI^pbD;RG+_A)Pe(L1(PANOV?|1Il}Yj+w-2yWkT98yQk%5drH#lmt?^9`%9Ay=$p76lZHv{wR4f1 z2+M0>P+LL&$YG+VwIe>$4%5N2z3@7&_OOXTOx6<>TKNP$s?ODC2$r6TUi7FH? z#6jSZ_S;dq4y(mK$YPxh;Qir{EqVP+pF6|dJg46Q?(q3wluml|mpK5E#W3xI0vu9g#H2sd zMNcSHW2kne#Hlsq=c(4#ks2$kx9uCgju7>ImN8-}^lT_|iPWtJ=(EMLQM)`7Z(HLZ zOk zl$N&5i|Z*6fMI8Of`O+sulwylEfJO#ODW=}mRTKSujjm+nV{ABs!8>phwa?SeJ| zdqxF_LFzBB@$nL-DI`f#UJ}xfmCZKy&*76HIyaw$GQn&0xLDK+5=41OYFv91#HYhVPwwx>*Da2wCXV7<$QnLe<_w#mKI{1qb=0ur~x?!xYzNQRSF{_ zMPf~js|Wnst-^e}D(rqy32XGC+G&>jP?xDVsv!KGc(G26E|4v8uCkaee5LgHyZ+)d zRaabzTz!ai1mnuxLFP6uhW-h?ZdW#0e})X&iEWFexz)76wEF7G2__KaLzxM8%k&OG zHR`~gWv`JtyW2)KXN%h4AIY=Ad7b))hWI)-q52|3Jvs^G5YmLz37?Q-d%(Cdl^nvG z(l+sSit$Nf__!ZcbmRb~n_WiaxvG|h)z~Y<_+Hj(e||6j?uoq-J#WA`D2oB@jFMr_ z#YpwddW8CS9@;M+czFmgc)vFeKY)&_1@erNXv>B-Lf_B&QL@g+t;ktY@d@A=frOYM zP5H6smI2*MP}w!vi(Uq6N>2!B2-znUDM7CV-jr@n35^m-)#q=K-(BB5 zo)lQR(zy^u>={Q^3V*2LZKs; zhA0U2fHwsdy1(~BRRup4^USB-(r1!wi~}3jz%j5`Y5edxvs#@P3kCMDz?gtR#PXXC zIL`dpx9mH)*d-~wh`pv8b^E|1uHY2zMq8QsaT39OB5(U1YAZ;4c}%<+k@N|`DAaWG z=XWL6MNLM3K&s7gP;=^KY8=Zb(6xdoX7r^?0%gB+nQQaE- z1;v5)J{vDmXn_#kF#%>c0*IWJ^wLW)930OMRESjTtbikrjv1*lyHnwMY=BE zPMr-_bbizgOp-Fy?SQEF#Ut_!EpmE{?2NTj9SbkrQ7u__l@Kb&0BOk|gH6Uwq#%>_ zyxTeH+9~5v8CKx`QHNPz_Ivbe^4h}cHgd~I7C8w&$A`L|a;bW(8M1S0696+;amP!) zwwWsUqub4|KgfWv#DjJi8JYO?>WX6N2d&PHTsM7OL7IHSDbtU2<8IaL)DzmvDvRt- zvQq=n%Cphdd3T+4L3`3IZ(He&aneD*Zjsj`yRE?W9XwJkVLq>QKGj2Ytgy)bBI@*Q z!{vo>n*8@J7))8?MjB)tca>`cQ*nXg!wgQTjEoX^pdPwaD^G;-&x?PVs~!Rr@YA)j z_lUxD9^oiYNdQ))J$;m;G-GM>>k!w!;X%53>ey+ zBcP=7DYH_ScT4u@TbgDrar#J#$B(Gp!Ifl*mE3M|Da{tGizmb$fziXfU%BDJxbH9D z@bik!$>^G}8Ipe1FpB#@H!A9<27C5^>5F%fms$~!{RO3DQxdvXECIGwf`3n)5~Z>a z>VZ+S)}i-=cS4ksZ0mFTPP4`gnmH7zWTW{SqofnW#U4A}gK}ZLX;*HCdd1+chP+*- zq3J36zh7Nlf3|vO{!ZLfq6lH$b65r_=oiEOzd-OxJymBf`n)sb(4JqE4CY=WUyQr+Ykx181Ma_tHup52f z=F?Q;oB4)vP@X*XOQxxhs*bV7cL~dNc%=^ z=Ab&9wrybGmT{()-N2oz8~nKa<6F+_+<{iVI`KK^QY+n)p08*0o&EOzdRhvUyH4!s zA!jrZmbX$F5uN}fT|gOLt#RRU7FhSs`_h`ITC@Y@QsQXlv#VYUJ8Z1WVUBUv3}Vq=t8UroGR-FyvW&acD#}U zJRC-0YRybV(gO8r^^}u(j z)L1>eDxtgcLwcSnThcv|pN-`Hsf1j5;mL@`y`;oP?$A|B$!1E{Fk-ur#f8o-&p{~7 z!ol#z&lkaI<#yRT-;2Cm!ss4vVk%BE|fHk4WhsQhBi=w>@^RupaY>JII39Z3{H| zlHF#WZ_GlLh4}!_h;lwed&*Kxn(brUr+2W5c943jB>wm6?&DS2F;rn1h!xu55d7<( z2|mLK8_5(Axb3TCu6jPCVb{kuBpQ{XI^`oCZ`Jx!|vaB57 zKL`pLAg@g>SkBlwJCW_NvzumK&v1}@-RItK_%s)mt9jMs3S?53v~u>TNC3#p?*w~x z43}2>nIC(av&4;vMgiy-gFR8KdO3X#tVHt%oxi~*gSsR21>_L|e{8!?)E6xT$pWip z+{GMij#m*8AYCBTz1!yd{LiG5LvZfpm3vo?{5x}a?G$e?3+f-k@A@+GJS9*Droq2S z=g5;~Mn6T+z)&G56s|ioK~qlc`4`;}*2kPCpue8W-R+GOODGbc^-=ZKv7QpAOZKQp zewSURyj>~0u;gI%&TV!58KPy*Fhk_em)&Td>Yx zJdJG!H3;z@`ce6%)r=)-vPG#h*eUgR0_LUSl`h&Lnd{K)!hIU|>omfD&PrsbJD&SS zQH1Q{`C%XPW~el0+cq`@dd@-U_}eEHjWk0zOfQHOL*B8(b?N*P%WlKvp|{{gv}gce`DG1c)1m z-En zV->km1n|G6(JP)C*P}L*sW_4>ylh}NBGeAm4>P*O``eln0y0G%Z-5&dEfF-c=!hx2;>zn<$!L`1&?5;M`BMZmd?yJJ@7hWRCh`S9e&qR8$L6l zamwipz{#keoUTh_bJ_bSCoD3>7bf|&+aMPt@1wCt)4WANaTFdO#iQL|(7S&ZHXAB`FC zY=4*L!dhXBzBNMl0K&%ih5pp`AbA@`9OdZaN=;1-!jZvIi~68)f)xu-c>ST&1{vbIsBl8u zN9tO*t_SV}`zKmC`kqA$I>1^a`AJ`)$aTQIflK34e5H@zDL6-BW;yeKR$&-M@Z8Pe zn&ZRVq1^K|C0d*kk8mC3W^uIGbqD(Sn^RA0Gm9Gd2JA@;pXna^wC)$z^&vSo+jR|; zD<%15RVvgPe0NN>xRfq{V4T6U4xHZFG8J|6;xx+e?ew3N~|`06W1QS1AcuH=<`bwxkN1u z&3tF3PIdlHp24YCX4ZT%cP<`6-FzC|9R3;B$Wk9x$uhVq`I?2M7;DG9+lDfaB_%TQ zw+G>3$h}^4E`g$NDNxGlnaA@y4ZNQ9LlVc&xc({OT$c?YtYtcgm&YV|R}HZMK|sF0 zragGmuhJ}VE!keGSk2AA0;$m;m*X@p!BVwR-f$@ypE4Yq^oVATE!qSXh;1M7jrPAF za#Qr4MDxZn+S`Vu2`cN3q4ElZwJj1uCH_(y!cg&{0i3x*Y<>fFMpA%HwZ4J8pVf zi|YT_pYZxmA)0?>65A^bLb=TPuRxh=yMqy(*7huxP8u)M{xrYEMxAf84%Q`lhiHpf zLU4=8?KFl@rs>;t7d0fDp+m{6tlqVIMJlLbanp7u*d97C{Kd@Tl;$9@_|>*+ZVyW# zrEItVN96Z=Kgt^1l#=6HS=O*4y^#i%5RZ#%Rw<7I7)&LWVVhn{vE1$I9GxNnuih`} zF>Duw@sbbtAQTSIB6zl-Rkl4gG+=SS-#htFpilrNkUF`f8Sgr6gG4R7?q};k zX(h#4^1f?vw!P&B5e(3l!m-#grU@kEsz`ix!LkjCj2ozD1_@8nQyPmCPu~8V*r%G! zGIT*8PI64wTNxckv%E`;jg&om!tM}sgtp!E5)XJtCS%BoSDy8Ix)Z9Hq|RDWJ)-`< z0FJ+22fK0mi5`eNBFpR;m)n>Arm0W>57e@u3HOD^d~@88A!Y499Ygsv&A?SfJaS8> zgyW)#wC09*-TsfkPM=SLyrmvnJ>*p~z^3ON3~Y>7>Z(mpC;jn{O|y_em^@oJYwz7X zeB02TWu2|YR!*8~v-IH(VWQ@C?KO--)6VzFRNxWO+^8Pm+y=air=nq~m;I=lj2;=2 zwa#eme5@&@J1rMzn2-kKqijA3JR_3o`^sv)52WdW*FS0OkKL8iq)m0y%yqOO|N$^G7H@U_&NAMaUhFkvHqczGzm3%?Qk+Z@;iFuk9X zF|B9MTJMNg;>{U9UDgDJ@GuP+ow+)2A*xtw?&{Y3WTv8hQt(E)T=+Wel+F z#pi?bvTJ{hXH;GNN4q|r>6(dCZAKvQ9Max%Ae->~ASGYb2W~h_EdockywgNqR}{*R zjs7QMLA7QE+>+b*`U0`{Kjq$69ieAaM1J#4Jbj&XvSO zA5^&ZLLFe|fIBnC9Gi9=o5{RbN(C0ptWd+QJeQ^mLh!c>xV10!tg^;d)JKJ~tbwnj zzq98#w>p*jg?(4-zq453d%(qm_Vd`R|C_yq#>-l&9HXkH6BH7S#nM40h}=&l#?4>O zLe`D8S<`2$k1a(3jx=ol*8Gr1hmFAL|8MC<>lNC^m+O=)#UC@jdlR%1{NX32 za5XSHOX&#=#;fbyYhwAkdxx)Xv^J0>!A2_y*Om=0(-1u(wo8_l`FuzS@ox=5Nz7mK z5LBagux`0@HVNao98}uH;Smu@YP?-bN%v*N;E=YlaI_t|58Ul{BhdFCcD~>nvm&lu z?BRRZBJJQT5fzO}8f{pcnJ!xJpvrz~^5Evr5O`PpaB- z{#r5>El&vLjhI0#n26wOTMO(#uD`F9ncer$T9nYgYkM#%$s>B+sCnlc6MYN9r;Wi? zGz2qx3`v>JmmQED6so|igTumVH(G%y+RyT1OlkQ~)nDBg+umF2xFbm&c|#r^taZ|F z*wqd>8w1#hC<*0o5&c~L?KQDd-8I@*(<-6tyIe%clz zfW@a)Z6vfGQ6+?HTZVO9h=dZ?G`xQG4JVbdCMSr9pJc27gGS`RvjO^?9}q%t+Vqn;Yx1Hx!C7 z%tO`jq?dJ$%TaK1K-m9sF&=2&q47ZdV{I6Moy)DO;Gwc&Kw?yGx@YzTVsexaBW6}Z%AiUJ{$rUk29keY{tv}|9Vgt+ zr@I`1dkoc|ba27rTAtlm~B#z2$_2-T6XT)JlYKUM~H>7LX_{lh_zW zTnpC~5M^oZ>zvLdc9YKKX;yFa1?uFZ{S3-dXwg|i1C>#*&q5R~e}VHW@D5*r7^IW= zM!A)E!~OZK_M!4kavP)>=}Ibe&eblI?7gCd39gWXZVSYRMIXF)y;`$GOPk%%cUZ`W zEpV%ngy&ZEoFWt27(9n!Dev;t5^`_Fkd05~7lnwOdOtpp7}9as=BZ4Cfpj{&y|+C$ z*DPcI)HarkYn^eek8FO2x{Z~Vv14!EsL}2d+ir$3+6;Aa{QW*3Ch-m;QqpFN2D%Jp z-v83B2=-eU;b}>2{4ce&hs0W*YzJJjY1Sw@e7yOs6S{W_5yIhTh_KF6xQ>1-#SbWm zYVSM<_T)?YIicpS+kTz{{5Ods8Cr{W@V|F>er36D$pyjK(4?L7qHOMUhQpOP5ajr` z79X$LF#ef$q$M7>M4wa$M3_DQ@7fEOA1r*oMc}udduzR~=2~0D*TY6WVC@n*b4*Wf zBk$L&Pa8eR7Th6o$|A8$LtE8wTKqJX;KOM5j=-30p`-1@Ry&fi^i>&1ea|!s|+Op zlV(hL-u@Lw>?UjtK=CDx-DAnNDOa#(yWG(vO6=HY@NpuA$vbf`o{jK4zS)`=6POYv z-1o{4>aKSy8oX|14TZl*SxS_qmV*H|5KQ@KrbvU39vfj`qvzPHhd)xt6X&QKQa}?W|K=>zx4zbFya5)uvK)af89yj(xKV*kkmaU6IcZQ!#;{ty?zvdsQN>)FejqUgwSo%h3*}l9|EISPsks@H}PQ~;;CPPhg~cp!EMdyNTx#Mm`^q0YC98mS zzYo( zYRIeHT48w}cde%DP1%llqT*3@RTf?pcOsk@6KhszRi=_amL7IgB)pLg3-2B;YwkzhiyS1R9BLT72<9a#g06f zv5IKdhbSM=HTO|63ziY7po3l_-N_*@h(ai6?zVYZ-%cyAU1Cj~>oyT9MVN45zPo^^ z?ub1Z4Tp*M6>5)`_ygXzFpPuNh-`IfWlY}k>XZHz1HM zlDZH-P0sgbGjV_Fo6SJMa&m*dNk>pURh+BGr!TFVQY)RfQE^U4f!>buUt<$%D!K;I>5hj#kdqt~>pGvFj)O&&m_y^ipQ zsY`43OL+5B5e_ipuQxL;9(=79l zhnf#nQNHxR>Wg|-ZXaBw1GHG@!|XnWWg7jueZW7MCz_?7tUGltI%>(_yS z9$vaq!UT{7uNL_**Er@*nJfK)a3>|R)F=)n z*LWnYrszmtQ!ng0Cigk6UOsH*jB9lLk}BIZTJcJX9RT(tQ4buCqrNi2RWJOoiy_0g zzr1$vBmV7rXYxk7xCRCVZ;PG4tPG&Mt^d7erq*W$;xH#ZEM}#kGmm1$s(3o(q9~cs zpO40zA;aTil^IZj@d4INpDn@TNF9iZ>3^!uI7+Tb!v9KhfiVP7JS3Z2-hO$RmjBn{ zfft$3XF7Rig&eLp&4h^A$J9z5`s%u6pb%8F@1cmI1XrKP+3oRei5lf>qyd+E~s0+f_ z&AyG=wHhDDxX-j^+=bY0*(FL}zuY^ncz*ctcRu@PYH0T6o3b zxu!TsP;WiOu$~JHqlB3cDKtQraniS9M@pGb7rzBzrjt0@-?|bPOR`xDt+$C5TF)j+ z@`)h{aC~KLF_4VO528mZ@Sb$$k__)%o_;#?~6N%RJC2xA9>f4~IC>~+dEpeaz zKd}a;@|xHJ2}eU4^j( zLuLTEeDQ1X0Sw7&2fvP3JADwz^JE7WhbHRE`6AFTq*ut|pu~`O6F|}1*II-^Kp)uk z7Kj$>Vd7dD`()Nmjd>+tl;R%#m%X6!jv7IU*$kI#PEkfRPYlIgXk1@s8U1)Me-B-z zvXrhBpDa`!zg>4rbF_On-y9sM$%i*Efot;(mD$F6@kFxxI&nuw=l8ZGApN<*#aCRf zG75L?AOtxE7&Jv?^n`TH=7uQ7PIqA|Dm1%K4^O*IrRJbI$UsDFK`MdF)AV>xOBrqa zmR^V};NOc{+0`d>P{JZ>$SeSJAKN2+T+nS_01jkr`0kU>CYuybmk5b0ijQL-wdS>@ zSm?y03gGsqc5JDZNICeK9IZj%gFg)PpW7ZC(kKQ4tzow|M>PKk_2Jl z3%1bft2L{Nmzc%byj2axt&2xeorx)@FOabk?EB3;zA&i>(3W!a` z8SaP_ZvGv^!nJh=2lvDGI$V(cpavL@|9xEpeeEzs2WmbFSPTwXR;ySR3~^JZU>99@ z{;FlSlZ#qozsKE8G+y2vZbOk_WmJwmfU~cHZy|Kg8V$S^$zI z#Q9(b4;$kMtc|RI0<^4(l$M>8gr{=pYH^CN=CIT=fUM;{tJ1)VX5z}%Np^CJh&JBl z^%`!N8h-i<+;OUXVf;!xO22)vNRK5ia1-CJ+;|83TM=O7699bm&!-A%s7I5C^W#s| z0)sv!N}?9NeeiB_yf4x@dRmZ1y7cJQwV#~8Y_UGm+YB_FMT;jn$~NK-{g6r=$R4^iv6^NSy&1i5tIVfu|i^uc1}Fc z*09wM!)7U;kqb1@qSiwC4Z2NSQ#{i@O(4HmBI06yW!9Z!w(UdCnay%-hO*a}xrAx5 zU?F$Y{2-{G0UxuQ9cZw(k9=Evd=!SOxY7RpR^w5UK5hj0teK;F%Ye4+Va>jNR_HU? z=a4&)yoV96Qi)sVDk$M`58tuDliBCB<#ZIakaK^ueKQ=)KaaeM4!9fUOyy~XK-hDo zxx(Aj?yN$mG){WJqKd2J0Ye~=qp7B!%3sN*!ujevdT;U z_e^Z&3l4CQ=;Sm^(T=J+VZe}0(;h{b!8>d=tW}S*)NNtjvll0dM*@-Rd!`$UfWcpPrKlD zg-jq(fEtgSFG|W4$g1QOpIHfe0nn2A0Q&O|oakqeRyvI}=9oY(dw5vg3jl8sP3ACH0K+pi zQ1VC0S~eBwb0Y9#*rIU&-PC8+cj}Wpy40MH#uGj3r)QpmV|&I2`EB2sX?i_)oYFIium4A)&R`+p4o9a z$pr;<=*0L|iK2;67m5dM`9}0qi3Tx6~Y8apTE69V}8!A)_5Wi0rx2lB49vyL;QXFnjEjt#GShd{Zp z8Jhchx7^5)oDwO3F8U@A=!-G_e#`D_r!A_@VzTDbNh!-obTBoNVdY6b~rsFX+mV1vnJNv5F!nT0Tk?h_F@N|^~fw-)Lf8QKALdTFl zBfD3ZbPQqLL-a6rF=G;kiUP_KD0B1;8On)M|77vQ|2R(9w9oAufhc-WWjb4S+l0dk z4=Iq^D+sHX!r(*)726zVJ%4w2*+1#oCehkgoE2cmsdQ0uDED(ZpE$}K{<6bB213oa zmmlW0?j$rRowM0pGcijRRfobyLRn+%{Zfyp;4rCnc`KIEU6$szY1{-DEYugGc>g$R%@2Zl|q`I)&w6~2>y zo2VN4mO_}BlTmC=uyJPJhG1k|DX*;do{$qM!|gan>y*0AM}~BPqUo(AKX=Y59S|=P z!RvQdU%*kyks(2O6bM(xE^ljF*wBKWns=Swbfc{`uwrEL97NoV8%ayjLL9ZkNt`Ow?YLJ@e+b~u27>41qU<@5{j={8evisI{{ zbon6#bb#1QcTO~DC(9wyHW-5jtvC7ACbq_>zxg!a#t&zUNN*wqV0`(05H3AjZv_Km zz9f?;x)X3YiRCuVg_x87*>w#rpBcwX=m}v7 ztO24CW&%x~27mn3LTMUVh6mjMHhza2KMlW0UGMGVoq$GBMi0sjQ_emM62Zz~k9Vld z-yd|LWbG7WnBY*WNVMVv)}?O5upxt-D@fSFn0a%yz#G`Kv3NF1$|&3&nhna?#vH$= zt8K@0ASU7VGtPyDqJPd_H6O^_CXN49`0{&|WLvJn>^a*<5PS0@0`QkXuk0E)p|kwC zN~CLn6om)T|1-J`3X5W6YU@{G*cld^JyZcPE;-wfc8E{Xp8}*>;coy|A_jN9>+Qo1 z)TkfQV((h*m5{bzKhE%ztE^4c2MM#vJ$YGljf^PY_`Q#{cSL9nxVPGH~o*KzWdAC5X{i_nL+kfHHGrHM1dLTk8 z{z~`fY}u(IRR- zB??TI$@pd{G2TlFqUoC9XZszZhT*bdFcGH*oAl|p(}R%>W2s~Bf-6kxxLhu}n3iVa zIa0Z6WXKRgr^|&jpxmU4RCT0R7Mk!i?e@xSXV}As*IlUbDQbE%*v4}Nu9vPRkMq}B zrM}(-mna$U6*Hp)JPTf&7kLvJw=jB`JC^c@6q+w8^q@WxmX%z;$$Vnw0puACQCxkH zKjg$OReI2tz&vGA(+7WjJz=M#WI)<0%BZ2^2FF)L#^1K`AtQZ~YEEW`id%%DNyi>4 z;c;R(E7EwKLEHajG4b|Il4{a?5Ji|2RVYGj1hODoUXjq~=vVFIG+vHn;^AklvpM|+ zYR@kcC0NvRaspA~soD{C|If1{)jfu|vlCpd5WS89gtx4p(0$;{qsZbsnFzJ`gCT|M zRP}^t9zdyOi{b7PFv^h%AT6z^@s`YC$vpk&2cEPEXR@z5X91gc)JbbHAP1eZ!K z_x`aU*cR$FXCSXKT*>5}Z;NOV6alB%m5hQtYI`D9>kABSWfCtO$zq$x zE^V1EP=QFO#Vne!axTFgZ7_t>`cYu*BEJKCYZXLs1eUde*^3Ydyz3LlwlX zq5|N*wkJi%)V}ULo@FH-?~HV6nrr#0cAxhlC`IXBiz3mOqsSpRh4#+^YyH6Zy`%ti zPl3Xq_)bodsAV?q;Vz(n#(vVCnK{ey8)L`jPw?X^mAING1RmkU2YWmZq}`KTcj7|c zVa1UCtKGOmPF>>(qjBl~N~<47CeSn$hqzAmn-GN?tIVg zY$kxq0WZ3XX&@g;)npcQc*wzl6=!9orvYdwxwr>U0}232(5R5ESmJtyP8svA>&r=o zjPbeL;XG(s-^CbCPMCE7F%UzP^D8MhHd749`3w?;=80w0N0%6L3>Zg~7Ob5qwr^TSYFfXX-KL?;OcqJaq@Sd%3)zgr|KAHk$k#cZc+)lD14SmDxfEv8yT~h zSYS&2y2}SKN00*;WCxkJ>q!+Eg7;M5Eg9;6BEXER@&?YbzllT2D)qc?*De$=mAgUcgI5fcC1iQ@He zu67rTe<}Id4T7c4YDKqh4TBaToo>hB+iXAN!(Q-Ht&-6KCUeGE2O=P7JMffUX6o?9fvaX52VFHLLI*^e7T14t*K-zz#ym!A|$p^Gp9lBrP0lSS$DX6)ZD!GE20Qmtv z)(nvj|c>4F1$ni93Gu9-3F zUFs<4an(6FX1#3%vxU&)FhG9);&Ga()!Krhs8=5}F?XcHbd8@q)Jdozw<9c@M31pE}to$ zXt@vMHZ71;w$7+xjS^}v2{&WV3Uc=PFm7BFFG_4V?8Lwc(aj-m6rxI-6Q``*`4P$r!gy&XUpGi5=&Z;Uv1HqxpkKayVzZ4(yI6kJgw5M2`XS}(T8S8|OVXocLRaHkhmn5j zu(qA>;ERen5W)yCE^$DBr&Q)$T6-iB3jbFuWn6DPk&x=L!Bk^Lv+}20`#um}UW~MQ zeAP+{nymU@vb8zoK-b|(ZKB`CTR)UoBSt_4VV~zWsWL>W49KHc4};}~4@XSz$xSg5 z#zA7TT}kK3E*xvdfk@N!2d}#>jiWLC7OJv)z>~h_E6;yMxU+$$a*5JZ< zlQz%=!)S!QT7wncZ+)sAR7&9V-XXtzb!D|EA&{dGQY-tF997VD_5ELpCuG-jo7tLw zD!N;#$!~k3S3c((4_R7YX~}IKzu69P?vFuST0K~>U3;`rK;xL9XD0Ur`#W__gPE~o zS!PD3F&@X|Ri$P_wG)7ijI{B&-tjQJn3wJd4+GYbj7=^9n$9nK0}ZAjqp-Uqt4*Cm z7Wv`w2{36bgNOH%HLr+I0fU9Ewj0(E(OIHSpmlVssqs!6RkjI02Q^f+B%cTGCtLr1 z<^R+N^Q!H695x#4&5%m3n~G3;0ROWQHoEZzrIdf|Q;QoA(`&PMfJb@zDw}_2|8nP% zJ#*QEbzY|RgSkii$?r`;ugNG=icicb%p%xJL3i=3HRCK5N+*vswfy_5OzrKPz0`No z5IG`2V(sRk(wLVZ$ATO=RFxT%JFy~vhy;m6qY+0G6V>&W!jPU^4!W&MMb$8r7wIFC zDj@YA*0Bo7JLpiaeam}j=Aj|b&o{4Og1U$n++iUNNT9nI_w3{y|jk!JK zO(mY97I>#6JLvG5!kbfNJb2GOBq?O$f&c=>EUG1xOxzsB%f`nc0-&fi3_j#U@RQc<(BJv2`AEw36_UknmW4 zajPgr-UVQ$D!WsZtdm3Nnc`8|@Y@`r_VE?>Y&+7|cL1%;s)zt5w|NFJc@>?^*gyJ4 zd%aq1?LOJgv=sxU9LWO$Mdpd%FL^Fac35}=#(8aYq@>G*)a($CmitOI0J33$eK~+( zMalwNmtN)5>sISJ6+C#+ClqVN4a??v2u2{?Aqz=wz4ePDI%r{bU@Iu^D2Qs)DB?V+ zy7zYG1NYz6&y+imK`spr6H92h{>rbO0BAa_*N2u&dYZYGbOZ1}eDL3~o)V;M=i#FS zm*ASE?NCNiLst#!*Z@7;L|APN_V}xbZ+5E%B$SZDs0X}^K-B*A-SBq9ooQvQxW^Wn zyn(fW#2MtD0ZhXG^&RTkMO)9xYNL7kIcbJw6|am$#_Kk739_258|2iX zdd^)a@W;@Xv)jW6(4LrAA9>CRf^aIensubcH=RtJq>=WVsc&!95Ay+1!Uk#l@VeEM zt3>&PNw;d_%b`vUW)>>imoRNZX(rzAqYbT?)3HTEr3i?;zxQfTiMVFy7|edcAi+U= zxL*BLD`p&TJ{Dh_y26pw{8rJ(*_Xt2%@++EM$GM#{kuRO`Xan$!Tb;q*FFSg*gGjP zPiPtb^*m}Q<;)ZJbjjPvZ=QgHhd_{K)2m4{A;frBZN1Xv=m?{O4qLW{mOQ=oI@3N= z!MlxV^M;zSdJo#sX!SF$0B77vNlwxRi`KQ7SMmzB$Xql!kA(r&a(NA`du!_i$t;Z)QcBo~iQ6^bXT)&4~%Uc6p7TepF5v1x_l0L(|9edY@=75@|eqT zQXnz^ekg{PCd|t(MCp>hxuxkoHzjOEZJ;Kmj%HswU~QkI@TqHJGrdNhIcyp6R~_F< zkJdy2>ziFry)HRjJLCj1A9ybiOf7|)ZY18H`j{l-HX7SSVf*~WM1?|JK^~7oDbt); zyi$kIW#1tpIaN7~|8_ifE}$hSNj}lDBEia}i#FW7zUXlZ_TzH2mXnbrjA2Oc_;#iX zk5!z>Q960CaQl`<0$pNR40~f=FiQmTmR$0*=6=ad`8-kxoR}&CNK>5$v$e%Bx67Y` zwZ-R_@2!e;M`5TdfTrBBV)%|Em{rE=Cy7v)QjnpX0Dtc9SX@0Qy=C%Qm~OxB_1v;6 z99@-J6MAZ6@X~(HvUghz|09Srd2Z^R!Zj{8+#(gFKNJD1=enP>7t8j&%oGq%nDf^1 zw@|ONjRoaBYh5$+V^CPL>^w2WQ=wHA(q6T=42H(Fn~h>;>!e+O(^pF0b3eY*RAB6P zws_0c_nlb^sN67sk1>8?Ek?vy#YM(m$#`6dQm2D`)wRB zkwR@x5!FkSY5|4?0F~GFs7Q}zyY6Z4;VOt4l<(msMmO0uHNr8PW3sht74?@=*=TDyL>%c&O zHxd+ABvPe#)mbBq@z}NDj={#?{)8u-aIHelL7f)Q?D+|FY`zu9aEAiPL_|gHXuu`H z&()~`$^|J!m=he$D@BncbyNW$G8bL}uqyzR9s%qU;89wQv{@-&jKd)OrrCQjKIYn= zhCbsFw$`OO&mC{J2<5tqu~V#h47rt(hj-HEe#3Iqdsy^o^v;_v>*|@8Ku;A`-en8M z&eu>0|cK@rj-Mv-+sOCO-j|=c@2b+;wy;m`{|)xIf56hoZ&V$lCb7Dl7P#-A_DP7y%XjgqLiX>&iPGzM+nbcKCvZ2^ zy($^L!e;4|N|etzs&ncTm@9l*!Zk^CC=4M{4c|C%SgX{bbxD0W1oCTmB6r#w@;mEn zZm|{>qXdD9r0HZ|JJRgV9O_wx(%7^+>ypnR5aq{NpFpfTJUA?|(c2|PPfaBNe3l<( z|KVcQJL~O=MDy$UZnQ>#XNA6OvY(W~gcsuH8wbv%_OmAelfGH+jO{XF>Xbt0_zyFZ zsYFdX8N>0!_m!_+^-dc36&@ybW|JPC%&m!t3B%N=ftT1Jtv;z$YJ zz)s|4y~*esQ)izq-xrjtiIQfFs%$cJEG_BK*lju8lo&_p*_I5@UZA*;K8}xV`r%M| zw#lR%1C>X0Xa4XYa>8DR1MqVncm%@yMMg;%VN}J6+n*Y?+g6u!M{sUwA3&3i9MlOL zo6Xd%6({R05`GJ@mi(si?GF(FZ^1S6-bt9&JmH>5b<17nG$VoX4kxRxuc7ZXSgs8~ z)^c;Vifr6e?dp3OiHJ4?T*93Y+{E@sLV@|yv!zsAq)NQ7@~#NtO_Oh8lVn$1cO+AR z2|U(Us3{Bt-#D{**?u9s5O`VzbM=4}xZ zM+feNZuhX1THwMf&?;Pno?+y5=9AZ*XNou4C`9^Ut3`E}$Sm|P15!pBg~&y!8l%$| zJ9e04;h4HaZD*4pGBbOyk2vn@s>*|E$aMJ43Y_Zh+;<-mf0pp;J#8-&5$jy?bMoAp zYcS7Kh z1z!E6|BE+j&laHcKm3zzjx>y`MU-Fw1a zD%&t>igLQ-F-)`!K+||B_dXHvCXUL>bD)r7>8oSLC1qD9MUcv6>RE2%D50X6lY0#( zP4e*6akQ&WWs||UXzgEdv6AIJc9CtvKz95*Q48R!I9dnS1zxcmdb`CuPv8xglOe9W zfCFGWy7(DjkO`^WkwLL`Xh1weI2%N_uE)dQV7x&gF?rp+Hd!;1x8$ml(Gw?v){upl z$Yg@v zqtSF#{P}5AB`h0bw4ETF?J#o49Vc`;cN1=(%OpiF@mdow`XC=CeLF26gZI>Edre$JFcoV^ldt=PkzFVNh?Kn7-39U|DQA<2Y`T}vy#EhV1402R>C-3`D= zK+p!DSgkta-JAv=h5~BIbx$?^l0SUny4Xh}jIW=yD2u6j>j`+m*0$Eve+(N1-~~7I z!Z<2+sq_e_4}n9Rd2b5qamnn7O%Z;%#*>(L{vEv5rel+hZZc~Na?JE-SBDg=)V(M~ zVd;_%iEc>wNl}-Am;H!-a$FB7>JyOh;0gWJSH8#B3?x_K(~H-}s_5#c1x64JV8*KC z?}5t{Krk4Xo?HKZ)A5I%yXGKS~I!U`gc2cd>vJYpqT$s8SE2 za)s^F$!F-YKFR5RRQeIkD#>8Z-Bt0_o4TRbuISj*EFjFN>-Vn$$_O}E{8{+nVKm}u zUsA3N1pZ$)lwM~*QoezyJy2Pv8g};*Of4T+1CaeZpdC&X1aOb%680Q)W?(#Db?T~q z2?|=!g5%s(IoUJDm30dZ43rM?y~?1uB$rqG4`DzDKWs_9=AukV*QY(`v?Y@P2>j zLfX{++i(E+ey2i36KY&Xd1x(LMUMl2W(ouDV7IlF?^<)2rk4s)Z=> z)5Gu@lQ`Usb_(>{V9+?h2~C8fqZl;_GHy!>)O>#%nI2ZfyQrl5Xae7=U&SFp_M9og z%+GYW{BHe2b@=G^z8=c71g;efKZvFb}?%9`Qk4 zUVfc-oian}-co~bl*vdi-uMdWmG=-oc5SmKun;*M-2M9xyg*4; zQmQ6q#T|a}!8-$c){#sxzuFK}1-DQ_yKyIWi0xWXsKL#*FyDx_TTBH4CXKE_l?k8- zhZ|8&4asSVM>wHphq~S59k>RRx|H@@ASQ4S zzB~tqWpL1Punk z&&x2FC-jer8;;^Tu)+^4gkj;SN>m1WZSz&{uar;fB;h{vKaag+Q2L?X_jLC+h-OZnny@Aw7{>L@RVJ#JY zzOGcwavIrWxlnTT6O_sO+U-8~9_L!TqJlF^_rL0K?=09q^U6 zE{lG4{2MqvQYSKrDBwgEl!H*<>vz8tAPY-823 z<#RY?PFnvdnroZS$7hzkF#Jn>w6M}0BAi$m?c&Q>hoisMYh5655xg2BYSx6HAS z8bhLBJzB{@TNfV-TSkkSo=JfN`nQUr8CaHLyexY>oZU{i!fYY5)Y{jG{Xz%TVPZ=Fw?D;jreS z&pO&Nw+SNV%d?8@YynQR;5(NE?sCnh^wD*cF);IH&`@%Yi1XmoX=e0$%z3~Fi;2E% z`?%(W=am7f2#cDtgn$#1MfWg5+wgK2zHh$YYpTflBfdp+x>&+`75G5Jo<34(`Vz63 z8&TLE5A7!IO{M;oeT4t$#uLVEI?2TZ=Wt~Z`3%FLQeHv(C$+vJT0)vtcaz4Gz%{E7 z?36t_%A~hb)2m6oDtUG1bxHPYnQbVUmSblArq-T(Hl215T;znY>N|<)_EkoUl`evi zdT~UhciD9+Ud}g#3?4BV)P_NDK}m?`&-mSDCd=g3iagCq?owquFe}{An1-klEeJnp zMEOJz-`EJ2aQN;v?deL}NmuK4il+8lG<9!*6vdEl3$TZ<zd+goplj!$X@L48sQF6@)6X%C0Ve@>ah z9Qy%EgF>B;B-ZNA6_2|Sz{4gzqb1>*^+$gRBx{%kR#4Ckj~)RAsf}#ue!Q9}$x4g% z#Z4q8Iaegy>aPTCm~2PiQAV@I9EecpmP1EabLladxT1@cdKSi$q2b?LG-J3H3+s*1dk2 znDjf>xjQiFMlFb1W!&6`U;rpU*S{E<2%C}2kRH+^5DU_7FgCMXFL^@@j+pSKcB?i%ZhffXKeF>mhbl}?ag&R;4iFcc#n1w)il z<$lv2_7V~)PXwHIXvG_!N4*HnKPQt`VS_&msoWtO{I$M(pOTNqcWV)k0EKw%@}f9% zXt4wVk4<-b#8Tz6)Lw`Kchl3F(BlEV4@M{J*plr5w+NiNaf=qv*%!wMDzWJh_;avq zYxV>K1J2gkj4c_?s=Y2)tCC~sxM>Z&u`XtS`=pu!JjV9eSC4mr8Q z;6Qe<#Cxn}b5aeI73yq%B^VC;T%YFjFEf|@kyh0+$;qv1#e|v--chpGu?P!Lc$^34 zk`JFWvZ;;HkO5euw~Xdbe!_hH$BI$ADP`e}o-`&ngbc%Jn=MbBmQ1^<_QpmGFxus? zOAvfkZh->Hh61bIu4)u)pck>5Q29;z8QA1f2!35|qJD8oTo zYtX_tXsxJ>a^(Ui|D~i^E6w`4GFRy*)>^JzM)6pR0Ky+P4r+VKfCq2r&I!-j6TM#j zR)tUYD&)H)_j{3{{s_G1j2C=N>UrpXXO+`R;8{WmJFKUl3z*EoiXeSAZBqAS4_5dM%fQ?bJEkSsEQ2LgY4_DVFf z>v`gD`9#$W?@KhtRCgRSzXe!3eapP9pq0=LX6*5QDyX+Jk0L`0pNBs!5(;szw;Jc& zg~X@d95h)C%S-DR*nCAstbsn}Ed_^zC#}oTS(It^h-VnZFr$pN`mfJRW`WKl`CxPC z9JXM?6tFK`KhczzWr{BH3XbdUEov6;fCYxd#SeHYhN_O$S zWR&2HJ^vW}EQw&=2~Q7T1#a~eqvw)MP}Z^E4DBs2`f)8onh)3?FbM%oqgi>P34@1G zs;M)mindrKr>ae%tDHY)bp_KPGe| zo1iEr_24LU8S!?M7Mt?#RH&a7u>T+5+y2=bkwXbRL~=HXynaR%fSH;Hlsg`+a#Il_sS()gPlArJgJC z%y#IFzT{yaz<@V|(7oO58|@>0&N(a$c#1XZ{A%Qt1$X!k^!@RpBBtPo__#_G_=KX* zPAmqXazjsZ1Dtu27~qvWL2Bx{586b`s$E2HeGj#?CEjh#5Ac1R1XFZ@7E2sTcbnDU zx2-4zT6$g~O>TyHpKmNp4f{JO`esu>=epi%DB2AOjQaC8(r~Et+nZe9QHvm&MWzNE z?tVB?SAhgpnWJS$t894^gn;94LgaA{tyk{<57$3b@ZGd$=o3d8HN#zv69Yw`V9LmS zN@K0Nlwe`6`KnCBQZWl+u2MC%2~&9yt1rWs}Ix%f15^SN+(AR^Z$foV#0Rf zPk62Mj;LTwj&MDmOUQL{9zeCJ*n0{lY_OP9t&|wCkPXOPIFZ`M^i04UPZcj&2PY9% z9DNo`=bxwVVcpryzdH&y!rYlDAx4uCT97Hrqi!V)SJog!4ORf+A=4cq>^u+YPtm?4 z3cwU~LirhlKQA;5#5UXu5~}c>*tRFuwko$r=5y&}OuTY9y=M;^V}D+fY0{}8g3(l> zaphU|OGj+m$CzhhACnGgn(=7cVH%xp=9TxeF2EWMOMk=S2OhJ!rXg>VU0<|@eH)3s zfQzlNH8GRJ37!C$lQda!3aSGrgw8_z**WH5G*TLa>$Lik|9NX~^>bn7o3 z4rcQz9EJW1hLXvIxkD916@|dP3E*>iO7YJEN3Cu5T;VFYP1%J6Meu{>5oX}ID)apn zHM~5bgq46HRV)TSpL1;}1h<<7_Owc5vg58JRZj5*fDvSK^++1-~*_0h(h z9*Gpcg1cr#6wZ~0VERbCU15x1Ysfsv`n`W}KEZr2KFE zy$Q6b=$%bIX@}2nV6&|`Ys$D5SwS-;a|iDPi@j+%l!{kD8;OvoIQ*Nhdu z22u6sYUS<^K?2*_k!c<1+Dg^rw@Ck{2NJ03-a--I6&rsGiPLW#x8eoJI9A{cj5LLA^I8>6JNo3Q$=Tg*cHCg0a zH9Nlg`Ym23R+{;Ho?C};GJnxJyW~SNG7oyi!T+F0q07(-tp8po-?4l2PvcyX29QXj zMx1Im44wH!`g}bFiDw2A_A^CQ+SQ8-dW!|j?bml>C#5%S2B|lL3A(vq4XNzr#jrJ& zhlC)^lZjF+h^?bmWRgE`P)U*NrUcMkSsnM)qO5RXgF#q_--j0EkS%7)uc3EYk_p;)abzymEf0i=>G%#N4@@lt}&o7BbL-? zFE6-mSJG$AgA7(pdc4YATH#MS^dK)^YVb9Gn6I5226z%|ix({kY?jPLq+i)I`+&Cr zB8d^T`cbYq8c}H6bkR9QvmP!oqIXF4`ux-n*sZ9ex>f*zS8#DKxE><#X-KSJf31(X za}%+^;^Q;cRIQn2vWc=C|3JM~C9f1=j5G^0T|R3J^wa1tZ8dLxBzL$U;${dGlDhGI z|GE{00Q`j*N_@LX`)zUw#iqzS>#l0`LRuBt8<>-1`182tcRn6e7 zeBx8~>T7*2Hyy_(*BZ^|Ptszvv+MNDSmQ0V1g{En0`YXG>=&9K?@A*65ao543G~0V zivZi)5i_fbb+PVwj+wPbhmqvUFs2Uwe#7+YpLKPyT_=2l`t)59E!Ir~^gT~pTmxl1 zCQ@x^D1n{cpImXRK8jjk?EbAC68TK#7eXo&6$0-35WmGS0H|jyHvM6&+SEF}a&Ar2 zOHwL)-ihzxRIsB4(E(RXmiapReaQ5#W#)~|1m#A z)+bQfPcO7E{RemyHJ_vP~5E>U49L;^TL9p?5R&$<(p5QC8bRx7W>^Lgo8wvWv^!Pxy5#rTaA7)bLiL zuEp@ygev8ax(@3;5W^oHnC}5VpU-$1QXObpt1UADy`ajNW%%98N;CCZI*J)DB{zYnM|gYf!-nUigQu>URZ5;AT?CM2H?sVlTy!nNWR$v2?ht5mRly%fwHZ zv?y5G$zJ}3Rpbe3!la7 z1}lR=MW3B!EJw?Ma0QABZ%~O_rGLqJ-vPf|x0R%B=*ya+?lg4t?W7A@1PZKNq}aY` zav(6>-v{SOU18;=_)J}VmoM2tDR7W_x`4k9o8Q4#YV}nPBPNtf0e9^YRw$H;jNlXX zR)+b8dIaR)a^s4(O_OCBg$ar>I3=RQ=KFY9%KxHa(A$6C_#2RBGJiK3K9IholAIjhd@KV#Ko{17Ez-B@A0V*FU~Mu!}E7*wJu08%2)d8>j5OF!esqK3Z*jLNfi(VB9KUe6HTEhgP;Lq#k5KZ z0T2hLPmfmKBtT=3(-4#ft8h;Wc~0PC>?w_7glStx zE8GeIUO*j15b0|(B(eWOvizEujSp@qpSBcPuBI(112l7ZVql%UWm_rLJThTy4bH|m zvmi8ov>>-V!M}cghxt~iOQ>R)5mQjbsB?*x7~!F^td0>+O3A3@1(=ClK1{fNU)j2$ z`k?ZWHfp3}*F+YGwU9mZ7Yr3-l>}PYj^I(7B|&h#rW$lL!5=xQ%?qITJE}*~@Rpqo z1$e6SUv62tcn8lDL7$$?m;cc5eJ6cAL4RDh~k*#-JEImi?HfrXqdX zDEr+EbJgneK0S(P&8MRxHZuX)Um>)zV$@Nbo_Dy@CcVNRWaB@vYMPkyu51|Uh{JS8 zC!J%CdUnQ*o`tjd&a^v=GN2LsxzReRC#3ht{>UP@Sm z^{S+w#0cSX^$G_MvCzc2|`6p8jKN`w8e_T41bv9*&MzZ?uc^MaFEO!*4SA zWb-u;(Pak}4z;(Q$_$84m*MVKe@%`8B=2p|Qmnyh-a|?%s_OE^9LEHprhx5@^T!~;gooDNGo&w-C|DNh@Q_lGrL3Axk& zO-z%QjOzlwqedOlNG97^2lm_>88ti_8I(r&)LntD7Q=U*(#>sevMYh)2yr5BC|zzK zZ&BWB#VX0ot7)Z_a%fYMlQ3=fd~9VGg6=M{G#_P3cYgCz^Ny02V9F?%5lScGy+bl* zsIb`lK%8kZCtpBt2d;JsE-l@tC=A9ngnthf+}u?_+Pf~$e%S&1pN$fQuAWXkc{Czy zsdbH(d_SNUR(UuV-OU4SR-xIhEQCCaM&hNVeQ&C)Wnp8LHK+a_+7ZQ$PlBG$_gqA` z-n!LYhABI|p4>DwqKWa9F*12<4XE5UO?(y266FD2XX@7xQ&+|Nb|*g$gti|H(>Dk) zHE3#n*eq=h#vr*7V^N|JEMhT?vkTb$d$=WqzwtYZaUO4xFsfp1}l`u;PCv^h(Z}lcoSg)3Q6|o@I z#z|KNk)I&ESgJN;7luf<1(R9Li&gVrtFsFDTQK3;mFA%|gV^rz!6!;ad9fxf*brY0 z;GHrl(4TuUQIqCPNJe;#ZOC;p?jXcFqSt*USQ3AlEpTHAeI0!aXENlt={3wC>9}|q zAHp%T7w{O1F2+6F+@xz5tP@CGTo<~!7#kgf*v&;6>DU!3%QCCp2iThs^V^mK$yImt z);#&S9O>oClSL==?F0BecSO>-zFWkXwC{PGj2*J%!CktOT)eM_(VByBuFjrcHclxJ zqDPItLVkqTbeCiddgs{bfMe-*V1%fHyc8N40Nxqn3%ZsDdYST(P!1=O$qda~SY)6g zA?ds$AWgd0fQU%?p_V~W?c~3y5M?GF*)7gA@92Bs+d3$+FFPTLj!Fs9(+8J3sfArV z$)ZN~3G}1;n|XsElL>66r0qsm)^vs#$O?9EhE)q9)@`7(Vdba#MOaQp#_73?vn05+khaAd7+PI7s44kj)F(en zj2GTuqak#G)*wINc*?xIu3~Ut(xBxag;1d5V{8+3w0pf@o$R%zc1<%?vEmt-avtog z^^wW^#LA}rMWndL$u!R-K<#VbVXq)N-m4n}jBIBV9{RNA3th0jr6}QNIR~3fs4up+ z>y#K%3LQvx;8$v>*d+zVNvB*%=H3bG$$hb279U!g!gfW9eI5A|3CJ5k$S|UY_J`P= z@lp-+E;Ki@_>>YP{%n+n+fxA1x1;jr}lO z(1vKc0+<0PqTz5oH=5I*Ox@O=k`m^8b31u69%Ci@PU4WdR0UWLlBbnqow!b5ExS=I##+(}rsfif0aJ1V_l z0P##K7_g-@6h-WOy~Iw#+Hb_5p1`gy#IrbR>voosS@y@B*TEy37rGe4T@UpPxMrW~ z*9knV_(^s=g{8LY+9s;S`yp^K(kAa|T`A0M-^T$Q)3LVr(J4BZ1T~S=OgJ^WFfC2W zOeW%}?@kkZm`g%u>Gbw*UU^3}ts7jN)k~Ou^qq0&kq}5VWHaj-_^cUK zCpygeit%XrDgDlA!APj=*=x!w_t@CZdA=W6g|a84+c@A1<}q=;cn^wVo2J4k#6sy& zCY(a5Otc6s6-q!)Noe;R+xHk+GtgPlR>O($b#gf&M_Oykb&yyy{HR%6+w@bk9X3y| zfq5WIu+lcD^2&EF4PMY^H!_^-0(}_U;FnTbqi$-Nl3EOD6@)Uo^F_xXCuadZPV#ZmHY~Q7JS)N@coaP~H zPuV;y1jDWNgw{LIkeYKhD%8Qn-a!>#IcJShn(p;PGfFt*UkVS=M3WCl{Eka|{xbEg zAA$9Z%L^$;)utK865z_ zmP#)oeC+|u5bQ3}n6FAg6R@+x15*pMr{1Ox`M4`Bvf716kI&#c7 z52bFNv8k_HW#y~wcWV}38M)2^NRbrPFpa`<%8l4D;{XYQnMjt_Nf=2vVPZGuMU%^R zf`dD$yU`gD@RaTIU0lM$y@)Po)l9+nrI{^BDqUfIlj=+iJ;TBZw_)@iU;k-EN+QGW z>8K+TJ=!)GyvPqBUcDsi5r*NTA3|%LpWn8TG3`3*TOH=yDGQ_)p16wyLAuskroX)O z-YJ1Rq$V?%DW|<=JqSJi^+oFR+Fv=Rj=b$d|0Cu4lLiAzf}U91Cy*B(e26;is>ZAf zW}ZUN2zK7=uFn%JdKyR2PArymsMQOW5TcifoGM4c#Ci9a&QC#4Fpf29O)qHWgLb3D z7SQ;@FC4n@_2?;0Hy+_QSN}Jt|KBl}K%~Gs;L`+>kM1fZ+x8hJhyFE9@mDp0qn?D- zecQzrv~o8ocaRV0UQ1LzXm%DyoMif1vPr7LrQU{=`^hUTfXpw>qW=OJ?g97!x!MIf&c&`ZiO{#ml-bXQ zEf;MnOu)4B3Ak8KXR5XAV^Vj~!N;$R(cdxQ{So+e<g&D`8|a9ak|ia;*}X>)_=hnoW|T_N{=uo zTJKH`Ki@olJt(!0*6m?po70!my`KqQSMo)@uFTEP;lNbo%Ge@zjU#DPBxWKLiiiqe z*Hov1TO%>=@kTsRy_$dwjiZr;vS&x7XJ!;o!2~~Y{ z@6{c80RfG{BZ3;iaL=sNf->nS8)7g;e~dB$<43Jr;lG_2!@PwaqmXj8JXvD&!5jF&JV zRu|e{>xkT82XGIa6L^@L{^@q6nld8>VAPK5$jx=+Qp~Oog;xkwfjerjumVX}DeZpP z*q?CA?77KRd3l*@;zcc!7tNIvP+dV5f_WnJ;CCRvUsyV?fWxN-U0ZA!{8P`E&gHC6G{0}>P3P9#sxJLNuON74s;E>YTEJFq_KaIG?!%?EX3N$b_%Ctk zuqRG$rfxXZ-}L*c05EUd`3Py_BD~in3V&3XV|bc9^-$69VrwY$`_$H@v^jzIQX^A6 z2#}^#?xLhS#l-D4fShjkcz*C4_Sx+bfpnQ?uQwtV#`BxBj@>2nA{gUD4qQfYp)a^* zkSePt2Bht}L^!`@Wu?~t~S^HxmG2h1pQBYEX2#w`V`3e1jfB@v{ z@~l2#u$80}zW=1Gf9Jngcci>j*$evYNmOy zMO9+5f&pWrpYofT%rv*}qZJ#!$?k@lF0~1Ajg(KzR;Q-vi^2Eyt7F1eTwb*M*1|l{ zjs&6a$v`_*%CwQpCaWfdcORDU+3d@z*Md~kpi%{6^@ig^)9BTQQ*bAGD~lBuS^z4W zgns80X!xJmQy{{+8w6GZL2K&89Nt;_f(~~W=9g)0Cf**QQEs<2w2%Wb5E_2K!>{(4 z`6DuC0Y8c;J z8wvg1y#(+k6<&w)mnZ@n9ijM>$`$#s#~h%UEL>sV)7YRZ>r8YK%Xzw%(C9#o%r{`4 z*5OEjGA=200-8^8BQlmi_SURkF}JluwIW{h>0rv}$>X&_9a#s|6qPO&BzsZ#MU=&m zoFcdGHdekH0<#uI0?74d_{3s&5T9s%kwjr4wG$njt@Aako#Ue4P(fvs%pt zKVi$Q094X*Ad%#1hIQQzY7cE5T#g}&v|l7s-1-ZAF`3dsW9K&t8?oFxxDd&f3&=}E z9-a;t2_pao^O3T==Y?S^RoptFO-VQJGphuPp|Pmt=i{gp-50V2X*vd3(E})#5{!geyTSa;MwaHWV>xRJ4opN(oV?kU}+Jt z^d?fYY^hpb6%{WVw+akeITZbm+jVeXbL!x(bmv+rZ5VombXH5~PfG(x7eLhJRIy6o zX$Hbd=&gC&*#0_0NL#I0%pEZjpcIJCjMn?<_fcLMMzx)|??2a&#tj*yP}s9o1JGTK z%qe=cWsl}i)K1Fp=cD>(fv_!K!C963KT@3ZD~MyE1~5()|BJW5!&m?uSvAec$0WZJ z4zhpcm9zfeH`;Vb36UT1mH67~;aGc}^XQ2lR zsNo(qnsy3e${33J2A4y#!~s|7pPl*dWy#kYoXyy4EI_4_xC1K01T$bfgp%CTBAPOXb;YOi(;8Qkgm&Ktm_I?>ZhwvLTge z51)lP-Tw&BhOrLKA9(0Yn5#A-Sf@m_=z&E`aw+JMR$wA(D>Zy)M|R z8H9Hiw;WQS#3$+VOE zOM~lwX4W!eDtAn@26e6Kj7j!Ly2zF^iSx7JDD8_n>buDJPw}OfVI@h9cq)HMU|I$# z#Wj!`UX6;IIcK_+Y_0I8V64ER$xN>zPZ(^HnvGZ>3UJEeAD;DVeD)-l{&^O4Nl?sj zVufsN8vHEnMU9_>K!S>j!a(pA!zz2SxFYaQj5{Ohtu7*Nu#B9=VIlZ_?oPReuom}T zse5OMh}>#G@xp8l7mn!Gj!#m@Gzf48=@B!OUi;!ojl**BX-b>AdasMPg4>8eJ2 zMJpJ`J$>^KrwR$cSzD%gQF)}f_9pM&itmQ>x$`sMJ~O(`yG;MB*nIGcU*^(kMPdH; zkL%bqApA#r#>GtLz1gOjl_XUb=Wx`bDEW8-BmLlniR0WmoX|Am8|%^ zgKn1CzuJQ)NdtvCvzE|(Eiw^;MLQ>DF7*b*|6-5%c-!t==RQsns)U*hTpO0sr zlL2$&a$l~Ubf!8fJqLdTl?v`pSMMdI=4{qDmHg%1j#?|ohy)2F`qHfS?#@^?8SE)4rH#G8b)l{hk$ej z>t2KON+Xt6*7?CVND~ezudHfnF@jHqZTDOv)PET_C85r}xlxsO0i?jr2aLZ_m1AO_AID2-gPTwj__ z$8>y|5t9r5AbS3g#5^)F_5zU*mB#4f`_FQ6sXxDdfd6;^dxsBD4t;EkQ4u2E^hTyb zHoYs?Dj&z7gjfgzg-9JKTB>1J97t5NLE-Ds4-W&Io&%rRssyDuM^<@HyxlBb6M2*&@Pid4AR&XmlQ#mAnbTvz&kG(J zJc5g&^GN>0lPX=h;tj#)`OZ;*TgLir2-se8cDBP#pMpEd*mX^i{c8IG)3GHnG*O)U z_hTOS+*R#)kc(Bl+QpuwYZ0wD$t+-o3Sfuo2Y5!lb%?`Z1G%I3W;& zq;hoAtmM`1s#PVc_WGhP?n*Fpe(uWw5}zyOjlz3=nAaVEDSBpre(f&XR23ZsCRC^S z%zqcHR-0qi)1*6-k7n*W#y=fw=Cu{4BFITBsUC#C1CN@net6Zy?$nw8I zzYM4&Fcd75q=Z;AUTKVqx|G=&b8+7|WRSlLdx*hyN1qs8DSz2D<|YrP$-vndqRHp9 zte(;|lM$_{?D@+zkp1+?77k^SE)oSq`+#$a zyiMsxCL6s@n|c=tK5HCP#uSSn&P@MFIiruABfTmH`IWudHZlv)l+f7z$LQxG*mgZ~ zlKKewX_*AFM77V}eRMW1cDMi9YP&UHX-4n&k0^3Ku8=*DJC@qN6i?hN_oEve@5>~# z`VWWS?Tw;Lm)dcsYHXq@Kf%wS#x{-#M7q&+2c9&J@tm{u(y&y|@_k?~vYHE?aepZ| zK^Jotja%EkD=U#hP-z#PmIF+{>;%GbjcJQn0xh#B>56e>n7|%hqCUeQPBNL?dE{@|u^IcqGaxogCuYYLm)&zC8Gwvn@MYHn_6 zQTg*}!gH>vA1au$xS>@8V`j3P!@2VDG@x~4jeafAtvAs@jL|Aeup#Gx5ydWB`~k}R zbZmy_Aoms(lbS>jl1w=YBP%e`qJd~HF4W-KZhHgu?to10^)tVOqG;xseRc@l^c^3Bnzg{L^1MDFeB z13Ot_;1l37@nH^5(#j7Q$>FJ5E_-)Uz}hG0&b(U?wqg+mB6kiDMHlh$x>(73!0X<) z#RBkZ=Tz`Zh4tsTVLi%o2E4FM@J3^eti-zYN34%K0C}!w)G~yLK(mZ4X@3ioD|l$g zKL|c!gqZx&m^K1t8*(@_G^N)Ib?tYmz1)dekquSS-zU=3A#t9Q!7qlHcJ0vS=|f?zQe{7ce<*xvi{GTaJ&06)U3QHL2O9OK zA;E9F+cxqUIosH$x~ms-UA@@SNq(Xr!Xz!HJ{4fmnBqa*U7Z*ZlO-QgN2j#6jmeVg z#-5zG3U6w#m48r?3XP0ZJHgKWqO7zwJi)O!Xw`HRD}<=^Sh{2;+ZRZ6M98B@UR6en zBV){Jsi)rCNr+G2!t-AT`mgHUa~Pj{;=+iO(%`7}-Ikg5+rS9@{R=|G=@9?Cx+d1M~-9FznHW|YvlL)_&1I7Xx$X+F- z7!qL*nWzT94fl`!j0X(bMup`1P?aqdyw!}5d1m{bxC{-mj|MQ7vljaw(ZLKqTH{fafbnK)_b8 z_hVudX?mu+!}#@?>K%KTFbjjGsV9RI?y3Yr7J-$_uPq2W^tN$Y<7^R~8Z z8@1{ZuDF!n`m?Q<6$E<8BA_gRVb&^;rV)rsTHIxa=2a>ftM)T`5t+RTYjTbT5^SuN1}1le+CoCqX~wBfu73oUco~%0n=_4tob) zBY=51&G?R5uw8uHavApDYf`j0CwgkwilVIylGK=-q9z00e3?6 zKk^PA@22IA$AI0bc|b!x8ObD0WUDa4@T3-XxKN3t`R#udbv$eL4;>=1zQ!B3`-sL{ z5~3C5uYYa-G1XIGE04Qwbmn=ypyUsi)9~&7DIyM5pP*vk_9V48>a#5XIRd@_D=a%y z)hf3L3EI@gj?A+Zl#+b#SUBp#?1`&v-{4t*$-mM$v=ykSBJlNU-oZ71R>2XJ86N2` zt{xC<5`}os((z`kB#$O_(6woum`RF4zRJ3JklX{t--oysQB|FRWDBLgrM{uL8urtu z)jf4;i~)ykZntoNoYPgDOlle_K{#N2nVF}YxAx7d@%Bg77ZY|bd@b_&8rPo=^eDH} z*S_{WUfyV{e-nJ95{+TQ0J+smek|6gUZX1$pHAyz8*IcDx!qEz`sL?p>|;bRfS-F2s0 z5H*Hmn#*1Mqw0M_i2YgX>fQ^^+5NZAXK|mzx+E_Kn>YwWT|YdJ%X5s3t?)i});4no z61#i;q|8HJ{YBegLd)2$!fq0k@BJyLBSN^YTZ%zqMW^gi(nc$A)eH}H&6_ZsjLZY; z3!f>m-tqj|0EQiNd!N^`1}+*Yp*N~0xL_JURBX^;AOdezrT-JnCHV6U!E7$92Eh#l7ri=@18-Yeqo!SrZXyuM8|`fG+3prqvCZ zvzvC$CBKBW5I~+ak5Q#3qO?@^c_QLo)@Zrh*gkmKp>GT!=8?NlbFhb`XORduh-CT0 z+(p~Xf~|MmT?p7;%bflc0O~aPc+0AYPu;a*i!dwoXgYZ5SEk|=Egl|!!>>)plh;9; z6;FwjguJCDG+-;36H{w4n0?*2rF@qdHcJRUL!ejFJ^U?~WxO|iUcI@h9nmAdP)=Q5WwbpCMegxe}xqbWGeNzTxtU{MV&p78#Eh z3yqnYHv?I~k~yw^a#}V=;b;_T#$!n8ZnTh?fwRRD7BuUot_-> zZyfM{rs;`pB8tvywkcm(vttWflE7A8@xao}&8K=NDb<~S3dc)?=`5#5If~HC471^J zq|}1-K9XbRYg4{j5@h}!4ZsQWHA-iNTIJViNR4E(dX>CLBLO8fVct81VT~Nm-@CVS zll+|4QkcXdE`XJ0TJZe${G)QFpyjuw=M%lJ-H+6g5t)=S6KkOsV!onkq8Ssqc*0%CeCtVi(%*L@p4seugJuk0y{mN!J!|b*QY&jrB7&0uP+u#g@kD z4N=gPJW6^h&EVWJw-kquu=zM03tsOSXZZdz1=btW4~Jj~WN&U)Kh59maZ2;Em!jJ) z(U5C3P<=`{zbN_rqOOTDM#`eE!l zV>w14sa^_|@0;yUuM*u8w^oD0_q@@)9Q3wE;!LD~ftSG5^ zcVZdyT*)HDO`tPB6JTi;kRVv4VTFiu93WamD6~Hw=QmgFSJ2TBKz00)xfk#}QZs5Z ze)(iWGjdkF8bL9}06sOJ9uFjX4rgFjbj}CsYb!7La_fsMuIn964{8X@rte=JOjmp5~^_D z$#!}TFmx?QsqG{j$#(k+*IjAENLRux(r++$DrOL&w**7*=*#!0W6vf|@<#D&%!eKU zKucgR!K!`~$o??yiO^He)o@7PV)ah|3$*fvvf9=WA@u9AaT5Upt4;KWIm08rc}f>6 zxHbebTvbYfX&i`sCcHwFN_OZ{;zy0U#03eP$Rt#FdOXgU-Tu69K_{hINYt9AhwDku zpMBnUtG8%l5oVbTCbcq4>a%}dK+5>9=U(^%?H?|poa6VFM^`K!MA3?OG3o*z+^?gT z^6P~G*!!Mhk)!0J`GIurAG5-}%of~&6=d&XnNUc=7p}=+J1=((dF%t5o{%T!eZkf~ zs|R+?E+MN>K2RAWn>XZ|SuB`f(NQ=Zen$hbf+>oqt|%`Be2pT)K4yA`l^Er=+A*`TpGe#e zqBn?lw^Zx)%sn!a;pnyayASLe)P*Atm)`LVQA4Vnc}}ZB&Mt5Dv9ddHMwIpV;ozD5B+$p;gq5*^H3I=rnT{MKAjX#+Ln6tZ}i|QdUI9clpL4u zWfuN!B;uAjl~(i;B}BsS8{?9hjaYBEpJQ%Fb#nzQZFj1zQlaCD6Ap>D#yP6nfMiGb zzbJ44y?_slj!5V)u;jSh$Ffr=8v`iWE4do zS2Zzm3k`~|ZI`iUFY0^m5NB!^%wSm5b7*_3EL~Y{c?fRwxf*xvo?h#GfPSm%fToOw zQ8Ked$QqE9x>urBcGV%jNhrP%b>~-1sc?Bd2XV17d!}U=^TCxU%L%y4eHFlOTWag` zG$Qe+`_Ph1zL+b3|K{xQ9E_y@Y0!-vqRoJHkBjGyCG)}B5HPcakpZdG{B%d)J+xa5 zDqQH%P`Wh7MFzkjaCb%1H6=l-j|7;TamdI+49%$!Jp$W0y$39p?Xg})(*fq%a`|sX z6zn0OB=7}K^}VHUVMb-*RHpq#!tD#*55a+*>^S&a%oWL$ERH!Eg7MjB9zj~2kE@?% z5TvQXeVkH6sXE=4uPuIsXdB(i@eqtJF00%}L~2kTcPaHILss>U`i&|O$+oxl{vmQO zdopaKg`Qk|m|ggU=0o-$roU{*DKzAETB%E9*$b#ssgI?+cDwvfp9$F1vJ3nIlXP() z&33q-$bRDr4Pa^(q2oZ{cuP7-7y4LQTWxd6SW!*w$uj&na zR>DW(3dzWbK2g3-$asu3b?n>lrg!b^kN<~6f&O-&Pm}u%o7p+ zp`6`7&hCg0+rzDD0q?797d*5Q^F^38S|_t8dx~PBcC{{PJZ)kj>aj^=L`?<1}r+AJwzl?OPuy8o2gEGbZZ{V>75MLvnqXa9IF{! zxMv?x*ETiL2z05KEL0<8G#lO&J!>GmEaVzm=)Q+uRE;;#4A84#;XJ{N z|1x5M@c00vQ5ETMz!&KD0JJ+VS8+%;;xmx>^C*|DY?Q83%0n&)5dCd>6^IK8#jcuB zeAci!Mj4T*U;e$5rX`^qWS$e{%EC5GWSfo1(+86oSN03{JjGk4k(*A+_#_M;ROq#X zM<+17GauFg4PO$??Pmt_SoqCb{~tHrnSgSC%BP#(H#V+6sBA-@h@r=9MPN@GdYK$R z$^jBV(jv04yIj5HMhnuv{-qjxvlT*Dzole*do{;D6QB++guD^nx(Utv83c{)tM)Il zRQ#3y6O(TQimbVke}S6kZ73ho*7l}8@%L*#e6=@n_?V_7Z;gbEbr9EX{1X!SqUHAk zSFo;@Sf#&S7Oq!;`0~r5u5GEpKMk+F0;ywxbF&>5lUQ!x0h&vGdo{Vd-b=d@z5mPdVx&v>6*t2c?u+@3H6XRA0z> z9Z?qlSsKUUDE!L;{GOhAxi(QKwxa%HTkmQ?k65j7hFe-fIHciL_s8&znDnQKFTpZW zvd^Ic64fem##J1Qh~q{+aGv7XDP{Q-wq=_%m@5trkO>7fo=`jnDCJ3t-r(4xixV72 z$m~M$&^5V&>G%QpGj*L6X)^h8y-B~~X|YX}g1IOq$_60)blUUVc>x49c@i!ZG<`$j zV2kx-WIV6`>~r*I7VrD9G8*~2*D)VI?W2zv?|N1ZAKIqaBIq2X0Jk zc8zQR4v?u17SpONa#4zhG+KrK)oRYLA3YMhWU!4wV(7rdKXe8Rf$8s%7K~?|f=K3v zwsnn`NNEgZxDy9pqehJjGc4RO+qeC#tUcWPYt#&}r(EU^E_l8?vH&@+c0(#C-=kkdftLQL%v%E}IlWR4HO zWgr<(c5>reeX$u--`^<)W-Rx2QRXMOBWhq(2XC|q6;SOOA6FHNxI~S|ZFo;g6f0~* zBdoUS9}%S{5D@|^^F@R}J@X*@POfnNadZ-p9AX}lWgnBg@k(mx-z6h!N<~0$?%jbV zk_w`vw}erpUsL>NX6sdCef9o?6ivnC-hpbPnVAZu{yPGe6?x=PzvQ#@k5C<(_QAKG z6EuN-*R6lFANvR8>5^>2OpBMw_(5+Pe0HQ{Ze0QuHz2|?_4&|B`kJxCT5oMBqD&LU zcrK~%TO1vWne7;dLTAF`N8qw_y!L8#b-Hu~{r? zIeJzgviXksldHvFyOtmHV=HZoy3GkhV2$lORS;F|v31)-Cnc|G7Q~+$%)UiL98Nh&(Fw4G)^>fbYEw&~Cf?FDw`~ zU1`Jo^@etn(}?{QHe@%xXsD9^aAu@6)>*o~t+t%-hyGo(73Sv_f2ms=2B@{g4DvFM z#F|Vh^%mM;(jRUF>mZgb8$&~X&`W2Ama$lTOsP_A6ibRWR!w27VN8UAR}WWXuN1B-Te8%DUmqJ@(0= z^wdJelHoI9r5a3|^a-BA*dcyrirv7%3B`!L;Q&Ckuc~PfAzC^ML-x}2cg)=8r30>sRK5$Aq@3~BPftp^o z6ZxG$ul4{7NUss$$>5qTw0Dk1ac(wUz11y(uW)DSFcAu=6FG1xZ0L$g^Zb20d)5xS zjlO84|Az*zc_C1N^?z*I25y?rzWxTae`)9X1kQ!qJ8TqL&L;F2Gq>4x+A96PW6w|q zRcc8Bb5_u#{pPC+uq!Q?LM$A{RI`d#9LRuNCM&*-Bg#o7sUyh7qH9p*6il;P?c71> zGEFMqza4i}aYO1wD{0D*Ek)sMlHjUc-D=dvuTlMM)LPn7uxQ~VAt{iF?Sep_!QXEP zig_7<;0Q7&T@Z$NacJu(=lH9af$vKX5~{Zf(x69iQ^zjHKs0LS{+klQDD{XIk}Dg9 z_Jf5S+5E&W0myul7?fp2Gp^YQELI{+`4WcOPg+$=w$aox&Gby6Mr?UFYCo0^9V%>p zM+0t8)%h$ru&0Ia-N7eQlfvtq7}PiYBfCcldGCkgk5{*K z-or;%1VZuRd^#gph3-)Dw3haj0G}9UAvGA-{&20Vxdf~4KuNCI&=mvRP(+l*X~)QN zs5rU<8lGG7%X&5`&=bCcT<94aw|6Tov$$6H*wjSTR?b@cmLP%)CR(r9>3Xx2u9Z_` z0`f2cp?U290HSQT&y!-wr4;KL#}V6m%o%_EqK^>!pNiUKC3=k4PWBsr7TuY=zj1gk zt80IQV7?9VZ|$sA>Z@)R@CdXx9h>mQgux)`iOgsjeY-aE zz+%bKq>G{tqOe(*+FBhInBwL&KL;)MXRKtK`-lze2#crTznVd*%WLesElLTKyK1nbX_J>#h_ph_B>ZCH6#IvJzYzb z2dEtGd_>DM=w1wv3XWa;8!&!>nx~GLO*IGOgIGcY`2v#y_zaOX704fd|H&P&8q5mQaK7zET0`tTyxmmL$v9 z)|g`_(k>pr`XG;5PIM~4a&vG(tTZKpr2aJL4v5tJw<>anMB9_yl+L>iQk(Q&Qeoa| zq(CznE-V-Nv-*SYaLRyg)I;Jp-h$Pjb<4XKPZbMV!gq`&+@st|iMrCI6hb<6;^G+A zXuQkoZr!+?T#4(pp<-R?v`0>?YzVXCp92K`KPYS0 z9GzlY2`igzAlHaC@5dY1IMlFFR=n^ylM6x7f%Def-i*)vp|}Vu&TwZMtjdyGTUtwR z%Fzs6NaGgluuwQgu5O6&=J}A0S_Jda%!YOBLa(@}!y^~_sk8X41iO2uS|D6lzm{+A z3TNUEQ@M#3u8i``jDSwsP#4_pK-6QjSrSd{{%*GrS^&#yzG{mhMNN&P`U72zDz%wX z&+ncSz2=|nXaPe_#}zc6v|k(sDQW0+r%9Wiy$YBRBB`l`){lsX@r_5`bVUP?H{S5=`Gy)9o%> ziOiRZczY%o+-bxGRK};&4qm`;z3ik%W_`tuED`VTARUljRz_uBvTBei+|GWxfZh@K zj8kA}>svc%$HZh1J->245!^9tWzP0R`kJ!7-R&xB20yWsbm``3lBe_b_(H(;81@fs zkv0PixJQqLMZv|jznwgK{=r~^2vUZ%c82W-sp9@^Cn>eaG-^Fj>3xrLr zA_C+FP5W0d=z{$vw!ta(4Effw-?fyb&~^!~$a{0DR|-6{=UM>8DcFI*A1mqbFel|% zqX~c3Wg8E@Svzs|@YV%ve8e`XW42_tTU=9zG>&sz7>Fm?ParSJjvnVGKg2V~ql@U(!SFy4mx?zvTO3t|VPgT@{(RjfTV3N`PO%?(N? zCo)u=JaImfA`)_ywLdy|bp}1iqU55*6!uxp#n%iLuk15CziCTTK*6X+OpObF*sUlr zwaTm~9Khx;x?KEqU=`pwK2{m*cxc~6999{c0fbqjU0P(j#|YvZ{TnDS;G0>a&07GP zjU8%6%qb|WZLdA*xN!)y^ohZU2Yv}$5gQT{g1X%`TPI4XW7@j8kT}Wn0HJl6L@UQG zkWWA9tzHx^r5f}#c_k6L8{lp+Zioz^N6gP`X8LeumF?C3fyn6G{1ebsd=ergQ{fJ% z^em_BBF$tj7Aw2b&1{LoJveMGN_xo#_h{wvsLAQIS4W@V%S5|D8#-jI__=H;EX%hy zeQw7BxAFa7VVvPmIDDTn2D=l-nEQMWZV*g zl*Va#gl+jvHF@Z4fYY&Og(sV2`t$~{^0)G}mpXwz7DKnWq19dxXxza0B6zHU zsI?XfQ?A$SxRKM^jA$R$$qMA5erG}x{@xYwC#?Bg^Z)V;DxRx7 zO!!PT|L4H9mJIIAFF`;1z$s&jYsu8UI%G}cxR($SbjE)`hw^7!En4>?1IaPbH7r%IRZfT z+Zwb(I0t7xyt%3fvJv10Ill7?l9rQ5NEXmj-4!KwUrqIaIHfWYAq7u%4(8_vOEkhW zZ`)|7lE>Wm0Dgn0WZVgkkSg$c^*M%!a@~?~?3cDMkw$>{Q+@^y@32^3Zuwn;sUmuo zEH|Zb6-#lAH)?wgL4(y*(uwAQ)M->DPG@Z zp-Qn=uL~C3_jyb{O;E*9jO9btr7sC1hK9Clam+IDabedlRtE+nL5dp?H|YG{F=u^& z8FvbVPYmMxkmPiv;oPWf` zKc4Xw#F`$*lKwu6_0iX_*9!1_-Vqkb-w##0PV0SLCysdWEpZ}bOgYYjw%*;@u`CBU z1Ea@2?~i6?XP|n{XV77}>)YQY*1xa~j^{AtS)MhtG~_fm557?%!1NnvJa|vTtX97E zl7|Dg6j`XeSW};hy4@EpCw(W%JomV8gjHMZiiCLOFkT((IGk&*8lb{i zDLICPp<3b%%CP>;QQ_r%69AJw)&?$M=C4kn#Bf7z8`OV2%IYg>5mD(lxYr(9msFm= z*_2=P2rXWjp3k7TI|k&UJbHHoq!ZE(lH7CXV_IaqO?SGg8XQS2JC1&Rqt8E{6plgp znR-pZZK46xYNsESD4Fa=DBAL|K@yhxCZy%KUZ}t=%VYdgbHDO)?`(4@9+zPMzUD6K z0MOWQm41*{D(Ty{ zL$_cdMKR{zHVi23wa*J}<+xg}4WqyeO$(A`f+ydB%*O3?VT~lN4>;+I|GVf+0Z@z70=^A<0N6Qxak4_Aoa52duLp**T{Ptr8BIT=t3Vxc~+yWJ*g~ z%+5^$TOtP;RsQ23$^V44e0X{0Gg25Et3soK#t6)@$r8kV2_(Izdg$R!BLL;mg8F9Y z0L&I5Gbw)Gs}hmDbkUysF+y8Cu$;o|cxC`K0!fD2wJ7-H?xwDrL%tSGd6&L$LS&lS zPOG2R=Dr#YHNZ1Apl&5E(Dx)NRE(mvqR!=E`5UMhXf9=U$LFIR^6Bxlw!g|qdHP<& zfGgADK<3gmMQck)Ow1#*rzG<8u1-!eWI5PDMOyM`rc}O( zn`-%;qtZTS%i|brcfNTd5H0UwIpbz}+p}<#@??7%C4fqw=)(0H7P&dmjVhJZAwv;h z1s9+rm9aOfDYB>C`U|a-ta-hlNYjJd8V0JfCbUL<6jMF0QDVTwHPG@yEJEZ%db(7^ zlK`&&V5P&f2jTz0g8|sMC2}|_kGSm5_SKhl z)zxnyPuDbS!-sb`WOTQ+D%-W=xPDdl%zpA`li42XG($*VB(Usk#f1;VTq|RxLLJ}c z1$6@Tv+(|~`FQZdo?w52meCQqSpf?zAyEJ7y2_>!6DfkmTz}<*K5m+uZr^N)Iq18j z6*Vh1vF>=^y8C59tKdBz{%k`|mvQN!pzyTXA50oK&+wUuJ4lrkjk z1q6933Z}kcZgJbiD-Asytg6B|GB{w3qeGgD9 zrj=Dvy{GY(sXOQE!fRNj+1zO^K|^K$;xjI^rRg3Oe1q`XHZSBe_E!%yqjh^@#@+#Y zukjgFiJe?XuNd^4lahFH3nW+W1`=;L3Ar{?rFsD^xAnNGn$=oEj#88L z<{b%~f@Gj=4^PV+`Z?Fz*tLCh^TMDVl5gqqbxcU~fDGM@TG=zO9fgEH+Fc5Jq*a2= zHYlsOg7A;$e4a{CJYKpexdhR?RrJtsK$$zqtAQRl18c^UTK@uFQvk9@+E(H2tIP;r zs)Hu3&wD}&{gbRvjkYDvKQ6vejDIcF{Y*^pIr%m1CE=5dz4DmJ@Ff>9 zg-YP48vXpW7ji8^SchI{!K}5czO{NK?T+?KR?YFAoDS4CGLq}MkdoCYhLPOCX$8+k zSLG~dIlL9haAzJ`^)cIxE6CC=UFZL=wv;{R5rkvPN8@H90^!;iq3t>Ef?`iGC-Ng* z($c(P6iQ9;9jO!X+}KUpKrywN8k8~m5_W&YVT}W4%p%_%510El!+&53f*zKvwTXYb zfi2X1(Ff^p`7|Gt2L7l+*^Q`py#HU!ca$^+MA1T8)s%^lHZ5aABEqy9n!`wxH=Xx8 z*atZ?zI34$gJsDnMGC=pii4eC~6QO<>see9-POhTWbqygg5 zF3b^$x71wShGiC72+a3IYUM28zFJfqq!=J4O)sPMxEqNE>YuNwyE1PBzvakHmG0oZLb`Wi&2~`vgyH8=#X?x1C44Myoij=Vsf+IO<0+^z;4kpfu%yUVj|z1!&05c;srrKYjC)48 zysKDMzO>blhHml$_KJ~0{Ndbz0ka-em-Daszc3A?)b43D^HL z`&q94dfpGq722tJs_UcjMeBZ=bxDYlK4MhxSeWcATzwg=e!A~MP5@9C@{S5l2d2L9 zU;^^f?4VrFjO{OeRvxRN{@I^S(Qb;S)qjwT$FamaSqxYswNF_yp4_0G3l+@4Kq`NZiqx{mkpTyo zC;ZW=?B#QGD(`ZE9B-IUu_DJiZ6@9bWY2_OH$=&4{jWmi)cfK-i?m~HsC zNka0f)IQm-Mgw@Iqdp98b!;a*3*_a^jiKv}um$Lh>koOIwRAE&p@6!NA-JH00VVT5 zZp8ZQRLJ-sriGH&b=Y! zL2xeIlZ8?^eNuPcCAC`?F6*N1>AynlT~q>_wsUj|TQTgLuMa)P~&cC*T;aso#6!@*RKwkyR1R~~c6|XN2th7B<&~JgtnRPx|K2t%xk(p)f80|eF);&IUwNJqz!6p*BpK`I9<299= zkV**f@H6{QD!{J(JKIF^s%K0JY_twI_l#&9iZ(l8VO?6ugER*4evY1dL-xJMpQzFa zS2o>l)8g$b+qT!0eN-$&48dUw#cpd<{G@To!jpFP4k&7G0C0dmWl`u0c;Ba(hCF>j z8m75>#9CrQTuVVE4b6*8ER8`+9HS^B%?3$CaWeEHfs8B6j$u)x7QM4u+ajBfq!mOI z^jo5h85`7Ve8^6ISM6#Bd?kC-8j-Cz%Za^zQ{Q#7Im&;WrAzW`*5{kA!IoZCxoxFx z{2{7Cc2x^9c9(=>W>PoN%#HI@K?{QYt zBjLI`2s@>rs|W$uu&wx~OEQ}>;$#EW!>T;_rcc6Ws&RL-N2UpDm2Ws6fM7vuzokuE zga@$LzqxOBD8K*g>M7M%DIMek`Es*cUd+vH0EMmX9=Pn+wCuFp#RxXv*S=C2)gED} zOzgS$j0;_hKTpY*Kl+@$S8qO*TohT2HgtEGC+;McnwH)VLsDCG@?pHK!v}p#Ynog< z0}#c2iUq|}M(%lj5w2T^(f&;ZW&~1VhrqjT9CXrg#LE_<1SY)&$(Saw~VuS${cqe8}HPta&ezb;9C4 zNsyIw+ys^!$*)3mEFh`}EoTc9uH#8Dwl3>VAKUTxfFr;7mWW|R8 zkronTIALT&=!M4Fp!xb={mY^O7(Z(AW|M;ImpvF@sPLqcyCUqG3%IA|XW8VtIS(-? z2(aIv7ZoE*C6&1@>j?)*<%fJeuE0yabTVdnY$BfJKmd7UOKa>$PFk{f=@>qQnqA5F zP=2IjNT-4JpAMqFG|E*r^p;zS*&GKSx01M{to+UqV;)tO$HB1!MzOMMX0BtH zi+LIBY*~#}z7#{)Ef)oaN@5nJRC2C8r%D@*_s&e8Exv+{Cw&9x_I)|oNq?}WU8-IK z0UKxq!3wkyA8TCH1uJ7kD!%F?1C3hpHj6u-Z9G-b+dHL9Ei9Rm%yXdhl4wvVC5Y`) zpNr}JnruxG#q@s4;-;3MM& zvMCQT-);kKu&~}pM;^))69B0oVE2kJ>FBXaQNM%;q$ zzp)QC50@q0mwvoF+(8_hA^NIjM16Y_%}o1Mn&&mcW+9uBvwj%?14CLVEO6S+Q+u%e zSWdIb$i5hPX^PBP223NV=i6*laXL=Q#3}Qdpn?)#u*%10*{cL&rGN}=)1OaRDf6)= zw$mPbQ`enx1cczEiJR4SXn;9NJQy%B)gNQnD;SBuxm#t$=6qy5u-!Gb3UT8<-HML20< z0P7hMefQ%(-sbSP8C^c)#v80p_A_CFhJFnGP>aU?7Z8LPQ-e>4u|6|Wg*NZo%RpkvrF{Up0R zKzgFBA?>dfqmpl9-_20f|C#FRz>WZ(rZfJ_Q6IS&sr!+gZiYG#@gK}Nc866=C-V zOze&-0a07X$n51&lFypT zWm_0U+qp_ry&~P$vsE2rUY!`54Lu7P)95{MDfwD_*bcg=hC36f;hg?N&JzSf(QJYg zC2cRH1P)!i2&-O{QQY{2%H2tS*EOHf%*Hu7 z48vm=SFqaLj=onQNa^$XEjvj};C;D`-4a0Y(cBx<$>Ty}2YUNXZM%yNWB1q-Y^$pp z9qOuC7d*rAx0*R04{^V_L)nl9%FZ3TB*1Nu58m1f1e2o$wAtD4O)PpMm6QgYj%{Om21?Ed8Yv$^h5Rbi-?G zr>b9ft+S>9#nbnF=A&8 zaS*LXn1e{$>eHz(n<2N(uQOTIhzJ6*0JQu&2O(u2_CIZ5BU(+?xKUEgoJ2YhoVUlA zmrOkN=Js5FHSyG=W8suKCTP``|~ zAHE*_WIC#F@Ia+Scm~fnxahAtkkE*;JR@g%IBtsKJ*OJsx3KroF&ARFIo%tMYRZtUdxD6wL|_S;Kx%> z6H0q4%_k^2(~DSSF_($2xt9dmS=!Sb1;3ql(^`#U$)>^hkU62|O8Q_dXLy#5GNOke ze4Y)zpn_dcGmLZbS5ajK1Igp*7M;o=6$ag9bo{gi4O=*KR1#Qy6lC8H2kMd&hf#Y3y6@EpY$tY|4gFyKDI%nVqU-_k1l!=EyU z1y6erwh~?zQ%nT|V*z?6(oj&E%C04_Q2|Znx7Ii@m35+YrtH!EV46;J=|X*eoc&$D zErrdR;&~?;WZ<}u=8i8@h3)srQHcKj{MRre_0t$Vm0za*P*nmrOb8{nJZh?eY{t;xr>4Q&fu1w^uY zFsqond`^xr0e-m7YSz47{~f&Rz}WFQAveI6xm8tfMfGBU6)2}0DhOCf=q-D2eDlDH zc@Xjj@gf`Dps)|zQ3Ndh0pV-_rr1kzv{W&529A@lGne7Q1GTT~6LkfCKSvU_6n~lNbDz)mO`cr*Ve z9tTG(7M(Q=#|g*b&e?{)#{ruf06b;a^PSGmSJ3DjoqsEu&QP5|4dgOOf@?%y%f zlIvyzi@Idkw~~0C5NR5RgMLutw0yaK0^4lBeoL3;wvbzPhwPe(j zZZG?*lQ8Yrht889rL?uFk|Otv`+1>7uc(c<7DAy6I;Pc9{e&WimKD4e!!XyDayg`| zXbpLqi0ydsV?ui~=WYlSMWZ^83zF1{ZDzb<9~86j(oWm_>yYC=d5Z@FO8qc>`2Gi{ z{=UB+=?3LMqi1IcnJi+4-7~~a>J58pyI(S1-WVtrN(4iBAeUmXpAId3-gLWCPWt5@ zGZ@aih0z4zc5M%YSc6WH4e;G+e6rF){GvbLZ_AF6`}QI8a#GR#3(F}c6_qvnMZY5J zUm?27{czP@=EpU(j)dEEo+QX!ccbs+4f+v^?WGcmi>bBnpF?OJ}ezwi|<}z?P(PW7y zQvuLm>m*(CgYv7Cz1JMSf^pW$`|IRcQRhjZkvHQ8LJJRPnYwRYHBNaDT}nqJdV zkmwgan9@1XSh!Op?KJK^t7ht4p?w!bSTQ_r=Sk5CQQT!4Ht+I1mSkf+-uKtK5LjO6 zcV-+|pIuAj*kOU|;JcmkU{Z+t5N*u}f1&R>q}ItW$&gj_0$UY_<~4RJOxx~Y+6Lin z_pRyroF=~y3js9ARfa*^_A?2L?bgZ{w=a{Qgw6}TfgxX{n=TML=JX)*rn|0clDK1s zd4c+`xy3Q#=z&&>CJ#%77F%D*6 zR-DQ}cg?5Y%VU8?<5@lm1So$(r8oXo1DS^#SqI9ujD78d{>Gs~W8bBtUBE0OP-Z7l zcV)Y|i{Tv{C%}+=Q+>QBWSskMCuSkg2JgiJ~S_CzvP?1vpH%r}X z???3<0mk2H7B@IYB})xKuQk=Vcn_p^M(LP3Tw9&@3lbsDR~FdDc~+({^Cqeq458$% zy%S-7{>Q(ezD`F{10o@F)6a|&WUz|#eqDY4jsNm-v$Mohav9fDQ25(!Y6-JEYEwM` zU8#?xtQjl6O*OgOpGs;Jw`X>+*ZPM|TirnkB?fNNHTHDoF9cX)YT^jEB7@BB-K&Ig zuU)3SwSiZexzngn_0_6l?ryuCb6R<~c9ik`5abM4WP0wPI81(_0Vh9m*zP52*2z@~ zsJ>(qBc&KpM)SrR6634c6g`$Ow>}OdRVIXP18DFm3csprEkL+mUy%01j9YP>t{?Xu+R5t+XuKcA@^t!y#Z zD`w&l{d-Pu;&xpJ%B zsUV)0T_H@y_le%QLHAZc*XQl)K!BQF@xFG!7YowzzKDH7Ke1qzQT&SLl2%q? zqe_=Wz(aSE(U2Tc>D<%eRVviXRpqumjwP1>Y0YGsV>%w*Buhx8{q@Q=<8CtvCo5_( zp!ojad$Lzv1H!M$9lFkKK`VgmnCLk4#-|In{@U_Dk5~4!^^e&x&Memh+iz@kTMZV|N1k^G* z?zAXizF3rF=ETm#pXLZ9cstj~t%F5>BPVg`R^-K${CvVon2+S|@}M4b+TSHggOIWt zn7$Q9M>0-^99|cgH5Yk#3|NCqk-R4WAPUQ!oen~_m{B@zUb}2!dPl>|>z&CpKqJAE z2x9t8jH(wZrEO))OaHNOFj*!x513J#!xp3*A8ssy8G#2d zE&c4W5-lf)&$U1eJb@?1h#1I_rW2l@5Ukw3&Ay9Un2VrjnlNl@AT~vIxa^x2i)?C0 zCtg4~i+Vafp;@pGaauC}1ktd+{$7m^l4&AB&B*LN!>V$w1tZ{l-a_x9@A>g02*t%W zma`wB>a5RTYbw}(2MN25ZKS}sD_bA`R53F4tSk#4hj~XR5SN1m09-Z z>;ZoxPwnzoxQSKvE+O-WUeSP#{cWyjpJ8xIBDv?2;>#uk^`yQgU{kGDiZ#H?MIZGq zW*+q_J-J&DemUKflbJHOBT7r)|9X<5jY-(6V{)&tSv4T!Y@D5%Vc@LXJP#|rCqfh~ z^0hsUTQp@9!6t@$5|>{?F!6;E{KDV%Q%~k|5E6W#-FmY02K960)%28-|JTukR)AR3|U+GTU~86Q!Yi@7CGpT*k{4a34+$9qN&yLXz$D%Amr@+ zH}tjq35h>g<&%+ynhOHSI{?SXB0ze86`g}l1Cyd%fA^yB5PX&!llv;jb{VhsJOvX( z(B3e!hdsokh`L?|d@2?F=bsN^66=PE&8+4cc7T#}-w!)xX(dDHHM2F5j{nqCu-@%P zGpJJdt?$InI1kzq)$^9?_8U_@j&aVWe=$745R_k9%Vd#9=B4NufmWIRCfLJuN$vGT zJ1N#jxxvTz%275%4Kf%Fv-P&&==lH8;&R*WRs%^uB+pXCAvMct-FOA*Jl_lxvKMju zj<7SqKi5`Ld?l4_ZK&yGQ{pdM)euSs*vZ?^-}&Uuq`M0-6Jjb=mBoa9e=O@5RFflQ zQ)=+kpEqac28~z~3{~352;fWVsIUCeyzy@t19uXB0B)BLM42x%YA3`x#kXCQ%fr+T|i^Q|}^X+hsIhlwbFs z2e!fLnNc2Zo&u9kMH0L42!QO5$$TLKt_*(>=VroOesc+LNN#)x;x(mUg%>OPTo@|r zh}H;i4NW6fajoB5$K&a zKq~wsfaUd*!?2o%PY7i!p}nLcD`rQZ_HY}8Pt^cr_twI{mYkbiOW$h{A7G3PyUa>} zQwZ>#_blcbyDGTfT5{<*?-F|4oHp!3#V4yz`|pT!n5H}4tDj9kl~xMA-OGIHq}gD0 z%ZrlqW3JX~G_y}5Zx`$u`_)j6wK*O~wqVzYH@Rs#c`@h1*K+)mseeLJ?nrq{eu^XXyJph-usYpA12 zq21Z&=UavQtEg#V$)~0zehG(PsF@sQTkdPF?j_8>h}k#!H-2WQ=xn1;E`xkeK&3TC z(`I#^7cPp}yemo6R^Lar17c(5v0b3}elL+(RhO~e$2<*}G{;2u>7ymH^dCsJ6?lo1(b5>_SMsXVc<@%ZM>DKpt3mMYWbSO)(X&*wOuBafo=4^sZbkrI;v%LiozMiO-1DmIBh?`T00&c z+K06AyWv-K&_^@l`G9^%z63)Ux+w^W9@a;u^Tu-)Lr1w+ZiH-mvMYNV4$bvDz`b#! zs52T`a2gh6CUSa~(RPIWz9v7)-bPIM+eye%H#@qF$C{BTGO5N9LoMD0=R>OC*mu4{ zj{|ZBja>IUr)4?M+cr;q*wDzkWxrRMCl9rlTU5G&Ux{UN z3SGLQr+RgssJnw_LhUw6iS>e?7;t-n2wvSS>bR0NY>%eO*uUl+6)18%BT9SK zjup5RpG{)qL=xkxEQDim&j3GV=mdmTlatAH{iGI@c} zY=q_$N+-EJUJjv7_f7^KnS)yOdK5SUW@}7?Gk9OkE`z3%oaO$n!wBPCaY;h_g9cDr z<=7IYki?!t?sVw1!5&pa4_Y3n2QpAz-|tP@5(>dag>LTxe@GVvG756BvfF73@D6xc zBryrT)Nz;fqAM!>CZRezuueRZ`y-n6y31bsz%dgYSrY7G;1wK940EF<0f3gG9F*ZA zqsD0S;rBN@>zM3q<;~)AdB2<$p>C*KTeneCfUkDA72Sym&;0S|Lw(OIFhpmgDX;d_ z;>l>nw>F(X4b0gPdsRh7dX(=_te|8*Tz|`*%k%#mK)SK>Z@Uq4ESf>WD@#Bm872Y; zqtq0K|Hew!N0F9wMRigdGc~UeCmWe%?UENlRs0mJK<$lECHvyLuB6!7H&J>BD=u@b z6n;gSv{BT5`CpqP%ytvE*r1z#(|D0(x=l%l>1$;r;@89_G7wrsb6*V6D=r1rNP+^W zaL~K8Rk!#gS+xXemyuktktIxOZ z@l;%#~tk!{k@D_qVFl| zmnV;*$=nj4gz|jX&vKcHg3w}XJFe4O?P*sVu!6(LknonBfbpGqk>%z?wJYr9#j0`_ zYA*EBvlaKujk69Vr0x zHprJ(rbRq|U`SHo z9oX{`b$@`TBh^;q4Q^GK)fD>-g#3Fb@rOm*Fn}_qWcP>yLGe8rS#C0x{YgoNBq5h=Dy7o|irou+r*u^ABTO_Qc#O>Xo!AmWDre;0NC)%IMh5V%t#I z`d>$0O!U6;Hem<_yUHJNe*=Erri1$(_3iY&JCQ)sGkvpwieU!U$K2AKFUP7wtcRyu zakL8_I;mARID}c4p7fNk85gCPQf;wQUlp|tcuY>r885*>#goHblq9IMvqhMe1^ z`#v>b6`BGaIgL{opA%ZZw#7=WAQwGkSYt3|>rmn=0rhax;Uz~;{_=t6s_Hzv9 zxjUut!Rq-cR{oUrO$7M;Qx=bKQzNsSwj{h$Ffp+0Jr>%*;9I1BAvZBrupKL5Q$toY z0+@PKd(qZ7;Zkxazxq$Ypb&6O#}O0ob^0VH6OXPkHvM<$0rv*!8dt=ssG2o$JO!Sj z<)1;!Gt0cw3ARYjo>8NmClC0OB{_rS7T)O^q}ty*d_;o>lhmlZxh%+VUC|h{EVB6R z*>A$2vJ!ZoRspYPlo0C-H>zT46H6DqHD+iKp*Wfu`_(LR{U<&g870--TEiz=m~12+ zN4lh#>53v@+{Mr-7C$lJaTj3?p-e)0g%#}>kNK??sTEuI83jr{N;kJe3QH-a+BUR*W- z>muRX-9Am9_hhDfib5C9&eq^5CqDb~<7C72l1X~dwa<$42+<0UpX$w)_Cg+hGjdYU7NK5Vf(gi3 zK|3+i*Cj5t$q$7(%hjg4|JGK|<{W%W(oYkNt`%)2rk?i}rHE3x3E|l7eyXimyynjaR#r)&4#t&^(TnWT1QVPA^~Q)%-hy=|q(7 zJmyv-*$pSLdTY=2>UVIo;iC_9i71;U+p=bjaCzCxXp!i^k%ra|T3gBtl|wIe>>n}X zj?NPSe#VgdwG#{Y_cYg484H;zMQOb+8|@l;!@%_WE88gsr1Mk1o^V25{d0pVU8mkL zC3J{-c!OU0VVlbcza@AjBL%Bd9e&uqcR(mC^u&@%Y*1yD7P52f#{;dY$1e)-P$E*G zLM{AK$uR`2uFK6<4!AqHdJJ8Ka_m{gv5YEoHZdXogaIqANZoj>-i)_t5(eHUS<$$Hk>zQeWyGuQq8!F1A*1HeTRliA_i% zYKYC<$aHW@q#T^VV&41XOZs!;naHKxfap-0 z&IKhw1{Vkh99bZt2}K_qS$9?HHVR*tI+o3>WdW*D-}3g`(JAP?9lK;NbR|spK|m4v zSterPMb|8$VIi%ss6-pC!%cka>SQ|UZZ?jQEf55xQE2;Qg@nc?oFTqm>?lj#{&2~9>^MBU^ zfjM-&^94<$Vw*q_gq4=~$~+=tIN%hA0mZwM?g1K|Lu`wyLsGVJGB(PEzK@p&GvVTn z^fRy@z#YIK7}4rVkc{Meh$Fppg`t@wnyLFE1&G-ZM3x$4)D|lq#3a7EA*dNX-~YFC|Iq%-dn@)=j;bS z>!`#8M4~mNkc^QSQx}m@9!2Myx%7Z|*OO-G;A`X^0+&so6wt+xer9Bf{~VW*T5u~E zh*KZ*p6_=kf|Iy0-7dsD(ml(m=|*wNB8P&hLP51>dp3xBWHoB<9tii*G|*=0xtWs6 z?iLMt+t1UUktwB%bx0->QD#9N_giM;kcwFGP;+))ccEQyxW=-~Nv`3-9r8q2cT^+a zyw1B?yTu`x>XrkLiJ;@ ziNIlyjkRZFA9G=yt{{e}vyS?PO+YrFYQ1v>yv)mHobm&A_<>+yCelfdfykgZcY|l( zl6HT|76RkocroEgd9 zxm84BKXyfuX}1bxC(V`jVM6rnwgaw%Dw~_SX_jrbn%Ae~6+?XHo*Sy<6sY3>0Ejin z+@_3)G5xL9`GjTJ$5E`H&4n)ZbgEBJSWhS1z1)1t2eXNs_z;kdmcV?0q_xA&wA2M$+x=gKPacrR7xThG!l8{X>>O|$8S$3n> zds*IuE}ya_gNbkc;j%(Fq^P9QdHmBpQYsbMtvE*|!?;r0+ zS$}E#Ef{zwYz33%j8T0GkX+<`Q~#JC?`a)=_ma+hZoC1=F9AtB1Pvkq!)a~2qUrtN zv{x8MC<=89N3`EZFu^)@HYx!87i7WrMb{$laM*N*V}_cGuI2`DdE*c82Hd}i10$t^{?ikFuvzm ztt9*oH#L;FJgUR&96Mo5#|}qpC}}ZFmthn^7dp}midzfccIu%!2Aqj81c&YJO&}j8 zKd3LkoI;mKC}qmN^-!zg4A9Nm#a~%x^;HhOnXKMwn8}6*yIa-Q_tGG$-pdM|>XBMM z?imRYxNhG|@74p7sfb49fN)QoBrZu`Q3L=(j8c#Ir1c+U!jhdij*}l| zksvyMt&eCrg_Z9zVB?(5{>s*T2s)8i8?j^IHZwkNGI`9^gz_jp81WLF-dCi?ha3^; zIbdJQ-o)0`8z2YpTj5w^qNb_iZOnP$)l2U=hQ{#ZDG;Y{#PU@hjkaYD7IIqJib(to zbID$pU#ptgr)NW_@Jt~KqMkQiU~aUWggtbRMv zyb*DGT5p;S?n;vVFt-0Mdck8D=HbsozZ0jOo0xT2*P+Xh&JAPU;9+M$4J_30j9?#Q z3u}mZc4S;-?-V#4w{S>x-{10J1_5z9&7_Y;bWw#WlgmwHnVPV=W0lN9S6|}fOy{wz zmpJtg!+6xs>*z*e zg>L)1^Vsu6Q>nKeoP@yC1-=0^j`0rmz zwN%5Z?*mn$B_WutQ9XiOonT0S2(hVBKGD;aYI!v(YP^>8&`JmrNVZl9xq?Bk*&4Xx z&F`bK*(UO{7UIb2=d*_dk}&h#h3t1+lIP1tQD3ZpVH$qmN;}%KP-XaEBCV2uerA36 zY7~|-$%1scF7kYcj3uKjVkl5KfQ%hYU<#q^M(c_@u3UWG=Fu;Xl2{EL2u5u5% z5-pqq(RyjR6!DH;JtTlMI$U5Y16Mb+FPPc=TtL7;qF7Gh+&D_5cONS4t32w5`B140 zBM3<;Gxg|$uw)r{z9xr;9#(8WK=E(||NK1mMooKcmw_C1$~Huh5o_= zr%E3NI{V{{*0PY=skfL$d0i0>85}8w(nWO?f=G(q;=NtSh7Aw!t@{CJe% zx#`DO&rGd0)`7BT-(mmnUe+`g_McBqi-@_!I@zgIYSHdqXZZSpOz3UDr{(6qZ_3t$ z)+GS*<)4r&3rUP!-Jwdo^Pw$v7HG7ez096~7P#!|cjetr1jx|1LRHqXQ;hDp?{3E4?4m-5sZFS46dCGo!$Q;LpSb2NRDf8my<9t zwgzpn`Tcltv8yP`j-LQB70vYpJ@DWlNGpl0U=1DXOtX1l9IBG@g=Jvz0f6xp z%xwPWU^oMfFFeB`61Nc}p=`BxYdH>Mlw3r6CClrIb?m^y3terBl65R3#dUD)U$zE)-_Y6FJdD9y2p$>v$0lS9|xrE~&9Q zl9vVyrk;pb4vYEnsN_POSD?m1zt879XcH<1SrDr=U)k5R${_!$kh zLnDZFEO2Q~w|k}*{whBNgOQu8}K@f-GOl zG=Ws)Nij&4MWN7v^c%aRm3Vo#c?t4?601|?)?$DuYm1ua9B8P+PIuc%)qFl47Q$zo z>t<*f6J(=N!!+uruNZic;`WiB0*|ijR{qg>1mR+`p)yu;Wg%*jxQr5VIfkss*(`t= z2+;?SZz5v*3Jp8I;H{Gs700-r352E7Kv`AY3N~%8<+-tf3*)dF^BRu&-aKcW6uk`- zSeI9E?Ni;!v!2RO&d8{%f@w?qxj+wKgz2Lio>acxI8>3jZ+uGiW>)+c!F&&_vk)|? z0K~vE0h91@!?DfF-_1~BAb?2?u| zO~)R(`*rOhb>ZVbE|4z;ETrT4eKK=lDwY(DhwE7)T5^)BT}NQO0bh}tkU`#hjoG5p z)Oh09vk)7&!RN@v!t3$XH+GdkuuR?Dqn8cAL+%_~uMmM`ayQV^qTC0kwjiPoIb^sN z)GhGcxxyDD&JqbN)qN`N^e1Tb+Xu$?`3}RxqvRAI`$I#++%KU4kXn7@OhfRBTX(+W zEJVm`J-X2P`#f08&tt~ghzpe{qL)+;t?{5-d*-Q_d1}4}O_0G^q)mjHF=7gb1wtMk z7Gp*@P@MQTr?2}kZ|}mBu0Rj7P@_;W|6!=p0+)P>%f-E2)$=xe%=rIeVf%KK$k#`) zxo|Et1l<#s#zMJ1qR1A^{|RdY0mW=YzWK!}U{$f^!d4IfBA0b)V57%IwM^R1RTU4J zWiVfWQNBwZ;ssvr^_L-Di(}AqqzN;QggX&f^15Ffr|F

3xWDeV{EG9&MR7z$hd( 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±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 Kp}tZ1`lycVIOu2q literal 0 HcmV?d00001 diff --git a/openwrt/patch/mt76/src/firmware/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin b/openwrt/patch/mt76/src/firmware/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin new file mode 100644 index 0000000000000000000000000000000000000000..986944c6f052884fbd8701fdcce86515a37c5449 GIT binary patch literal 1596848 zcmV((K;XZ@XX=2(kWDc(l|9hHVnNKE-b872N{d9t^_Hv1h3!dSPC0;=SH~J1srTmd zh>j_FrV8`o#NLH?wi_Ws*X#y&Xiz~+4$m4W*zGU57k)42YaOg^^z$4#VI{N#b8P3m-fBL80@LPd&(i&8bP>^ zQ#f(f7r%0-S>``Ou5#+)qp`DuFy+Osd%t5A&QXCX@Y|I;zS*AiCA@1i9Ec18NB&Sb z;I%5}crsDUu}#efIjg_t(~4;VMw^%L5319RqJ<}68Nzj=8?~aKgov#n8m?>j8!ZJ0 zP0QD1(xxWjEIZpYKyu}R7CUfPQ*UVnUkOmBX*a#T;|w>T?-UGEfPNzg9X=cZ9bK~( z=-G!PGqAYt7a;It_d;W{fg0Pfn65zg1?_5ckZonuo@Vw{8>dyc8Co8$56wLIc&dPz^H4UyIYc8q*A3c0OZsR*A7Pl+@g?)$IjU#vmlWBEI zAN|oSVcXqefV=p3MRpPkWFd^P=7{MIHArURVHB@ctWM2xysdraIn`<2*?iSq1@qc? zS@MM`OZb`Fk}%*^yo@otT2m!|Q6udFi*wqzs_SUwhp04t|Gza8MM3NKq0q@4w>l(D zn$n-$b2D)NJ|DcJ)?Q2kVO74gtoaJro*J!+G)e4YZ=r~({0y^S(n+AClz@}B)t<|{ z9U7%|C=RD7d}41)jX@nffd?wo;pQ)FdC)B|1|{L7j)OJ%^7GZ2UZ|+7aC2Qn&8#BQ z)?-V(8cz(zr}_wfx`SM!&%8bGF4cNmGQZTQ7ELT`)r=)MR0QN>TUDL!G3#0o5skQq z3D|Bf>=f_#y}GohvU-+5nKnZtu*L|A=-K5-loED1(_VZ!CWH5S2U5UnU=@-G{urMD z@cn*f2V?qcD+rUuK#oDjQHtqnoOt(0=E~Sj?mRg`rCYai$~ih_XS_xX*@WN|!|tS) z4@4mznizC&Q+o#;;bEwp&^de68oerVsyI#FYXm_DWk!+5SUs0rSrHZh!s(&8SkZdE z%IMpy&E-y}>P2(!s4K^Y&YWeEf%fUDDY+F?qW35glNI>o)pY0bI^&nu5|*m%)XE+2 z;sU#&d>;~K&$(G~?}crPmzIC8#O3$5tCi=f6R*H zLj!d_ZeACi5|o?7`M;?$3cEes3JMg!M^opFp(d1?Nwxsx(=uT=;v_zasg&AY-w`Y4 zintMvUk`W|yW8Os$?S)n7I)P%(En+V6s8G~Eftoh;&&vI4UjzVIFphOvdDEPs&ex* z#85V#``BmvZ7{>)y^MT29y+Q{#`HlwNtj_ixFqfXN`7`Vk|zuYjw&-)slFqVlM2?$ zHB8>cNBjErko2b5exO3=4_6$4LCs96VIjrIFObp}Uy+s=Xj&pwwyf!{fj!Xuhj~-ZNhYDPp6<7ot~m_fzKgqD!r5>X(5t@)5|PnKsow^irPIU>c0CLB;Pf5 zJbM9`{8Dmi!(3jq{A=*S-{b`rcPDPr_m%{PFlDyPpI@(Fv~hM9aUzO65_b~ClpDha zzr3AR2OHIM;cW^r^-VLABTEEtyP>Sp`8B$Uh82NUgOpWa>(TeOC!DZ>C&e$SSG}8~ zNilZqNwg3hD_~yElax~i=)a)c}Sb+>G(eJ@B6z}?O9W<-A04R<&1%q`D}_m2fdgMzcDizeuWg~TnE z%8~=zRZ!SgAUUuK$2}g^Q@E&p|bx0>arnjf%INx=`i5I>BW~cmfx{^tp zC$~*mppbCM>ul`kJr;-?s0+nq!cUM&+J-#Oy%X%a>){AMmc(Ya;uv;>k-iBFq}FlLcKHsJnZnV~kvK#Y z#f1?5izVY9&gqr$8Mo(~8z2g}6|?2UoyH7eudesBIyMFt0UG;$;0CTVu?6dq0~3xO zmd#+~b<(9wW1E|p!6%VStrr87{&6N3@=xSt^e2+yQVSU`* zniZ=qpC|omyAjgO(n>VTe)DCyw4g8$F#)XLv!NczP!vYc4)Y{hV1b!wSR^S7Ri!O&mMt#e|1{?Tede1q> zjz3jU6rHO@ay3o8Y_s+c@^3xLn(sFKc3kB+V{R>azh;We>f>u_IPBQ!ldxfb<2n78 zJq8U~w%8P-_7CkUPM#Q2JIYQCL&&LZ?>jg*aOAuid)hnP6kio|(Q~8**~WxOOlEDv)hnBlA+{%bfSjdK=$9^#i6# z^$YwxChtbW9jSOT!OLe{?*)k;`xdloot9^5Dp%Kj0d7O+y>OpdW-*LlaD@>PqB@c8 zYsaln7VYC1h#olBLjMWl3zYFrw;QT1@8=lOW6ZhLh1n}&6$pj)wOgHQx}3+fnHo_w zl?06dU%1>SK*^$Z2Gw}HrfU=T1($&Y97jgPbBYt*Q@!GeRfvvgQm(^y?v}P-7s~U> z>rj=eLS6+wf>+y8>kx_{c&(kONF|3mZSA1#vY8}v_4>914&I?7C+t49tv|!;=Ivg14DtfFf43~{DuFdk$<{58X|};uyzw`s73NS zUIGdK0ow}lp2%RF|AphKs1Ffgf+ui_FE#1-$6gxlzK>PbA_k)z@L$ydRa#%*_(?Y7 z3Rz>jzk(=z_D&(!cwz``pM%8o&c(YbE1&s?<36$cz@-rFD(I3s2$5Rl45qe3L*4aZ8GPP#mmt2FbWi0Ix+uupRqm@Ck?!>LAaBAROLHJrdf|G}9kyW(f1I+h((Ibm7$L?Lg+n89qUj|C!oKrTqVTB$_cnN< zhI2ns!eO3edDZXZmt#-1_`Q}rWZRJ=2-*lk|BlHoILJ$wL1_}?)v;#@9aN{7y+RkA zXJ6kWzE8d_M_EaVRV4938cm=GwVn3sFgUag{f*0W1D&=rF^sgGId_=8DsI~58}b@9 z(~C%D-+26#;7-J}SPnEn`-dj=9O%wgQ^{pL@FF+nlFl1~EH486D3VbVzqHo{lj;;C zt~+=|LWb&Je*mdLcnr%9tEHgmoV>JA@`W5h0@*Cn?#KNga)Uw=?tZ2A5%ug zsqvoA%_QzIF{etS2g>RbL|n`9yNMW5C>dx%X(0j{L}1q$?dT>rKDrqXxuCa5dp@7l z2~C@N6jnO(V|I`DcGJzBB5(Y3&=n54NYFun1;P&}B{PUYS9F!OBAZ$CubPC%(ai$l zlA$OdC;KPMfoB7h(3sYGc~#>e>effLTY2~ z1M4p`=u%S+`+vK4losDWkb~_3I6(di>5?%fx0|?Q#Z%a}|G~(p7J_qNO>WMG&zvAkNbv-A0M+SoT-NFL zo!z_L+E1*7zWNoSp>dYC?I6&8^?M!C~1Qr9pt z)IJ`&OqIxAcIN%7b$$(u^A_mB$ z`Yd*S1wOJmZ#5KHYunS~Cz3TG&}*X$MfvlZ6a1JSNj@vcLz9Q8@GF!im1SeOUwk069mD$-X(2>fq7OACi?HO2U+~)tEx%n^;>v} zs!fsd^{9w`mx3HGpl6eIZFYHG3tZ1Xm0hhM$NV$iYa`x;tWkMSY~_3encwcM&vK5o;2N8$SyN{DVmR63>mmGb#kegC~)lla7_;b{`~M zf>XLn!aLq4z@XZ2EbpM`1k*CaPV9<#fK6CWi}2CGQ{L+plx;^&1a4^uV`C;BQVC(n{O8ehi7+`nn+AH z9c-qiCJZ^-Xj&Q&vK5vC>Ez>YJmpnG7!F8xAoN^{#mu2sH#|9VHyw+H{&$T~q!X&h z_a9dlT!{D((zXo4Xh9DC2WdfTL+- zsxREEW?sR!A517*g;5eZAcs?#?!6}}iUYBnEQ8rK#Z{AYe?<+8NrBeD_aDyP%yNms z5NQXJ-f(qs{uiJKjaD7d1hI*kbB-5L(DDJJ*d&9rXFjwz_|1vOEZw*RB?^ww)-j5&Qcn5$p<3QQM@qZU@ z3T6$L3w^U{?4YzsjZ}wpM$z)?RMr`yHxi^oBmnqOaoI%iHn^O80lo6~!8LCdEs?F~ z@2DsY7ga+n!H72mv>7Rr)dD^ra71RLVOmi)?upvT=l|c$O)j$*r)G^yjV^Ms|7n;1VUxM2`Pf(9qyQrKCzf9+>7!!m&(Iw?amnE#!tHV z>us(CXO6)sq09}zro%P9gPjP94jwCQ-6!TsY|QwHF1F}m7R|aVOR$(^NTONluj!bY z_BY>D#+u5Et1TpI0CDunf|Dt2dndJ6|^z0v&wUa4_IDPc#a+R%-RXO6%J2(6K(+Rt+NlK=}j zv9aJ7R6|55`ZbI164Qy$QE<)RSzksX{urEbsNKb|4@!-P;PnF!*R;P}sle#347!1Z z>hqJjca&(5+x0w)g3zhH2a9Q!Qpsg0^8U_3I{2xb-oz3fd8-{kz&u~dluf?<+l>Wc z1hu(z#f12w8^5)z;p9K(sskWza^Mxr>_b-K_ko4q3CKM~G}B3HVp08gC$KuhzKoa! zky6gV^>wGNbqqy<7`t29w>n2or8ruW134f?H^k}HCg>?2QD==lu|mfY&$c&bglQ^; z0qFRbr)fo*HDhEmqsHhGFuBaciC}sbWVQdZGCx(!k;jdVaKmt&)J$T4*2%QP1Q==-cDCnxlriQD=h-ToZz;PdqzpJqv^Bw>X@+s`f3E-|_orlw$uFX*Qp)_CE@4be`0mKL z&h3&3s2F2fY1K3I1MdWCsx;MxZ|GdUs{GTaakx z@xem(^24YX9W@F$^Q9xx(lE*F@*y8xZqp*fDi0gsipAbS_fM~+GPMVEX?1F4EvO6I zjwgI#beYNh2XuPY!s6sY@fb~_HfE>1l$WsAZSSce1iBp}!Vizw>9P1_*dHo-P}ZUy z%5C8lePdpg-6f#@xPY0C-baygsiGc~0g$|UOpbM>TwXpql})?~aY!~@$2Ap?4}^m2 zuDQI3UeckZVc*r^Bik$#jjg4LDe>2i4a5}Z{O{GA+_J(`*9j@gvv);K9sbdH3>hTYyHM3UO^Z7#)(tb3cj?58-54_sngG~Qh6 zRYr9?lU&o@O-X6scEe(b;I+?kKVn_xo-AR#He1NK9vl_YF}1d`1&r`)qG&fK>g<8+ zao%;JAgu*hWs*Np>C4hMiN%QSQ^!9mce;5b-fr5W?`8LcC4(;qGc0@pg%n~tBRGdp zcW)WoRUC9OcE;9i$$jZJMF$wQSUKHf&lJKr>)T!$n?WTDmTf&=59}BR5JRGo;zXlV zWGE~GPBDoZFU^q&&FPZ+y@Y~2U)giy^B!qLfvJY9rQ3+Klrg_ySk-3Lou!Lg3AF?9+6l;}C8;s+3Rv-T82S-;_>8Vy z_@E>H{xmfwn90XxU2tA6##M7SUr?X>NJW5JS>UI0*ZgRTJUjPkF^eoP&^+_XYSWj3 z65Z-8dH_-%-3|=+-T@1v*>TaI-H6wAeEwdNcf4@616gy8_bU{aMVEXbe_AV+VD66) zAc&UE9pBYd3`mdes==O*=NtyO&1R=SsEmnBtPLKi7T180)SeY=P3<|lFL8p52&v~M zpW~LB4|^nC$Xu!f=no|}x0A}p3mZ*c*ZfrtMcrl(+ylZ6{A;wyJCJ$>)DT?`%*zlL zXHHFtQ@o3h-30F>8oHrbr@b!!7s>48i0}u_D%f zgJ3*(1FX*+HLa2TbQjZv-e{c4@(C?fQ#p-lzlDdHp+b zq5Y5)GEVhN8R-m;4)#!SnWTxZ8j;rdkW|zCgpNBA!mGc!JH`~VIxYgAKe8XPV>mej zax%d@e2|S)z^K>)Ea@KiDxT(U4Ofv?+@ph)B@1-4dA%f$xxbQ(p;ng$O3bP)uhx43 ze{x7Qbb?pSG_{VB4zHW)scQlQ2h&~%lQ2CxAQNR2b{#&6ew}Qn3bwPMk|@F#!`>;x zq%=fU6}%rUy~B+!-q|PCYhDX;hj7`2Oogdsk32Er$qHdzhO(PIuPi z8dsPp#+csu|FY>3)MJ-)cCebkvYc8H78UqPQ%rrEYNj~FZjcK<*6>B*s&R==4+EDnP#F+C`&QS(- zSeIDAq^QUx3KsBP17&Jes93jT)v+FnIRz^qC`+U<-ui=RJmEDq7?w?>H>{cOBJU@p z=6rVX(*)FtWGgB@b|~MGx3aRv!X^bh)vT8WTQrnJujq78Eu{83eTzVq8*JxWH;T80 z6kDw*`7?zRP%tj|ef@b`1qyJEKvv~AForQOzrZTZMg%+wAKLcyWo@pCSlI{@w4Rs^ zoqmz4`sgi5Pjsic;9d2WYk+NAQWExILEuz-ISq5*11po(O z$*7lF07&S6yLFddVgi8o1`EO}*AsZ!Y4sOhah&TBoq=?Ey&qBS{qodSD^3md17JMW zJ-$xdNR@aMAxN5S#%q+LMpGQOqu&Z(h!oHAsslX5F!$zZQof-m{i=6UpwKi?+@w4z z`qm8dj1e{q*>2a$F|cHik5BfU@#sMBQX5?iSrz&hs+SBc@quc}XBDcWcKDtysJ_7j zK}klRwdjA0H)dL_7l&o?u3d5Jp&i^r9BV4{242PlQp zqJ1j~HUIN~?91JuWS;_H8*)yMl_O+jXvJ5Cy>jl&XbeTon)7^NFP@&p^AJI3*x(M0tfh?ykYsJg4|~7IJLLN;hlJ$hYDhlEYI7%S1V-VkZNDPJgw?y3>XpuALqd_gjn&Q zIWHLGNw0=&*PeA|qC)jsipm1vf>j-rhCBGjA5NI=Y3oF{3^Fn&5{Qw2;^GmW}b2dQgAjTNqKxbZ?&^rzF z0EbU9*y76u2_`q>W*um5;@uyx^3IIyKpdcqDW$cjpgPH z4hv}%-4byGKr;n21H9<$jXE~Bzi_5VAO~bnX(1*vT^O?WnTu-`OI|nq^H88!urf(> zWQY(g{aH?X8Z}dpl34mB2{N?7q*$#K-HFdRkuVSFT1=6?hQ|@RVs>$ux$zbclKDp~ znFpppgq1ldjxplIF*40CzXJsz64zO^mzy%+n~dL{KyYc=ilX5(V4(AhHt;6+2F2W_ zQhnN$DNIvBC(N<;EO&3`W7`9m%>Az)tlTR)%bL*(xvg;+5}Wnx2R1TLU+f3&#I>+l zyUI4P2M^dF%F$bSk3-q;bRPU9bjeW!-J7uKS7Emvj@7Wwq)i~}KtI2kGw)oi3I6QgKaC8QZl6`pGQ@AqDX zKJds|-`uYCe*wSEJI81TeqHBB_MB)4O+s`|91h=o>$Si~*&zGw05=Oe7Pm~r`f7QJ zV4UbxvA99F3_G;}U2W`N(Jkul<^}01immE`3Qw_Uo%+} z!)wWmUlMF02o`rYuntUO`A~?uL1=R66y>ly`L*p2jRpjU?D;mFW^2 zMd^N@ZZv0m055g-(1JIxw#yb}r@F{0-zX3P!!0x*AP@CN_9%^H>L>e+O+0lKZ2%z> z!4W%;eQ*hIuW>HN{M)=rADbNEhndSVFrQ-_)pr<~h3^1{GAX-Okn$j@P(E0R{%*?; zkw3XLeyC_biLsTvO|cIA+>a16@_R+&J3gOQoJgw&a+~ETELz4hDu^_2l73a($(&x) z<(vupdt8DU7&A?~vMdjhFhkAw!|iC;9|vrmvzitzI7mzY;405d1$<`!2?7G5T<3?X z{bfzLg=4G#Tg^vqHu`3iF#Y-PW`_tAxdkVc8dwEvfQJLBjea|-> zuGU}U+Osdk2XC|OlPt)*zpP^qPvxM#OZu0FXlIKn4ZL%3CNH~a8AzM9TtDI!~3O%VSU ztQQX~tG2y-D4P06^y6+(YJp-t4|^M*4ogSh&QXmQLd=0%1}$joc?eo<22*9?%N*xI zgZRERVerg&y!B29Ur@jj0aiHM60H!fFKT^!FJa^}&rM~OO`)J&!r%Tn?KtcYj6%NY#~e<|IqaAR3yR_% z?H}a?l-{XGq1$yg7kWIfzBLHHI;KLmU@N+Tp3t_6OvAEnXvwBD6DkUryA0;+Z$fzr zP}GzM*v~VO1K%wU;ZU?7;Upzm@k9xcM+bCCwUR{&vzG%h-cKlO2S{unAvRVv#UvcO zIG@V8HwVr(_jVA7J}bl3!r4Zj>+?u6{ILb6xb>ei8N+OTQLKq6q{(-rl8pN(vb=jg z1Xd4qhfp0?KoSZaoJzAKE&;Cx%`ct!z(^*6gQ$U}WGcu+2XoPxkJqg2kw!f^`9)x7+1LQb(1!7_unzimmy z^H7OaCvS11`av~uJj?-QOI{zilu>qf{?_K$QSjWJ^X>?qjlkH_QqPKvl1i!RZml9< z5`Y`~TP+1Q!2(h$-uI|;+2Qq%ZrDo&dV1cH0sK7eRjz==86%NQt)fuV47;CP)7to9 zx;)8YS~6&>kKn^4J3`=`cAhpiZJAkFdMG}fCRJ3j4*jo*_EGmaWc6lQ24DI~^NpEK z@7_tJ3V?WRe0?r~{mv&9Z^w#V$?V#f_qY2}1%c`BA!>zsIc71HK&&jsyKkCTR_Fy# z(*afz&=ur?(XoDQS>WZp_#y293rfj4$7-pE_bNbV;14w#EQaoM63P4Dmv)B3yB4Jd z*@;lDYCzljCTnIfWn4?csdpnFgiDVL^S3aEu=jn5?o`sY6=FutI095@ z1*9C_krIp_?75&dIe7-2lQdi}cibIStByj1ND&K5dJe~f$a;;r=c!_)i7f#te9A=X z@T~0`Cy3tDu?)4`ejvyRL5%b-Q@(?WOS~HpXx)srJrJ8q{0(MuEz5;VFB&>*WlO0d z(2Hwc{C{6eGa0AkMLVa^Ded@FwP?|W|&! z##q}|K2RH5;3-DPhYB;ixjjG6xWLu;FOW!!5W_(30wT)T6`B)4=#UQ7Nqc1I*Sz97 zgK&PhdPb#$sQ5}U3S1Xe)D;cCv?t3NGfJn5|KJU+Cu=2PNV&Lvo#SH>$dR@7yna22 zb-qR1;ICSakm8#sK}6fo3|qyh4P4yl_8Ygiq-vTtsTwm+bwag1{-g{A@tUZ3Rh~|Y zem0@X2A21oDSNe?WGR?UD;)baz}eCb0s90%vEd+FAG5S4@Mt3l-A%@BYui`Ad%$pE ztA;>Wm3%Ht>}^XR;YS4fhHAxOD9?;xZ+}NG_xs&9MT;8PE|UT1>W$u2Jwy&puoDcO5mP5EIK)?RsOjmqr4%g{;dxeeE~!{9e#+qHV?g3DA# z_dLh7qjv;c$xM0s(RjSX+XGAyYM*15 z%LmP>W5+@q;#9ki{^T$9IaS6n!J>@wV7wg3_J{zRB14P%UJltz#`117%<@PDqOsR& zHu7v5Yqu1mR>Frbh#m>A3#%*XUp{VfBJCAaCew$Xf|>;Z@g~WYXc2rw;6s^#wwYT@ zF=rC@BUIlil(lO8Nv`&;kgh{Ip6b~Z7+bvWd%?J!o(-mf2{<{#e?SGi<{|V$c?kX= zN*qzSB!<^fcc1Yn_NI^?umH1i5$ZtT*QTwG1&sQ6IZgek26%(nMVIjz;hBr=QH3;P zx_>c+iJNW$L#&HKHF|Y8!oqYwnHO;QDNYeJUCz(!C|dCtQZ@I;xoLvp zoWBgPnYv6FQw0aI4Jv~*hfqJw4k91^4Oh1cfBV9HnuPa~5U*+~QdW}?| z6jp-leieIyk|?G@-j|%;3qbOZ0yEf^3@vW!TX+0=zc zyevbp#H&zVn<(&2(n`NAWjlU)PwRzmI!^eoLjWn3o7F9q1DUPay!hN)K59GInXNQw8i zot_^aK}{-4!`L)(UeEVS^7$uob)yDZD0>M1^569EW+ z(zEx+i%36F=~e;d!2u1+C})pBE<*msrDmMKvPwIl{m}fHK2K=?Vgz6AaCgI>3MxKT zJbN0S!9^RA3TN1K_!%rA6;QMyymRZ|rPcvNRW#*(x5%V8^sODHWHc`7SXv=ISg9f! zUDS3v3+}9dxs_f|N?sl>SY((RCdli25Iuh%mc_6XqaeGd z_KHX=fT*B{sFx&{pOq-;lzq37gz_g6LVvu*Pgw^PZzc1G7!RnEJFo1ZJ1_gC^n}D! z{lRBosr_bf%Y(ylO4VhqSmXX}!6WYcFN4T0ZL54_{~L2>F2rr#RcqFJLjYaoZYRed z8@$;Uk~kp72^~4qIM>&Jb-4TvP0NIcQ1j%FY4|6#hpcqSH!TuKgDk`)5rq6Q!IW=@ zYb!ecp!Sc@-cWv9@+d~Rb%da(2v>tSxvQL4I>U*X>=GrwXb&1@x3x_k@6C+uPJki` zW_>vh7sl2xCx(sBmcC(m=(F66GO^ij;+JVA(qYy3Hs?h5x?CG}CUxSOpUo@%m7N+a zXMCgs_Gu<)Pv@}G@@3rd9mY!gi&A8@Gbmn#iD727e;$bJ-jb8c$o+#=BkhJThDv+N z)JZ__%OB@lMLpzEuT^K9ORDuTAM6l8QK600)zGd(JS9lPz7Cp8!hsj`sZL}i>vm6{SlYEt3&^qs7ai3CrZoVzA=7|3LvAQ z?B+^l(uTT(KXkG%>)Nz~4)R$AzntRT|F0;+1FU8E-i zAN9)V3hjA}b z+*)Crz*9Z>c1LSk*A($L{BSB5G0vU1kd2OVEsRe+2MNz!6O)#KWv8sk91A#Q!WuOQH47Q8uR7gm ztd2sdDqOfKQx%EL4p|~1#b=Btd_1xF^=9w}2`O&~VaGj|L|Z{WG(6|34zr`b`Dz!| z&2#_|!YiCpY(lP84{vGB-B}lxb8B9EC@ld0V5{L)>8_p&-V&43r(&@|ndjsfy$9R} z$Se^Nxsp1WFr6Z*@N&dpcr4h@3ncfmm}5(G?1qX`ZTt7ElBUI@CLk227I2O*G5Avi zI^Ew{NH+K&>A!8&MXG(8QHVmfnk%l9IX#lKl2Tbd-_M;axe8^L!tOmm@U-Zya3vcU ziov^&lo`#qE7&f-bARb;|A;I2MelPY%%a*3a=8H@R|(V;=Z8c91)Xp!2Sps(RF;(> zybl1%e}0F9YZ3Zr2p^nVh9P)Z;GG4T&_?+e5y;8T)KUy*uDs0%E`>F-wOy!o zcB`aUq>qz@hb$nTGp?`&IEv!E>zsl|b}wUJj>vdIn>8~$96x8uZ6D6+p9fnVxE~So zn^XYz_g6gI3F z@#Cg823k+3WJwrBIJL@fv{4?>O;p(8oYSI}-eU zosOWjun=%`F!xWFlXG(_hc;zPdxRvlPOBWMbp0V!PUQj5o1RLFZ?=H}Oab%yuI$It zF4N7~sd+2#A5#2ca^`r10i3;*kEL2_QF2W=Tfr}T#S2YNp*dMWLCeV{!eTxkg3ymI zKIcJy1#ur6X${?S@ko=!=a=H9G2L@wmFp2=^x4$d79thHPRC~SQyP%Kh5KrQF}rRg z0}MoJ#3gE!KR!Ps@S;ms=ixD)EMaIXE1?lSBUk0vZ-xJvrqcHkGjeZ>4^f*Z&(s?Q=}qiK@py zt#j}&b#RFl>aM@MsndRkDWJtdSz0pMb8D4NWXWNw+)}(%pnS=7lk8v;N$1*5chA(ik2M`W z=!4_5MW`PJv3e$pO-c2OzN5j^^LXwq`naw_;!6kXwz8L3#GowbhNGj|UjRT+3Sr6{ zoP}L`-J?VC@IbI2tN=HM7{McfCbK86^I<7Xj@^Wvid(=}pO}~@mwi`>O zIb;Gs#B^Pj;!P)pZ4XE>DV`_nh{zfjGwP2K?xbi!P;g`|mun%Wfe8r-WW_=Eiqjxg z0o0T8gmNPaS4k#tHq$5k+|lRQ3r(l*6rldDmY_fpVZDef--UrSsz@L953#W(3@&!g z9=Sm)*alBE&b9(I0xi%c`|rPPmMj8f7=HwtUXl~XclI5qVl~1bwV~JP`f@`S?pI4v z7diw~lpA(XChmh)5(&kLb zP(Jegch-wC>9SDPArg+1-yz=o2pRA+8PB}nu{M5PStuVeGSEHnW{M#yuj@R*+?Dw`TS_of(7IK{EV-$5 zze=;IR}~kuRE%n+dbn!yK6r-y574_=?5fR*&Q6Z&P z9qdozX^p`QL69o^Xn756K~O7czPxpJ<@=7*L_*%X(RF!(&|K5X9<|jj-#IhFjkN00000000000001tUfG#gPNdr}2Ky5cF3vHM zrV7P)7DM9ICQE|v_CCs_PbxD&ByRO(uh1SP!^g%C1f4puRdRV>>Eejdg>ec0TK7m4 z^=7<@hmMnI0AINu-RdtUJX}o=XqdswBAm2M+kTMIiT8@-=f4T0da;pHPDp?|bb-LB zN1)xfhUd?srfWTWcNmUclgzGVYKfr&@gfdx8zEqAcT-4eBnf1{tK+hFGidYaO165~ zj+t9_HK1OJMjxopsz45T8K_sOU! z-vXZw&hk^!H1*gUG}*3ut8%E3ePHrzVey68cNM9Lvc8~r>kD12AJ6W;Azd#uXImtQUZ~Es)QPQ#YYyJ#dR$QTF7%bNuG+9JO#aVYxG2ldX1CX0QL@DW>OBPT+IBv< z^6T}NlO9YRN_^gh%7}SHc*oyv4CBT231ZiM;{+0Vty~ZpPLIyz%M|DiHMci?F~@=) zFqf`FmXv?E^|a3yvI-ng-w!DRr>#s51*f!us?Vl`nkdNnk*qJDiRCv0DkiM+g-(8c zQ6`!f-Q~k@45YR>)lCtDR%Ro-(;pXSVlkLA!u`suRaH4zL+{hy?)0zM*Q!dkE zWCLnKl9u|D@|#c>YKb?mJ?&h;74P3>oEhNlG{2$V*maHS{*LxmOSqW~efA2ysM>k>ym`ipThTuRE)jmq4#Mb5K%o>m9F zq=$FH+58l#yW&e(B2ezkaMxeiuH#T?%5L+-Yx9RmA9(GZ=HHU~C>dp%RTPa#pm8NT ztglNMgp*iGVCp>h+{O5Lh8N0IZlk;So~RUUGhSq0v!)+*D9!Ou_19JU+}!nvXM+ER zVq}l63Z$kt=$|pTG-(iu2t}?XdLct3K(uIEb8(AMT~VRqI|N##q0C;zY!bdsl9Fl0 z-Mmv;X+oX9HoQ4BOg0ytsrpnPj&@k;@e~qmfmD%=GgeZ(P`eisD|&~BO06S6r1M!;#%8myQ3Xy3_UC~;%S4MH_AU|f zI4M_rgdwpr=W?l|klQ^BJjL5{G&A#|&fX7FDLG^!sxD=#+q(m=FZaxaeR3ECr2NfH zzoH{nCZ=hto)A&wS8>Svgx6%nwGTKLSmT(*M*az=Em5^GZg^7@T5ipWLMB0o#o`xf zmk>LbBLN}%g^W%KJU+bxO)Hkn0G885X1A9X(eXbsU zhc1|8m5bbSy|Z@!*HGr?4}@_eAl=irB>VITel0QgwpqW;Fn%V zzRs|V4|sdbM{fH3p;B8IjUlQUQ@^_R9tFoCNjD`6(CH%m8{pe89)RP11-dT4A|=D_ z706%5+IV5p0=WgtGv{~k!JV)dBM@fjts*?>jlF%C2Auwl#NR`MxQnkL=nfw9OCvw`RbjN=2lgUV?E=!c9P=I*cYWKrYgF z0k`#=%C2zZHWip#ft$F65VSvOJ0B!ySA4e9iHioeuE1^$jcfGpZ}V4jDWhaL1DNZf zUj^pe2rMhs!U6T}X=_(^Ye222Rj;p7c)a>xhD!SnceXc=2wAG}5HmK=!8a(!j+ z)g?jo=R~(pbkl35`yj&pwX6j7FkaBV5lV!h*#>GBc)Ta9o({0IikFF^DnRuk(Yf#JZm_6(l<>b6Dh8qz$TThmTm)s-E!eoG7%^ zGE1&8x()-=4*~)9FjtGSj}II3FX50{|Du=Np2hBR6)joxs=3hiu+RN;K(*Z_1_gfK z%&|yL)8l@=oI7aaTUiT&Gn%~Cm+nzcWyRhQwKi&z-RHNUnxxtHv=uIk@E#a;iN;eo zep=N!NAY|bj+z+SrYP;iM$WripVDf;h)Zee*-58z@;|V9hj)VGx4)+y#1eeG8_YrRLrBEYr zJezlY4SLsG)&&yvotVE3gb{&Xev2fHuJ0&AukafSz>&#-Rx47+Vr>_T(t;rZzZmvk z<5I`CR8`1-NYJzmGCDEMHp61T|1Tn+;RBt0=dce`?S%Rdzs=g zifu;4B1ie#@b}@C>*NJhuu6#q<(S?l5_DWMpv;T<&A}p7l#Y)CGgFDb+;~1`E%((+ z(Pwx;c#=ucLiz|(4aoM}-eFPHQ9K}41i?Lbr zSY!bDfvxv=<4dVCN17!N8*#$=|A8tRdCs=`o`#FvLP@>x7J-9+R>E`uVH7bV(wkY6 z_F8tpRl&^&zzxah)>H()ni^?sL^;z}ecdWETWfg%ex|<~uXC3UBpt82e#t-McaxCH z@|ynWau>f?{3DG(0>E!q)em5G35lKKStJZsrAk8?b;8X;3uv9eG#_j(AnRD}4(FfClj)`v8s1ODKW^Y5C(MQc?xr(u}_r})~2qRwa7JkDEDgp5hxL5g{{`i(6l)(e0le%h0{@LIIv5E%r-A>C(CW>Gs!nPf*z1 zgSAo=>HNUj(Q$Tv9v_5dFa1M>`v>k1P6g=-87o$|SJp^M8w*k!Tt;T{xOyBK!m_`` z!!T9Gy@rtH7=;eRJSE%2N))r?G|Ys72J{tdQsSPvPqW9ui*fp#B@r^!G1FDb;?Jb< zQ5>2ZYR1fFstm9?wVEqW;O0XK@I=jZ?KavhvK_~RtRDbAA8(Yp=SWK+Y_fWOe*urN z-QY({M6@!SGLX2HPL`X42QjA3`j}#FG03XYCh+4a&Km-DtycKn;GP#@OI!v{*hork zDIHB#1NXjJXF`vKEZ{}mB(h-uE0yEB#N|#kw^~ecrUD?@2h6pmo>%mhcIu3l=xZEm zNtT^LYfUitop=#EJ)1zrw=O7WgI#m$Oz@0U13*!*XrJODv|jS66q$-Nc0ry|*Y2yo z6eRs$Ay~}~)l?SN!DXfz3WR~)jJ+lejN7Se2XFxvt-P)eOFX5bYeSQD1zqBb5UW4BG+#XV#1H`L&+ba`lIYW>IJy3g9u+0 zv9Sn7J@X_VvV7-i&8Yq94$ipNHpFv-Fc=gF2eBo)08eT-*MqM^^X1EcI)2yqXKdcy zanh20^l9ho7COdR8rEUf+l$zUi;}GJ4Uz+t(GR{VJw042Ur)UP*F9&$1>B5>&N`ej znUc}>hszM}Vt`@D0s?4Q9V1R}&4&e&S9UC)6oc@CXe_BmXpR0c`^9Tg#y6&T3BWKg z)t{opc`z}lgIhDGMQe#OUa)J)i_)ZQPwNv1al_El5Q?h_c2yX}yg{b8i|xy(-s`}5 zkFF;{Y>as-h6wa+a!eH_dh|JlU-R#5$M@6=$k_Sb5-1FmeM^>YB>q5Iil3oacdnJ- zneQ-->G=7X#HJe>(4UWsNn^phpuv;wBVkB9irRJS#jQ#7g-K+@Oe3%nO;W7Hahoho zWR3=ryDrQNw{jvchk)-<_|{6NaOYQ(95nodnJXftH}cyh%$EyhQ)KR%3d9Kq@N1r8 zc;32&rYj89#afyh%8P9=%ZskeRE~C6_KJJq+Mcn!4;^h1(28%?85t#INTpSZVdAMTGwziqb(jtuHy77jT6OvOSq8rtm{=V8zWLbKpBhe*G0dZ)YryImaccH@p>TBj`9pNNQg&j zgZ>ow{SJstByGBRu!Z;H$howQh)mH`#3sKJS|NYeIAKU}KUH~$MF853_A&47HQn{q zi~}igA`E#q$D4CRDkljb+k4UPKoBfYVt_OU827&TyN^^w5eKF54Zi06qd_Hc*9^Bf zU9dPcu78u0aQxlQVVF``e!g>lRNf@}3qY;jD-qhpH74y-Vd6q=&TCqDHYz21lLAXY zOLCFpf=FqT3+LO3_kpn@A8X!W5!*QRze%4`)V)MWaxyP-taqXPQ={;TsQjp#ft@`7ut&hsDSw54|U1%_HOa>FS5o&ptmkre)BTn&y zKoo=2%x3v$C%IZ#sWWk!Q-`|4i(yVTpgTl@I-M}W0yqldnK1y=WLM1YKcSEo61ddxUy*p@pRVvlWr-s!Ly-eQva_QajyHab6O`+@2cq3INn&jDlf)7%-7d zLn~MonpzNSZh3GL#a7-|qN91xL}qnX$I2swooCop%Hww7blZMG7#~ojg$8zC_5?EB zS27DRFF8U>r3D!SL#(N5nffZJ=4c*i)~VMlh=XaI0=Os`SG4#t>522}P>+H{({fz4 za8QrDpd^0H`=i@aegs*(JO!YplrrcA76)X*dO`;u@(g8gtFaafbib}XFp_h*3kQzX z%q~h41$i7d&7DL>NO$1~p3plmvCBkyz4N!+VzpIWL3es5#`E8OGqjOxfh6G3(L4NF zxm{R(1{IH2N#K6h)ZM}Lg$|+b7^?!tBUNu4H>Ct3Gx9gvB2f1<{rl8P(^`D)pW8ra z1ICf?KqFqi$5#7y1nE*D9AamHfC#O!bSF%g1wCbSQeUfmn_JY2U?u$aI2zG)Nlfs8 z9a>>xj-|VaXR^EwOGGYiLyGPl>eg*WxG%kT1&Z=Z=C8BS^%Jt_Gf0*SG#@W z#|aaPTIrq&Mz_*)20~QxFWx?nHHoilS77&z`76lL%__l^;@)M{s01lrQf`P_vA@4q zx#jpH`3}v`3)1v$u<~RHnX8soCG@QBpkjj3g$itDpyzVb;oU}aN|7{9qZXqW1ZN5L zq#`J9qR!4s;OYI*hZ%Mo8zp!aw;Dn6R86k!)QctFcM-9M=fwueiNNU2s3>rwb;QD6 zjU3jRkX@6*J#)43u{Os*wDx*K1h-@1qbU`^l9c_uf_P@K6XaXz*E=LPJc56B^Q zQRny(#h0a`S1zyJ>7(#x7>g>3GoAJF=#rlqZ|ea6e!UOnq9zeGF#+pLP<>75S^OoP zzjID3Kvq4?+KHc`_*W8e!`*#CBiJ5{kw-Y=?GcHIOX*_3e-Ljw{)8P@_6To+%lHX` zH{`k`vx8$x`(2Edrk3n50%)1CD8__?<5K8`KzuItMTC@FO*TeXu zu~q1f$po={xjJY4!Sg#DmKc}kQq41*-*}N6DCUNr#KkN!jKzE5>`ws58@mSncN3eF! ztZKgrJv^mXFXn%J8@5tmfoe}dk)UXG89Gz@b&1YfOJ2P?{FYFn2`l6t5>2K%zo$LO z5c2-y+TLVwE<9)@O5MtyKJQ()%_px~v+B+~hZ&-&1vo>uQC z37fJ@^ye0_MZg9-z6C#lo#k1STL8r2qrDw2RY z4q%9v>WS;;?6H=#Dd%TSilS3y>!9?(c@KRtCA1(GLc2CR0NKTNapZYrx$$wxTQpB( zS%p~ym<#+U1?Kr`ZJScQQht`_x@`&cV)3%_tWYSBNhzqs`Uo5Pk>}ti&8^s(Wn-YT zAZ>ZJyYgy@qM=x<3*umm53p+*E7as`IJ`7&5K75fXAf_jqSynmiS~p%0!PdeqH|M@ zJ|v~uUyMiUaKraZ+!zBgInb(Sv9?HCd0+ZW zNFTrB7LGC8Kv@DASL2rVdN0^Zypyi&?eX`?09S23a<4Rj)wW3_#zek4yHf2X+}~5EV;NGoeNs+Safw|R40{q zBJgTzdF!5l%Nq4Qb6;0_v48gx77CdzYrOE%@Ht&-CLKtu(!bp#XO@qjjx?5vuQ-31P?>2ir-}Xy7JEoMv!#_o zu6cT2(wH`Cg)H2ro)(YG_52fQZSSZWbsPwlzl+%*YCH3r1IupF9v3vr>3OI-Ow<3# zn`qXE5?L-)Kh8hjS$dizCE0*dk9ml(`bQ}zIu0klp-R54WPlr{`5GkZ@3=w@m{9N0 zJQ>k@=tc@ra`v1RRc~%G{dDaD2Pa2y7wx|d;k#~r6c5Y9M)~o$S|4wY9gmjx)20+N z%-rBy6nTXh&m++ypvxQ;33b7$`MS-h;P{+lQ}-%jO{SL%Wgsa{@o(-S2QgpFz%f0Z zST)ZKb2aS`Y7H13mNk#2r#TKWGDkQYsbCk@{*<>kqM&{s5t^Cr@2z9UgYF0z7VIg2 zBkJHIjKr%jN1-gJl?0=%Qsy7kyJgE?yHK)tzVzU zJW<@Xfsrt`@@|C@-1w#`Kmn$-i1HhQDg*7EIzPMmO7WlP1Cs3jM|O>Lw5XZ`Gg9(# z4W!c<1H>ZEzB|3N^-vks^tFc z!>f>lyk3>gwz+>$E}kH?Y5e@rLY6xx>^bhmx*M93t~nj742iVV>Lgk!fdOJ+iC0WB z;BQzmVHxw|{=Q|EiXXwy7lKNYPZOsO|6k*wmG$;N$<$RAO{=|pBN%~SQSTE`uD(LV%%fBn+nCj(a9igpA>UdwcR^TdhlPsTn7O0#-H7A~nJ<`56~_d<9p8X5^&&3AwJ7Xfvj+A}cF- zkpeB45DitZEN+9T60{lMP_|;4Um8|q02!vA<y|LaW65#d)S_6R(|_6Ei}EMcQ6;7Y6{vEK^)@Q@ zj(}eyPkqJ(S7j$M=pFd3(v%$hAK4niwtQF@IVlzTfOxvfVFYpK^zfic!6& zRfZg>T8Rdvy>{C*rmbaLf@q+)>{IfeenuQXh3QBUb_?sIM7>MtEKy8X3p+Z^+E2uz zJyAavoPLAI_Kl`@o0HjVR=PD(I`wiqTXW58n=)O?z_#L*94X`4~I>908N zD!AzR93DP!e0SP%BE6MIs{eCi>RG)ISiRCnqq+AuX(jB?u#y)CM<1Y>D++b+PCnJOj&CE z?-(K~x&bJ)w;!%)$=9JiS`<_mi2^~%_>CB5qwWtVAd)|JDn5e_`wV6=#2i@N=g)bE z7yrlH;w)spJLIng96>k~4()Y6q(0r_#+(VO=kJd6Wk^Z;i?%`mF)53%-0{C)sqUu&WN`(9ab%ie&AzMHd*Sr5y7dDPfu0 z|Lr~{(O%7ivPWSkpkLx1X1GypOVcN`>7$@Dn-Et*Y!(V(y7uL^EI)7d*Z!O)#RyMa zte^IRrMANY*nBTRP{RPizM28$e|>n+$c2)J79P|T*BVgi9gQWHHO3})r(lOh~L2jYbBsf_w73W zGXt-VnuY^_$J=SC8{6dA$#guohzT4Pz(9H5#~%7jR!Yh#bi;ZjNd>OXb}PkI&kd)R zv%QsTdM+u5LUs=9Q=?_5`CGXSTqJ;oJbqJcu+xNZ^&Ub7?CIem;$xox_&NUHQ~=y> zg||*~=g2~gn^V;fd!@Z~uze6&tR|#BG0eKTb2_IrbQ8@_vS{p1z8P(9!Dfwwbu(FT zhiW$1b|+BnD;p`e>HTa;iCAy~jAIga2hShzxMWG3SG(7|oxAT)ua@wzgQYCtAA}=` zipz!PcbL7%>%xpbE^h2zf=J8Fsurz>KY*-y6Qy)bEP(ZVr1nXGcaEALECneXc7jCT z1ttqtM=xSP$;Npfl2i_fuv$-Ddd(o4FHRIu~$Pw|JKRW5#SnO!`$EJg_}v(kKY76 zANEKKUeb?~eQwG>D38HTM7EZxnFPvTxTkW5xp2Wz|1VF{RAUo-tmo5eE2L4rMCb`) z&axMvq!J+6B?m3%?R|?+tl#6}Zln^3!`~nzdN1(BLX*XqEX`KhG$vzNq~!DX+3Y|v z$a;|Hz9~Jn5-De50&DhA(BnZVi3POJUR||vy;}d7rNH3L2;Syy66^-w+T8W$2E&JA zYF^1ZBoyTaQ2a+2ct{v5XdxjQwi|@&5RQ{~aqI&=eMcy`>MUEux`<#hq%d50{vFE! zfH$x?Re+uCsWlO6H!yiof)}z@XvoI#+wOkLHJf-qwvCCeX5A*UonAf7VX8j^q3}MG z8^;hueO|lBFi(ZiN^EhJ7u7i0%podNySY}{A5&yL;peFt`e=pRUgxYUb`H@&CV>Kl zzC>bj-%keNeURY_GyZar&7iBW0SS%tV&4S0$YuUBzi;c1%n+-G;qs2J1qa6niRqM@ zRsP}6iZD;M1Lsj6)7oWUFygIXO)^rE70MGo7#c~D#oB(hD=`$W%3&PAbvU~sQ7iOb zVIKs4E7pu1?sY$|V6IqJdI9awfB(@nK%^`jL`AU^qJ2orQeI14ZB8IHvb_nkU*Pi~ zMRfOWdtSBLo?My9iPw*mEeRqSksZU9Z+j7@*+zC1r18vwo)K$aNG!iakRq-PEYX0C zMzhRdbwpNfOfSGzQ;oSU4RBS6+5w5D>{YW8;We$W`GCHAA-SvTyhGak$$spQqZYeQ z6~Q8A)dHP{kf}zNjdUOquGu@d{}Ey8(Ue6%Khm=-S?t&=ME58LWNw^&jP~?phPV}A z&V*-5bVlu_m^KIZnj0|jv^$>&JoX^J(=o~7)W3nr-RT)tv%dNp{LzF_#XQYlaj1Uc zrB0x{MD*H5(u-ZXf&;Q7n`^!p^Cz{TK4*VChO%Eq|MPHOi4Bl6L^S?n(!$kGe~?8vETu12lZ;Fn*6xfItEE@JxdKItT#h}c%?E_T7Sc?< zuN#uJ9R(T3{3Sa6ph`4UnA53RcLoZrZ~zdhw{UoVhhRxj}qw?n9z$4 zpD|wGybVwKyWU&sZ!*6#&#tSwfb+K_}h>kt~%cniB-ch z8@^wGQPdF$%`XsP*eFvDYkJbd!-%kCpV~qj$OH#^0eE|g0Q6y#r+4gFCI4EKcLF(E z`Q~gP6E$K_?lCKz8h2ey$b2H~T>APZ)c32@bBsEIZE-0F`E$8W0k$jYW}Eb@26fz` z%ar4%gQoU~(YIux1$j}ogh)%?`N0ER(&dL?Wf66$bom`R5qfOxYD2>WT=l-EQ72cS za;6MxO^xrG2g0?o-(8_Qoc|A!wfo`7n^JXsX*lVoVG5O*JGIlPC4#ALTH{DlQxxk8 z7iK2fU-#nt!O5!I54*+-3PCi`6Xwc^G_-Ky8@pGij6co5)ju)h8GqL}&Sw2m-d*BV zF;Nqgx)E&90f>>n*ZDW-+Ss_*s0)7rn2iEVr1xWmGuQ~m*nn0}UMgi{R|1fsR%QuA z!7#gAyv-;Xz4pD;R=iEX;y#6h{+OcA)O+@HzhL)3CyHVIJ-i5(D)=$DaYJ=;(S4rBM=X_~E--V=!d0|GoE zSM8S!zCBV%PmW7rgD}M`wN7uO_T*XNHVv|6g(HYIU?2%8h#s7@n#Id8k z;ak)EHtMVbLp9LE8rOWwABT4Bxq2aZ$8ZOQ-b%lLiEmB8fLiklLXQm?jqTIG$oZRE}YYCKQ79n*M@Cem*7%|6O53F zoT=;V|Fij|Nqh|gvW~AxnThhD)3SL*fxX)^thQ$n$*u?NIuwjU4bekX)F>1Anj(>Q zn7*)vZ2;))PD9NjHYdY4W{)f!9DeMBGBzDwtzXW&uGkN5BepRGLeY(NfzMA+XWf;2 zSb7iobDyYty^PT!$(-HIA+PMzF&D$*`BjdS`VB!j8e3SERzPk{=x= zPmKhF@U;t3{wUcwU_SU%%)^+Uq8gvcHAE|2dPB5g5GXb39P19A^6=*~;^J5;EO&0& zCuVwdtvHQ5$E~xor(q@TK4Wp7p4Y)DScSt~!gn=2zgMdq^b8&5vM|J{8Unz*?*K6t zy_SG`APLj2bMPI&oU(qZG}wS_?W@`));MX_qz!~n-7clHL~njOixK7tU?9A+%c}1@ zU^&-lgp#2r)pq2Rb*rA_+xzcA7(HzCFQL|}RKCs5ao~!Zn@Csl4wzk>TOrlZA*DCW zNa9?KJV2&W!F}_Z-NGuF{~{!?t59W10lH}bbF?JyE0&B4i%AQr=Ft$>v7$d@(OAH` zK_k7u2b9x>-n$Q<9~1xT>YKv_>JS-sKuWy2f2QE*7AV?ps8N$GsUSH!3c{5?$-xJT zw+i!EVi4vFuUEU85w;)rXiYb#7U`_!k6JGEyP9FdKR!XJ%BfN_+T#k z>z~0kKymTch8&I2re{_fCI0n`9c`hsTRbJOeAxKV12fVBK5LrU$#T&OYtc?+fnjw59_4LziM%htft-+@6OQ| z7z2;HXU{FPL>1+6L0E!x^hRS}TZce4=l)~VDrQ>*>GqEIhY|aPpEDe9Y;RjhWNe6O zR^YeiTCwB*E&i-E{^4-Or8^jiOV>gl-{+G6Ah%pvOy}{O&khLoU=f}!^IYZ3uv~Km z-rzvT1opTDd~F%O)8)3ht^-1^jxNa!!35f~>>CiG;5`@g_yNu#MvLT5fj(N{HZfH+ z5f1UIM>lrHZM9apm@1 zlYI$I!~&G!c93aD3^a4~!d98;2l}vqXB;g=c37FLcJ~B}WNpBdQw^4cqQ*ZUSfRex z@-LEa?!;L|S68RQ{GHy)t4c$WLQXc+M<;UPN;olD*e2IXIvI8l+wP z1SZ9PG4psq@vdxVuMyY?!gofEH`yia^8C<6tC9c-aTzqieOKA70eLbrZu72&NwW=N zd~mb^@Y6VYvThnL`w$)@>u8Xo0|c@sC`OW%+M?(@_NtPzCeYB+dUQ*94QX?B);$1e zAcbpzU`riQ7D2&~cdW&WQIX>PQn87>0NN-Ooz9c%hHr@=05-^d(BbgPetC?7@}q-L zJKO>#;EoW<+0U`Tr>Qn_${-3Y#D^ruwHQr8?%N1{PLg=}?kYI>1qm9^VXDu|xq!=8 zaM_A&cOMo7wU?xu(b!GT76Zx@9D1#r0Gj1tNTG0>*vhGJ#xb+_*vC!EPI14`UQ2zl zm#m%m;8lZr9Zv7pRX;JqWTbtv^NyZIa85}M6DA~9I^rwH$T8Ku`6nPi;$n4~*)Y@^ z5VIJQTUC*Tk}rJ53|Oe9y;rg{o!eZ+0}VsFVI{VJ~5CCBiA|-MM4tT3^G9 zZB^#`(SjViQyZSHAxO2HVD%p#;IReRs$@=jP&nKWQ@`V7V|6W~#eCswq4Iy1GkTFjCb?qRd1tQ(t%pciYq_E+YH@fZF zFY=BC@($T{rm{e;#HXO%!W-BAY`4P64lFsql zKt&rW;5dI+=y6!0;d2dJCn7$tz zQ(1E~pqdwa0&I;%Ej^9zPf#BOk}x%ys$Jsj!?UjvY34&b7FUy)r%PZFI;1lDGnai5 zJ8ks(66OGzT+6LQYU#I;q0QwZ$^QZm#a*A38<>Eippv&Pta{KcPEt=F$S`sUCb@}U z_P{RRp$9*K8w$1s-w)k^-#eNj7Y}g=U%~T{_sx0n9A*h3qS52o8f9han=`EyreRa+ zyZw}D7U5z1EML?uOL_6qW{6qoOxi(Di4OaW?h8HIFLQ*T#M)r1DSY3RV$#^1mXPVe z;8JL)_L-)hxxV_+yd0tk8jS#`_9m#&r|EkMB2Q`1Lz9GSjTP9;;-+M!)!o{$y9kRJ z91u;*n>AvdY%F)soWx;4m*8hXH~c|)&QHKc-NkfWK+vkH&}K|6k2YqT_n)VkA&Ms> zbjW9;E+bSByd$>gd4&malP};}6~x}8aE05pG0xefwgthCz1@UzAKUPzwCK^W;EQ9- z?!|B7*znwUVl)O+@AYDCv~ski>z~y+4#bV4RZFMZHZiu}jh?+NyI_^gD*YY-_BP(b zboNP9|1%e%{qEmOra`vi1~B5fY>JK_VxC2CFB8AD79CO=HoTBzEi~=KzopS!)l$|& zfZPjICes;j8}=K@CWtbSe~Ek_G~=00YCbS&^Cp|7|D2Qni?G%hk*a!;ov{Q`{6sCi z5O{$oHFn2tPNm=H*RqM}0%rS(rG^5!{6Fb)@ zf;l2`&jlIu9LC1@7j$;8J}xB6e-;NnEQ>ShjvWQAy*It0r*>k+L(Q)eFC8X~vHy_0 zamN&RWz9SPr??%td7!>)Y6nIdy~y$FdtJMz9-7uRj@%%Bt#)xXxUCK829sIg#mioo zAD}6$L9izih`ftkE+i>d&i${hyGo;^gU=q1LKoSEmcP$6mCF;7YqK~2fgWqmxO14_ zd{M2?msAwK0R=p)kDh0SRL7l(xZW;t>dxSQq8Vv&!#&66> zPCArn-~hS3G+JWRs4^yjCZW@wJyw+OLLC22r*Hne7qLc^wl>KusCPPybws~9(pk<{rO9wKm?F8X9FZVGG6tDM-DXT5JZk%`a_}|SA zG#Ue&J#i<6IuUb7EcB<*>04t zUF#`;!_@(!Y$p&m;MZcjY{5sxsOZ2n2zCk@G5CeuO9~{`tH&{%Mqz(h20Qn+N{}nq zcSFN2E;mRjWIwzvG9mRmNsuBX_4>6TS1NgkIUmSnmTc&fDrM~;MlO>teZoyel5_SK zVZhaz{S|8&6qXS)+`@}~P;n&@)HX>7|A>jpNJ}^Sz1za1s|H|Jl%o1AY!aMlnsW)> z6((p(ZXF56AZNr#-O*6JWZ42;a!vQ?@mB?bE1YCR4ZtPF}frKa=Z-y4w~tT zTFgBG07SsPUX;{Dye7pud#sZGDSo_j9L7J90n>YgA8?;vOf$zFK*MMocb3cFhBzjI z#wUNPsjrg~jxBHQ+80j7*^~QinQcdCl+yMl8EoUBX%(ET8HzyEw7H+CQAr?^<9zx` zmOY1!pFI>u{wCrmd{4`K;h+f=p(o~G8VOn`ZKL)}MuZs2=DP%Bv6h<9g@1`YpU|m=riMVJ9_KmoO zZP|V{=gOgc)%_(bJQ@leNjl%WFYin&h=>kq7x~3({Hr=-^b$-)IEh9^GgPD_E-qiA zgvoyR+=od}RPFm8Rj+uu6It>3kWKC2$b>B__M}?uzPjN(cyae5L>okcO4TZb6_Fem z#R*`Vb9Q{oW4b6a0~Y}w(&|R)QCEWWm&n}Z@T zZRYvJMHpO}mTrf4q{wRSZ;UuQUOCqJ)DLG1){u{r?H44cPv7=P;9Ak@%mi#mr)aZ? z3Qj)s+mP5XL2nBdfJl}~Hslemnc?s%iNnlg2W)jvvbwf6en5Iubc|vnZ5ed4_AY1z zO-W+Er$lqKu)!1%Mm=Y{ODs}XRH`INZNHZ{!t`Ida$XFRRPAsIA3JXVj9O4NgHbTH zyIscceN&BOy%$qqidXI)7m&*h!DD7}-?RYvSz64T5kcT*zcJ^oMtH9v?*&lOTwiwV zz-ooq&Xrapfu}4s6`mQwYk6x4cA}dgImGqa>6$+OwrrDM%sb+17#V~LR9#gvvZ6MK z7NXXJudT6$r&M9A8<%7>MT!t z;77!!CK5r}@Ls&4;GBX8Vt_Fo`0m+v0LDos$>88`i!CX|`S~KZ8LF`rNX!+9iVyk| zxFB_X^a!955{Uez=uVpjp{D0l-MY&06F(xULl(TVeIL)R)B;|G+wFBZ@RZA_70VEM zD`2wJT`dv9i;%}kG6Ub1gp@d`myw+jiZzJx#@1X6HL}FoV&>tSd{s>RC z)Q|@?mOKz52XQ(Tt0GZV1A`%q(!3dVMj+jagN>Zq>b=R=5Xj@L-lp(*V)G6CxMQ$l zQ_?KTHRJjyPAX#A%v0Dx)&mXEUKltAcI6w8 z?`6~{J<=LnX=G%prMVpmwA}YUn5!-v$U{@F!!Y8Ymy5VZsUzzO-(9r7R#SU_mZ&rO|SB>l8#W8!CK3Nw{I%Wm}vl8IPxrh2T@ zEFqI;@N!4;m1f&5SX*T)CDR|ctMc++aU$ss>E4>v5fsZSIUv1_y?GgtAT!lyj+!raKcVgYvYYRIuAJ}*z(;1S^xjG z9;N>a6P66$gMy)zbu~ee_L%xA4F9r@MuI;ECt0vZ$v?4~EolUL2+b|mLe63m zTH(-rPFI{ruFlyJmgT%<7?0ZHO%}Vog>JJj7LUu!Wv*?^;}Fx_=?-ExU1g%# zh&;iz$$|x;kS3LTnIyKYM4G9GCZB>a3(7-^emuHPHYJ&!BExM`Q)LqN+e9r?gRbFR z?;7|%_Tvhz({ADs#k-lU?0=B!+<{W9n+mA6&ZpCV!*UDX8(rc0_H@AE$PP|4(*%7f zrf+U?Eq2e{+kJ4r8)I?Ec+R1#T=uoqU0BF$ZIWY7d|4>6Aj973&`R?LeetRUUmA|~ zPoO)7Qg{7=yyL16{;P@+?M1Ob$$|6N0&X8~_}8e2Vk!nfj)P5-M9?g5kC|)?2bZnx3Zav z^755zAKNI0BsMbSR9}7fH@#4J?**l@1JWhYdg|m|+T1A=`1#mCHhSX938$`mid!cG z68;7=FH%6~_ZN~kMFa%^{~F4v{beQr*`gnE!%{=PV8dE-_2&aycUc+Qq9qM8)!+kr z1+Dk{W#e1ndl^pttH2(8~!gs9KD7DuA3~efZ10?`$?@G zv%YueR!)r$j3Bz}Q<>bMfFFSYrhh`&JXGj0c|87w&||9uKcA;pwK57kTGy^1b+?;T zrLw=B?k{gW!b!5Jjnw|ib27Wzw2TFWj?_^U;oT;3$}9UH01pCz&)VgZf)BOwlF7Ll z3d3lqY2YoL4AL-B@5#j5H_E4ax3IcrO`bcS)%4>?c1sZrB4hFCvJV-3#Y?1wP}@?z zf=kkTs?2gEC$Z1tg`l^#H?9#a`jUF{5>DtCh;cnj3vQ`$_S~wm4Z=KVFU#znE zlri)Z^=%9rE@>4+O^6ToPXu^n@fymljTL!ZVi+?()z?v{NNTh!K-=uB9-tpz{|{-k?{| z*l?T7WKq>v<4|6^+@LV?M)-;W4>JEaAC%P!O95mMUm|BYQC}MmoAfB7*HOo*{~B+B zg8bAGZg#Tx9cPe~{^iXq61BMHB`@x3^#$z$GQ2k6NpLswnH|!qi{tWvj#3}nK2Z<3 zoKzXqwq=pU%xzo^&u>5y_oYVrb)(dj zLV#hC^CAohj*@M3heP($V>Iwv{i_RF*`K66X`Atsk{60{wRyzHA2QqTypGpLNUHAP z;w15i1@}`UQxFb$YwwBrCZ^}cIlY2*YlE5WTqM`hD{algX0Q?e1zJ33!|)c^M6`|s9uc-rdp(F|HSt&2VrxJWvs zIFSkXIk8+L=!TdpBt;IQ-+Y3m2cE*RKeBAxA4@3O!WiLZvI)Ae08c=$zg!EWfbQiM zR|wH_i8JTVG$;e_Itq(av^`QDqojuHTLBuv98xvJELUqm$Q5hB6!FFyytCA0Nd2}K zAb5F1&?l9I3=~{0a#^hNjIY+B)SkTi6m=x(*p{!kPo9yyn%`{d7odab!8z&7U_|M#55*o5OJESPJ(NVXeU`Y;Zmn zs))oM_8o>o`ZsIr?-rYam+b2!Ra#4@lQIu6)!cJNvAEet52tR|Y-|aLOflPX<>J6_>s6bD7(8i4)bADMY zW*OZg8fr;k3xso*XYEdZ#u6f|3xmywQ_#N4fa>l}O;qjs>fN}WE>a~iWM7xv4$4t| zV}1anziRQmNT~$l`*S2R=3ssVp;0w2*;QmVNy<}owEDpbnGHHi^ar<+d{+0;i8=nF z(Z*IJJC5PcImPJm+t~8zlPvL5LE}i4$EvdR+&pDUbZ`~wncF7p622?7%Lq+~)`HGUg>T;4rA-6p6w@AkWrzFVT-M}( zR*?aLSrw5|r$s1PzcCP}o&p>(L=E-8`rK>vY#RE5cO2Pb={G z!=*trnJk6EyS|9d;Yf9lssSy-aE07-onb4Pk{5(tZymIIRu2@iFDc+)_l|td9o?|V z#(N5v6o1RSegPeIp-pLrky8%wI;)YW;oA0w%)Y%v1pTa%NR|XY9qtz)&cAoo#WAI9 zmQ0za@p7`Era`rAa13<)LAX9}`8G#EIL86}jvIQBojaE)^hvAl!m!P_#fYnz!9dA= zLrCAxETGosh%Cst-~VL2bk@WIZirw8_vzCHDTs#ujb?=2Z47=XPhm7+KfFI>|Nha`FIxj{;pcWlGxas$HwLht;vdC-7P z!k&YZ0QjC?9BTQqR`R8^8{>_AyGbkhu|#ge|Dw9=xwRa!g1LneIHwki&59-6btBNf zS+2HZtL1FA-`M6W<#hv5WLf%HE(xB}-TtY0CVW2-MZ8VGDeZBbMi|3vWP1Eicq{sapgo^0a`S#kJt@nmIYNEeM zUYi;(!aa@!d=u!{f~UtWo%euI;n0`Wpbg7Ok?)9grmc4W80Un%`m=^ZFz=9gUW4wk z%s~a2E)x$wWA3545T1|%Aj9Y*kK=kW&GdO6pjDv8nSiIx!~2CoHzfeYS{4OPvof;I zk_PLg{%BP!LjQko(k2xGAdDu*hY%1Nu{|UPTj7E96}3gKX1=VBM9nfnX40BaAT|4& zX-X1Eq*1!mjE16lDH$6Z+FJ%e!6taEzHaoB4iX6|EFK?1x|_X+&_ar!P~%2Dw!Pl* z7m;uN=1vF*oUmG2wYvr`OM+ZFu0 zw^H(IPss)@65^@H$2m|tf+Zo?#WM6xCw97o8tKX_tNN{s>atD4+s$95}b?W$(!YbOT>5;*EY{O(oDS7mGR~ z^EV-@s6|2h2%l5P+cGer2%YWjdWFfO^z^)}UWRJ`7p(1Mp=k@Mv#d4cYtrEXV2uE?3J zXBte4xu@Yo@sa_A8+5bMf|gRW!?5gU@Rj2PR(#4vUpI<uU$nr@SvRuxTndB`MV5fd<*Rx06a zAjpqR5~{c--t#Ry1+^N$h$t?p!#IPKEs%UO({F{nqgLkNK5;{G-iT!cPE5lasgn(7 z83OsR&b4 za-8-hJudb3W`@?ZR$w?!=6K|Z@bulBfUbgg9gLGta+zQ{nc}&)O2*gF09OyxKfyZN z;rCk$W8S`cZoJx${_e>h11Q5(Ln?|Fgm$q#jR&;mmm1}hiiXVFE2}!5s>c?gcgdy9 zzQw3Q*H9&jm54aBTfj)CuZJ2r#pyWf$3nCpII03+e2@(%Be`ZgAmn09$JjJ<1Ri%t z>KZ6@TIk~+%u()@ju74fsrc|P7qU-MZXj|u9Cq10s8n&cy>~`!D;@9s8>(k(q`lTn zLN|xVb9q{$V0Zx2ic6T~Eva1u*lK*ve*wUH+d9Og9d)4=&KnznQNXJh=s>Uhaq$rv z;MkRmQ88n6D^%Ge+A0@vm*&7W@H%RW8twiHW5@_*k zg1J$j8y;9(xi36@&TgDGOXlCov9LML5JeIUA)M@ax*kk57{`3Rh63s9)@+w-8Zndv zrx_k3#U&nR?svKsq;V?BRC3o2P!Js|BtYoErI?M3O@2DO^D6LtR#1DS4Vt(b;8OR&>43JG^%=ldx!Uw-cm~?01gp4PH)^fl9e{D>&}2B zK+X5~;TejvKOM0Y_ers`{%cYa7+^PAImv`SwAaf8g^hqn!(TX5(V6wd%s{=Y$z)e9 zEpD)k8-r1_`06ip#*%1i;RGslTMc^3H)dr2&0t%qmCR|$fyL4N%BDkhRYx7-_f*A3 zAn1DgSQs|OT%f^~5r8DkBL{@ij$ngCH_DAYi}gRpFaQ{puiR1n zeHRk43kRHsjPC~?b3tC(<`AGH$5fit7Y(f$R8_H(k0E|5xM$s(o}|E*9l|skD*(Wi z{2gRiSRi2ZL-bJa>_FoTEAT|08|B8WPYYTk@e_lZ zn!Xzfi;SQu>0sjyFHgg1JXdSj>-e=Vg+oi^A{Q=Ka2qvS?(hue=whg65=%Xsuz1wE}x7lmgrLlhA$gdTOZP|&X@2gmOw7J|y7s;Bmxc&M@-yPTZ}#=bLw z$DiKgD{t*gSyqP7Z7JQF=j;9Zf*gl8YMiL`D>j9IF@e3rKk^r zUm98TqeVUzgNlB77S(;hSzg@3JyH};Ef|2}su-ca0u*|YjSf!SxO^f{RaP!!w*y)= z!oO;aQxl3=HN4zA;8quB0Rg_yH}5NJSQrP2D8I_Ba4>kwvws4iScUgp_PhU$Kj?E46Hy6PeZiBMiuy_-wq)2wiHt*w`sh#1 zZK5q52mt&{pX*tdAM&I6vhUVt&+F=V!NI9{2f6OPeQo--r`YOM$;30}x!41lHNaQ4 zJHhN}lOrnAMl(6hX;X(-LjwxA(msWE{c8YFd206t$yMxLS<`lu!D9%~dJx%bo|jcg zmN+>+4KIE8EER_J+umNU34~^lHT7&KD3gA((8yahvjj2^;zUy}zcB}m)@zlY(l?`# zm!Ld_lUEE)R8!-^mn)>zx?pt?gXZp`@Jx&mSO;}8QLvBk&YgWT|?WuyP+_I(j zd#j@xJK{J0C!gb1u`9ITU{Xzo{C&%~OqSs2by!kJg|TwZN%c=Oa8J}(7BCr$66^A71&*E)4wVA9x0irBT|o*r>bx6b0BkCa0? zG&3B+VL8xfS^97+mw_0r9m=f%CrD4~FZ#2dawEbG%crpa0GJh0j8=xweOVd$%>pAi*h3-Z`qj^()AxNQHs6TI2 zpoJ;0k30v$oGQn8Pui@Oqs3^<3Xkn4T74a~Yc`b#(M*ZDijzZinu4?;1&0->R4=le zify#sXI-|l;vmJK5j->|Tnrkp>H;e?anI-eXCns#Wywn>;kRyGq`5Dg&YD0w`-vAe z=iX5|ZWGWx7_TWew!oD)?P7tqE>djk|s9B1qFU~@!iDq zH`o%m`MVfzNwrK>_{g$J0@dr01(R$YlB}krwum?Ze(!nbE?inpYPM8gxyXn41Vn(| z6=)+Eh;nGM`GA5+tOwY}EkFXCyl+qSRG}|B`q5?p@qo1q$`T9N8Hm57MiPOS4T9?t zJgnst_ou|ew>QbCI={+3%nX>qoPiUV5|JT`qY_Ol#fKDl{zLMMh6o;5+ZgV6y$73K zbZ*B(OK#2i=k+c=CiKMMlZp!Wi!p%{Srm=0-0U{0@Iy`YQ4U~gQ<6lKoyQG0@;q>} z-Qv$o%h8M0qKlE*-{0@!EsOmskSDjYh`!3?kkEND)K(qmeL|?fVXn;UA|G4yK4BR% z=4FITvJpNFc8|hzS1|ij`Q}Hw4^w%!dygwO$a0dLk*)>?y`=CfcbuV?Z)aX9YOEl` zXq?~W)0|fgmESWO>1TDJ_Q9-<%3HJ8D9oG6#+8y3x{N-MJ1@1BJiu3Gqd zkU%qs&;sQ-Tt3~(ETC|Xa?}<#!NL@(F*h!|^xv$Hp!@FuaG5JymnzEVjdnK!E3>#t z=HIPgM)Cl`!3OXWOMhxG0;lc8LgiMF62pUg(EH2X`b4134zn-8Mjx&snHfXe$3xhh z`6d@0)n>&$)_OAin)4GSa6L8p4d=dfJs`R5Rl$}2n6g|YJ5 zDvdnE=tTh)=g{wHX0FH$x(Ig@%72pQy!pK5rNKB{Q&h{5TrHpaebXD;j6~i$j3%~b z1Cg#HTjD5!58#yfe<2Ou;q+d^-Mi6El}y(38L|dOl3pxR+3vImBR_hsK@!&Uh0t0-}Sda9>SR-p1588 z7w+IyPtN^5RZ+fSU3i5`RSVYErRwJrSTHpMcZ<=-{HJSJWZ<;0nTX&EC&#%l?CXUU zavR{dN|#DHH*Da}CN{*zT7A-Sh+VSs7R{Za|NJkMV(}KkOwyWY@+vt7ks4e;rgIM{ zv@H<>sRe7k(C{=jKZiAe;sXNC}_facyQPdlPI>V9xhEEw6Lh3-l`6T#%D4p4$z0;# zJ|R~f;|^j;&{vKk3hEjxS%FA0NTRBHS0yh-nZm3 z;LN}0Q8wNoen1u1dD`Bi{Lf~o>dfC(1m!+89u)rEk4nih7jd|-biRVhZ1bD*hGgd% zlQu3f6m<=yNgbep3F~dgoD|dCvwLud>)>GE#reWVa6ppav`9UFjd!^VoUzCm>()_r0HGZ~g2#1v_8 z3FJg*5cgx0LB*mK;(8S&>5k3F@XbbJ->3lxF!-%!6(?ecA@k=Z3Li<;u5>v)bqFzJ3{R3 z>UUU4z*)H+QGUGE#dB8Q?ckhtkErZRUy7=$JsrV_yJws?RHU;wzyu2;-sLwVyW=^K z2!t|$_Ug1Vtru;AA)pnMzxbVuLVIgy1m;CCJH^RseS-RDkD@Fr9Nf~?q+n?h-)k8OHc;xe1y726B@+Z(7}^>a5g<~KO> za!CoHhWFW_piyJY&DOPfOYbCNMpZBwrw=%}dYx$Ehaz)2RPl^k3oE>9oO*Ul^!mb9 zigPBc^{_(asQ(ihJ~C*Eiinn!wPCxhg~HX+++6)G0CO4BafaS2E(d|R2rt1l#v|rZ zt|Q;X2+}9Em~;^x(}{c^lrz~4NvdjpbeN37^&*3Kfv}dN_qU)NNafX-?fjF;bt*db z4q9E=!y!HE_zPcX3JP2;hW0q>yk-Z)ku}LnyN2(H){MO^WF7~kb^~id+HvSv4g&7j z{hb->u7z6)v#DNMshF}WR5^twmTUsXr3ipY4utAy-Iw6)<4Idv7Y2N+gUHFb8pCPA zm-g3MM9!-$q1!X#;06$FBoeOFkZy{;{dP&67FP}I8toQd<;r_Gc=@P@EN=+mTi##G zUts!hvFdTq81nMk`hN|kyJJ$n9B)`VoBIt=dPaf`ratL=Ac)kZX>1#@t(%}!va6w# zat(de+uyL4{ra*-t0d?lo+g;OUs0_SZ0c8LZs&@OghY5DJTQ_0a{+>aPLu>OPI+R0 zCbG$@c8<@yC)Pe3DK8lCYQ!0Y9+OwbPy_C||Hv(Tu)h{Q>g&x|E?nXr%#f*h=4jb- z>SsvZe^!0jBOGK6!*>z4WN{=OWJUiDK19%-dyg@?=QTD)VVTE~8Hs)%ox!9itjY)b z;KNizAF#nsuGZzzbD7wY^vyxDCgWNo#LA<6n0-Q(O$PW3X&V9HXH zAr6_!YyT(a$by2wbjehJR&s>mlU5EFO({0_Qr8=74isH(IpD$*<8Q7;wbU;=ot$=O z)4`au;*Zj};01>XjV!cigS>L7F;0Ymag-~>(S zMB`8wV3Wu<3iIwJ_2@QrnE<^Bll6Pw=3GQY~GpJUjpXPrY zBLTbM`;^XvWynCCP@dr<0v~Ecz!z%nFI)n$Ks?1CkRieZca6!7qT~m)-m#-vrW}j&*EP5dN#O*=&Ty&Ez`^6CME5B%hf}Hkda;ufu(A zgxle5-lW6y_^mlTMefJ~b#f$Q9nNJ=Z@UxSgX1=HIgz6EG&XAm*#+2tR%T*_F`4 z)m!^!ek}19YtiUqUMA$`TYCWU>IX7&JrM&>B23FX7jP0z4dplRKh9(Pt0>uI3e`DG z6L?d<96+mX`qHy4MkFZ0UbMCjA_InSANzCoKEwvW)!V)*chd;7wz!bS)E2e=WdS)p z{qb9E5^YQ+V0>4#`(o0KfQfoa3uY3vsK0Z;t!SbDN5Dvzp zZ+gvNKFM4~?~AZS&oc$KvcRggv)L)8Ex?x!_AeVSa$du8N#(FdvmJ}i`}goYxFBUB zUB%6!RR{fQwp7}7@*z2Hk8rr;D+{vu#ss9WZ2JNk?-*YM%(0t3Nh%bhyVn z6A4?#knB35)L-ptO)NHQpNX?mbyEM4pC5ke6*x|NfsXcWg-6q0Lr!AFW+QWDdR7NBX%PH5>1KYJ zLyUd!O_FzVr7BmkGu>!<2sCDzy&A;2D>96rJRy;B3l8+B5;7_?k*A+fL4(JYINw@A zm^OL3g9zzTXNtCkb2~$sRdu81*lEv-N&ng#*t~uW>Jx_TNO*R7)D$QaJzv1jnJT0%NUp4H}|PPuSKkCyB& zY~LhzN+f8xP~Fh>n7ARH&PFxFAzHV1UsF2z7Dk{q&LW;W_24e5MtX zK@nly@RXO8Q)+N@BT|W7$M73xbg*dInweF}B*yXr<-k)jJcL`+PlM6@cr=fJOFwHI ziqTy#v4OcJ_KMx1$ADHM`i|c!1xB;+1UGBOR>G||o7&aKAK@%8!gA*x`~$RcGv8xk zB$EP`h>h;Al31*$RV}tE7t=4CB!mxFDN09OthkTN-2T7Q;N{gnj%OCi29oa zRK&3mnc&!%Yban$8K9L-EJLSxF=ZxCUxmUYcEsU?|B8AYY8#YKT=`h}=E3Fb6bS)%F0%n*yrNPLV7RmA?S3`pO2%7d*1TJ$Vs+xB@#3Ytbw$}5Cfvvt zadE#gV)am|OpHIdTGNpvha-79Ah7v!1y{SG6is^gZ!;Sk-l7dxWUs)WBa^V~Z!AkS z@&p&3Yo$5EE6@bYPVuIZtL6R?3w|Jw*~F-CDRX#N@SYs_B16tP@?h z9@`XV4aO(3w4dAhMd+pOwaWCmZj;WrWWdYzs2Ag!!%gfIPuW_pe+KWAM`q3)6& z_qIx1`%_1ep8!wD1gSv{KQ4@I(OJ`Tj5N$8ib67oJeq%}9Ckde;9 zvALJX8T-KEHkwmjB<_a`8*$3Efpm>u1UooB1uPw;0sIjTAmc83|2?q~vWr85US5&; zbGgXSam{|zCXyZ+EIhe}e)kBLhSeJ3EPfG`!arh*+#p5|Fab5^4tt2fdid9HoQtrB z_O9sI`*DLYd}UW>(u9lqEfyQsTMnqp=4H2_rAnC#agFBta@8Yn24g=aTkpveZGMe{ z1fgvpOV;aElu!-fP)@+7IhxzyRRfKSFkEh~No14W*1)wwWt1ZUhoJbWQ_acgk!__t zWDRcL=oAInE!%{~)?Lajh?xpXL`OG%E;>@B&skF(NA&UI3RD^!CShv4fAZDJgGu?G zS*Vy3LqXRcP98Hr&1Y2Q;>*Q2J&Lg-3Ou9I3LH$+WeQq`jk%nJtFe)%zb5wPZA*1ICiR?x-y$JNzF&H$xS4A?0pN^}0ar^f?z+m|IAK(xMk z+@%lvI|y69a3leBB%tPE%%})z<^SkHV(tqtLRF8s{X^cGB}BwXn&q!UE*ZinXqm?D z7Dm095U-1gKSwURhM|i;U5Iib{ovr^3iT^K%?Qs%XSvVSL#WLs8{+DwW^v`NAbj1f z`H539s?ziJSaN7msSLO&)h;2_+%sXEv?F5{n^U`j8>(CX12y{9{@jWAZox7O{GHH; zmlgm0cFafn1o5XdO|uw+;9M1nRxh7E15GO-Q#K?jK#!upz@C}TlrVoqCQLoZ}7c^Os9;V~9v-uX2Bvla)>s=%(g=D&U&Ix)|% zB$h9~5~GZ!#`D3fT`}i3kNgR_NpuNsCNsB+KARZ=7w>y)mDVq58rMn9T7UZcj908= zKfwam4I$I=39gb}0;GhdPBUl$<#QF&DyQS6`d#vPpVi@LNGgK|SA=H1beyyLBL^cb z(4h5%O;P4C&Wue`!o|%v|LQcdO25JxAnZ$zz%tn-@NPc0+8z)ET6V(A%h_@6+~HI$ zCVRc#SNLYI7?yymv$z+{&A5!=a|@$GjTfodVA}ax3ML0rROFb-OC00||C*zEO4cYr zZOR#q$ZgYF=~aSPpk_sv9NoJ6=*&w6lYu=CmJo)4wuny$?}s5L7BE9{JrI5YTJR2CPEnW#rQ0pb9E zef@ePy7NMoI_K>(bX7|8SRD+^@`7f31W+fm-nUj*9^&3hye zJOQ$c>L~4h31#^sSSE(om4dI*|y|Xw+F9uj+QA}<)A|d1A zZu7Re<$*Xy*ujz_rPJWH9v)2DmT>h)?%RuXiIyOPz#{2`T|?#+oeO+7Gw1)8-^r-^ z<1>R|4N~94?wi7BLv3#iC6V``G_t>ZsunOPB=y1?b($CFaj=4-c1 zI?}#hPS8L25X})=a~!s0+4&NV8V~{E`RBHAG%972Sao}fTYbCSTk_ARE~Xjwdu9O{ zqL6FKU)OxRz!3FUuD`mX8ZasbVc)9Noh$70KmAui%#rs`^Y zJ)i{!xS2PQ7H|p`X5Vn3{n=V{7t3r=5qv0Uhg7O+?uRJLnc-iL=M$4{1!a5{18v1S zk^~Nm!Z{;;YlwrSV}K4sT&-7vCltb%^`SWTI4l++MBeLaRZ7*E$r+rUS1^80!$|lA zVW2i?GjWGtE}LCq{`nU_K?f7L;=pP6MWmd;%$|Q_COl5Hwkpczxe+ zVrXVH@%z9i&p8%+S}?m?bs~jz&t916qr!SYk5OL}ntAJu?;^roKsqtX(gZwB}4C`9*x>bw^ zZ5@zxOVEOo#4xI~DLN|@1>kR;40uxapa4{r3uKdQ`nBAFM)gUNSZ&}0Esu^`vMmCmi@56)CBzmA}sT>dNw7E|I@gZ{0|2plHH>YF;H&yGi8E%Cm3}6(?@}V@l3b{As&h&*3sK*-c0cZpcsNkv@Q;usM#;F&W-cEdF z;2+m=+DBOTqtvy*l%XF}gqgk|r-RFb2DWA~j5+FaDxy(d7#N8;kko)gby2oNNQ@qh zkoohAKhvVx*rB!dNP^;`^^k6^koA?CSKF|2`b9RmEF((vdSW@W1r-_`hY1l|_Uju2QQ!S3ocF z5-@tZm*|8moi1(e2uh5}5&}+5Bm5M+LiGdi?tw*t7lE_JWludqZ4Q#!(t3l90I4EW=ggg&xuD z?ut1r2Zia)xiOFoaE(uSM}_#y+PCIso7`vD!du>TdeB!m0sm4rjk`Ck>-y{V=zku7 zeK?PKT`y+G@-z=K@sW8UqagKCDS-2#mn~x;>P=M{oO_Jjj-=Uh{^XNUK;8eGFIydphmy4$rOIil=k}Jsy8B!5l~V02RZn# zJk&L&!{BBqmk9Fdn~jOt^0PaE)dl#fhqDUc$>u1h`-d+`;z8IV5|Z#$e2O!R02^u2 zI~~2}Sx=0w=()$$Xl|dxEVZ?NZ(gJ zCgIP3IkDn6&$khOPf@8;zLva3R0nj987Er;2yuZTPszMFxzwtnIZ1=M?ay z&_w&q&XDT!WL!ryJdl`f7`}Wj!axz`-!98z%oWiY%++4@GSHPq*0ig%INM+Mx0Gc|t-hzU|!T5wJPeur)k!m@uuS4YxCiJSq#%?V@ zIoL0>7x}z7@sT|EZE3<5r;SL-=_Jn4UnVJhSegst&Qk8U=LK}5HTxxc3 zhrOP3?$X51H=u>#Dfqf+hG-3on1Eeh5NgE}y@JR~OFH*tF#EMjR8d^#L{C-$X4d`a~b4Q;El|MYv=FZY&kVw3sLF7NTxCP zSF~IMOb_94Am>l^7weH(LF@0INy4+P3CQk`yNJ*CJwM7xPo3j&RoD0})9EC6p0w=R zK_tv6dd)6Z(0p=yb-3ZanUFgLzf)>gT9ZvRQCnhOx9wCSd1h20_B}PV@e1Iuu2uo3 z3LUX%_SOp=``)*f*mPJjP)cpDV^7p#2}#|5H}&dkCX4Qip}QGJo?3p*Op}T`v}xoY&C(j`NgiRM0=ch1M@+!F2j>P zo?K@8i9MO0P)95}K>+>jr+t_)*g;N0OTeFJLH_vny!_%yy;4W^{>{xK|E|+l%v1a^ zA<_=KNB@GW#l}w+oZsX8tJ_a}u4w1^%vut@4i`vR%BiTvtF#6>X#L!bHM6f_23oLx znL#?z!X8HpyjFB{nT@S2(I^T&#wFcMc*jS%j3O{P2~nqR+(w9Qoki$ppdhVIkOz&!?JT z=yZ2SvcCp0!&46nwsnA|bUE}DK>0kFS1WD4KuwfJd{C!2f@RDY>WTy?Q0m@WC$^R( z;jp`8vBunT3YGdvfjtc@vd1(OKZm&fPVRhgQ|A(zU?w``tcC!yh2rJZum};fdLm}= z$p%mejGx7+H{}SEXKpTI?dFNu(qTj-aB^F(z)TDB2$va7D+K6dFOWv=x4Ma9M``z; z=%W?rxv=PE3K%c$x2Cb<4O;!!%apH@tm&w)bPcXdRZ1bRQ`7ukB|Ri3is0{x04)xR3HET-tP z!z!KmslJM=@X+91*Aj7iNPo^~-+>-kGR%)c{=u?iz?#Y>-PG7pRpkqbaauL!p@B96m6M|A(^PE7;|a!zqHp{4Sgvc`G2k+A!` z1Hv~>d*GCw|F@j%rkUJ)*sBod;Pht|!<2@PeV$SHj1c>!`6C?XvL5%XXESJcJ%rZ^ zTbKU&;Q>lis9eP00lx7nrhOKX(gfT+D7e=?2idoj;<41v_Avgl@oAhpL{sY&h$3$8 zm{}~BgO!5^yqjqpuQGV~DIb3aJ_462V+!GGJM*6Z)~oyO1phJcPB&$HX8J@IBq=g6 z_*FaL=obgjnob76K3SpS4paC(SYtVJTZE>@eMKDhM@1n`v?_cJ)S>HEZoX!Y-*{EUTp)1@|GEHh**@qeg z1g%}Mn>Vi>Ab~&msVs=egb>NyU<|c-SbGRaoOK1JJKA1Ez94Vb^6|;n>Rh5mlm|Mv8mkrXtre{I+3bw??`;-!DP`P1D{TQA%mqDs zX9qU%l!LqV(jUUC!debB4Z}{7+G|)$(Aa%?i}48p2oO|EEacuq&m3s*Njy=leEan{ z^s6lR8mMjv6fqksfq?Nvb_%SIN0msr1FH{R=d%$h5--Hv{VRvrSUpU-cn!g?qazRi z)W0)J?~%|bBrgaYj|x*!ieW} zXRc>fj2ly~6tb(KMSQB0pv?7C!o60c-i^9H4&2v-<+@Xw1^NcLY!A#b+F!hi2u^o&s9F&pw}{{x1vz9! zK@r{dYo{)-lw>doadsQgzCK8rk!)XHs?zbpk|i~4O_%YiIDHQ+t2Ck_LGm93jDuop z=UF)?&2NAWpSp_>lIX)02Z&lV89;P!Mh?ZK_4uyAju;xsM-P5SD9;TL6*#ET4)b?7 zYcuXpMp+?>=lQoitSt{5)3uHtXL|hzc48@SzbZ-ky;jbcZEb;U(B@BAAm)-Mx7jDJlhz*gV2s&JkD`P#*AU^ zj@EdNxeygxv`hOHP)pd^xxjxFR$czPxK{?$=rq;#0YRwu40?QHt5djf8_exfWqrA4 z9Fl0Vm5-s$jbPf?N-R_}eqbOzw6c$#z>-!?3610j@EUx_igccR1D}UuWT@6YZ%3y? ze?QT(m92IM{%Dxl92cs=H~+@Z-~`CB)itM`t!0f~f+YfNs6{AwEkeGeQ4t z^k24QK}Tu%J%MBIjq{kV^IMWf_Lf~=*`fl{bV&jtYiv$KE4SX<-TE`={MZ!Y;3ak_ zR)R=nGX}S9y=p%N08B-~j;(dsFNs5|CGT5siI)`6GtyFiX`=vXJ(kCsLe8&V2Ko{FI-F`If!gP7tA4N`4F!ldyVcBEl@VgUtV z4g}es8_v6G1y`ODMU@+ug0$0%0+-F%YDZ2lJ1YC!wrdOav_7c7yHSE&5j0@rnTy^7 zR=J(A_wIv^ayhapP)eY-ZnvtchN;92>4>GwS<>Jmujnb*A@33Sq%KQ`zkq>atmJje z`tAQ)N;VIC0!3|(2z8bpw}ufltbxO0J-y;Y_#WlTmj9c#DmCGMjY!7-5d#vg<@#%E zyqM%_1JSkX2R6@)mhFPy7tSCI;F?p_p+otl63OLz#mGA$8RqL`2BE2b+sV&oX95ru znIyMPk#~ZOS(Ex)?8}Cd%4r8f6KAd+zwA%%!HU*pTW6@BJdTe<-pm8LOc}`yGnhFD zfig+W@C4=5>L)6^1;zdsDs`H+AVav)h{8n``vh7vc;bN`I=O;pj+kuf2b^%i-Z<1W z`Nc(|?5#DITJ-s7rjZD&nHYglRsF%?-@uZ3ja+{?7F5|&{}e;85seO4=-}4zCwfp& ztdH7PYKhf0QQ2Z+^Tgwq%N}#C+iC5%E~X^r)F8ZT32bc6_$twZ_a7Y+fw&sLfLYES z?C*eWb8DJ9l~7et|1pvr_$=6BCI8san?3z_^Q#qeg6s6UzAO3hGcSn0dW1?VO; zbZUEaW5^Npey* z1CJp#mt$PttM}^<^JDdu_W~1YVPaFTnnw$)I7D5+j;nZ3S4zbCbEXMmZ{B8Z!&U|9 zNiQ{4lZzBelbC}^L0RH3U*!AK!uZCkHX=983&^wE?8yDC2G1?NbMdd-vhJEAPutLw z|83`(T(CE%IfM3RAgk%u)LXA~fT3dg#UEK}yaUv;qi4{WWh_qm>DLGPQ-^S_n#S15 zaQAZMO&Iro4iMXG3IHxw-b@_2M~p3}=l)0YO^^(6R3($V;mJ~X`K3IVKq$sd%_!<4 z{R{~oB~O$m#O@P5y6UbCt9_h{ic4y806;*$zsB#^9;5}q1(j2!0LqAP$zfV1S@J}C z5FGv+4GNjqKS!O!nhL;>pUM<7&ekymDkIJdVAuduK&w*j%0jdF!OVG|5|x zdApwd!xXQ*HoQ~Em9$Oin+0wkO5+0S1hIia;_MJLgq7=xCme^z^RrOfB{n%{RX;dl z$9WzDsVcvhb&=-H&O=fw2;>A+ROPh*Bw2YuWjJvfHt(f?{1CkMv>PCy0|A@%&&ia< zQe4%v>EP2LlQcTx23m|<2_m%Km914eZ|fi6RwC2rYuUU>*e$Og*$L!!s-qPmv7;`) zt}8eWf0_6#4m1SyjJgM-vWTFh*7<+;=qEfrnd*ADt$9<*`8_tX0t0y+uUC5+DiBs% zW@_AKFC)$+U{D!c$_x#&t~-$N@!(Z!fnkIBGBP##Knaje{TM^*ouONR6TT&uwMAG9 zj8;{zY?q1?Vo^X_b}VesS^ZorQ`#^QCI7AowKhb-?nxO#2{j2!H6o!b6AT@!WP5W1zR-BX-K2*R#cX zbEG*^)ST=^1eC9QKaF$`ZhsSOCr*(A9CBc=p9{f5lqw|t+sl{^?w zuT#0J6UNFzk=tm$nGS>!D1-N)#UdFY`5)nNM7Ik{MZ-#={O8%J-8X#WmH$bj;+}h` z0gMcW7DI?n8(qsQ(u(S4TTX+R{dU)>k4a=`u`?r3!1odyj@2Gi;0>2cSuAIDJ)y_n zWOLs`7RS0ny{`quQ&|Yn73=SzWuO*)H$Cp#dm*Ib;bU~(K4KJGdDta_hWq|cbN7L$e)UV*>WplCFEvIyBCyf$5UXaA-$>yaTOJ*o1 z$Bg1S2qc=~e>#mYE`ipN9VpOX>A zPiRxtJ3KpX?_2on3Uji&%gVK1PHXA^VbO?sYt+N4)&vtuDdXSbgJV-Ns zRkAk!vU@!)`A?0_ea$HU%;)KIa#FxD{LA&olZYq(7o1lJqReP5uG z=%8aYEa4aUbFfB^%|;nCi*A>)%Jg8sXZhKiIv8)=b9$@NCCGazxjDzit?Dq+8t7@{ z)^B>g4Z6$vU&n%44a-2x(RoPJ{xD3o4(R7+Xa!yHS{TfNpXtG*J`pNc~B zGG2K!REE&XW=^dLE_igiB4+%wDlz_TQW!oNLZCWUhYt$8AoqM~E<2&x34|fKN|4sz;Py(z?R|! zL&eN`4B&^qSp{VSLJG=uc*7F?(es_2-;QgSH(jHE+n0G*cdkiDaEHGAnT{q{sGxDE zRsE?BY0md!dnI-zXtyNFZ9 z9Dj~WOF3gx#-AO@gjP0AZ@9nb7lTw9sYZfLF%lYX6!J_&+rSY#(=va^GSHkLNNewX zI~U*hYD3Y~$g0vNJ0=T3FK2$M-WWgk60sPpOikV5(W1s~<8&CLD@OTc=!re@h|oEI z5};w`yrFPWpGnP&sKSKWOUN^k&R9pY0$e6%1@hU#i`NEa_XBOu!ZXJFqr>iAv(O57 z*=aepKWz4&g(-TIzj>U8Q&-<Hec15=_y(Ufbl2Q$u!*HX;odC+FCT24TvQ{MfP#1Vz=vEy z$fcA+1MzgC2)9}018tWgHOTa`?Q5#L8^VOLE;K)jZKJhcw zRzmz4=mZy;B6p{P<=xQ7gAmEfuP~%M9#M&bO?9#?KT2!;M9!H_3sCe&zeK~OF-}O` z_m*D~g;NH@X&Fr7O`d-2kKobjIZmSMI(&F*S8$NZjj~3ec1N*56i-22(J2nq6A9XMo9@kO%=K;KW13|e}0S&mh~#kdYFK+P-?!jv?a*k z#)(sbZxJ7E7C0aP&t5p$2m3Xn=?lxIFuf+lOU|{MYl=Su^Q#wT7mw}y6a~&)|1o5fF zQXz=7vfzD#{_Uk8o!pAyoRkoGBDJVL(MLK-0gZ7nI`8%jV{31KrF#)-_@h%?Y0N7K6iHuMnkl7MmwP3)Hnw% zpoZS(FF$KMq^xc}77ic}2L3VAbqGeF6##}QjO^0r>{Wis$eQqpY20w$L&Z7$Ux&E? z9hC7=zl%eS#+f5J#7<9QXh!0ELUY`U;u?nFEl$12Z;I8Q<%k7t(5IDiyY*&tgg> zWzyXpmg|@@*hI^*;-S?YcItR%uffej&QF3uVIs@3C($VHdYB;S^sr3Fl;6y&Dh?;= zD&V@aPF>oftGgNdlUHd@>9}rQ^+I{>p^fqR{a0)ieRjykwrnzh89Nf z=4w3dKTO#D{Z9nJEo7TZHS;sIi>Q$3a2~&+W)qibzn$OQQ-M!G zWH6i{w|R;l=dtY4|B$ij5xm~Z{UzB8fQH_ny3E@TPCQXCX;FrvvMTV#M?8n69#==| z>h1s;w9LNC^)#oJ(+BNn<$VeGq9QDT-#&_wKKNTbD&NCe+-;_lz9@Ew8sy`yZJ>NJ zIU7!;wabX7zaDpMrVin0_R|Xg0uiTwzTfOaqt%H|wAyEEF>0BKR~wz%!OdsV;of$l zEW+9&(+_0i7OU)$z#;JDzY_f;_#1Y}mDxR@zS_era1%Hot(@5=xnsyhPz1=kLoW^s zpPMTf-FEA^?t21VUg<-Lsnca5R<8G0o1Iv~K8t3UW_%z`SW1XMcX1w>1Rm4(F^66xGPjLca)g^?0jA z7GXqIR%TIwvigWtJcrvVGdccZz?8R+kg+ggRlWx@Xsk`B7yMDJ!E_{^TO$ut1~JVb z8|4QS(|GbNV;}YtI+a8nHSzsd`S`oBkv`~Bt_F_^&nT_Y5WG5&$6Px!Nl4?sY>2#x#oUqk@4UnSZ*{u?K2TyGWl{sNkeWXt zOB<)dkR3_ZaM2+0GD{G^wBun0>0;Q!z^{aX7KhG}7jYi_o|1UtafvKwRX*fIJ0X0m zB>iaVh`X<{BfWGszH>_n)ze9SnPmQaKh^0GfLjolc?<9Ho0SX&0Ezn6SE9AvX}wf* zfaG!!EsnKe;)LnxT9cUTjiY{gVdTIDc;Dd#ucnBUPEGRA+%9A)VGf@ll1408^#T`G&9j)IZQ?TG2K?Hj#_jto2UmhR6E`+5g zfD>bE*jk=xtI!WKjH=T4X%6s4s;04}CW18@18TO(4T3(!ChMKGPZkWHZDklTr`Cow zcg7F^7k;7G2~O;(`r=$<;{vn#T-%p>wCm_89KosP!BkEJK%2}L8zXDI6O;`v-a-z? zg)wnn*`!L!2n9CauIvi3B7c3R;o*32EdM>Ht5BDCaK7t>C`u#)3Z60aFO3JVQ(P@C zT+S|(S$qg*vGpb-@rEoO$5#D7z4ldxpiW@cEr@Y%ny0^+%fP3Q;xvt_N(F#ITw7ot zZ2}Njbl(X{&z(3d0~tKPR}~8-Y(slzH#4-$Vj>8#-K%IH)Lf@j->`E*l&+dRryFzB zwOLeq4}?g2BEB@Wvu-^G=Bm_1!>8y3Nwi%&0>$lesxUVdmd(Vf_G%=WUrvQc#~cMv zJ_H488|+x*eNI)s4OsmU)HV|z6uK)V)P4&yzTp5rw#HvdP(%vWJ`YNQuni!KQA!+0 z4S@WGZ|lpm+rHDwNwu3HV7zIoE=;nO*Ydd5hX>qB4_b;JtRRA3G#zb@)@v|rYZkF-plXSx$6uI}&jQ~Gcf#>~ zs64mGrtz*(iqkggrk@~t$sGl*#jL(%@FsM?W1HEK#^Aq>fJs>zXLY3s&^t(lr$M1| zgX_6F?!g~nOFLmI9zZP}o>c3O$hh_(WM_h`J^&r8K2Ou$?&Gk}*mEhMX9}HKgGv{K z?|hNvF%~U0poSlMNm3gdY2S1$5rjDXCzxK3JAK)Y9wz-{B5~!t<)i`c!n1v7{$xqH~~7n6lsG6 zGH@ECwW`QgxY*L5hSpfZJ~XY~`yA?rwgdAsM(_0>Lfj+`Z!GZ+t*GrpO)c=E->a4i z^}3r(%&^YnwlF{6lT(Og&`A|wPiWo=-%Va^R3@27r{OR2|IcQOzZS82uk#5bzS`AX ztH~PP2VVY3tV$T6bvqXMqQ%uaC4HGcFfpf*C4D~tYnAJ*aV5ks8c8I|)m*Sq2aR_EF-|y%-;r+_jx>MXn_mF{O zi!8Mut3_5UO-#1@%>z`>>pM)_JcYg+vhNkXap^oJD%Wh^1t(vJ8HwJ`(>JT6G-33G zJF^_3k~3$HO3EJTqz0B%ac!Vo!SmTSnhH#5(mdgvYtlfTAy8_?N?9NCcMBols7ewC zy-WGCzVK5A?&TF*Q-{~zn`zMM_Y-U;e_PGp^Yr#OfeDg%^*Frqt24L5?;amcc2l-x z&;547=CmlpA5C+9sgOG9Q#zE(bgy0%OD#4bgfS0w;Jtk4iE9z~;wUXpc{6c}6w88! zpU=Qp$_7+y^K4|p<)ZrUSstuf^j3{1@sCPIjg+)G!dif=z!b&WMojYOar(h5KwC07G8 zu>nnwo@RepURH=~FT-<*@$DEZW;nMl4!Yxjxz0URdM!*YD}c9Z#nm|>X(braF1i6o z_I4MgY~bNsMVqn-FNs0~^qzJel*~u&tiM_QLLzoPsB8(0m2<^j=X7@5E#V;Hp|JY) zl$iQ5Eco#Xc2s{a5%R%@E=5KD0O1|c&m_#PkJ?{W^gn zx`of+{1?a=VPMi;6gp$M`_f>0I*PjGEv+t9_0GNGKhc3uzu0sz>|yy% zAxvXMeJ6mA`ux2I#o+1H-54VIP{vCzXgiC}fv_5*;G;%I?_WvW6KqbY-)}HR zaNPct(Reu?pso1=WSMyxyiptLfj-OW$Eidg z2sT6K_=1?{Rz&84%o>5>!wld`%&PK>{P%&s^AN-mk&$xUt;)GLgkLpiIwqu4p4o7f`_p=#2M#$%`+lLBPJ0c)e3EYYy+ z_Ih>GW&};UPSRVBfInHr?X>SgRk!KgOUFJWA&X&W8a$t7fl`b{YOCiMRM72F=ijo? zql}Goh{Gn!WhMxY&`3t8DYvJRm4xR~!3}p{8@C~uEt+I8l5JO!!5Mws$yVe}EZshr z!?_gP!#hfWUj}@U`B0zVS7WZiJ-z;J&bzRY8yC5hW4K z{LxnV@4ZII^khd9W^xgi0TE67sGH^@LK+p;Ahmc>{$q>lTXi#TVQuFccT^!)4ymQ? zrdbd23j~Y8YowMB*D{?So!Ccw<0X^Cy0B~GpB23McYsQ%qis>-{f44RN64w=KCBA; z$Ji#J>~Gx02J#y#VLEm0*-RtpTrK$45=V)smoc+kQjt*5Llx*kAA8= zW>a>`i#Q?1=#UnD19SMQ6>K?`W}oRw5}WwI0LRh;+JPcQVm3Reb)=dFA-2z@zw19| z!BlrUCwPM_G=^jlzE*ZyjwGbL80=zqrIPl4($TD8ivFI!3Co80SyxJ`rpd99Pxm}( z1+oPgXM9>h==PR}_-dZb!9a-$v-=0>$l>xVp~>S5)j8sME65OwwQo#duHH(X5ju3+=HCDVO$;C0+;IZu6ac4L_#(?3^?N_C+Y- zPd~b?hoUxsZ8st;Raw_OdCacTc?-96DRcVES<&(G0G@L`I?(>N@u+Z`6wT*dVgP@ZuE#O^l1Q4TjH3ty~C`&!G!6-@V;g?iL%?{Ph*P-x2~9(R!J) z$Kpk>tx8uI#jy&k4h&3fHixl!ipaZRPGy7*&}TeH)60 zsIdQG-=Kvb6}(!rgN_Fw=@;_u@8=EbFCg9MJEI+?VG_Z@J64uqq+V*cm8v$fuxy9* zMXos45OouL{a0nAxiDMPks&@bw%p$SEN4-hOmxnJ3B+e*ZJxEOqJj$CQXAU4RKyB~ zt;xbRCIglLFG?KWOn~Mol*Wd)#U)5n#c96f^6AO@Typh}mXv{NMQP#%h-HQZGj+r) z4ZmYho98h*a)^JShCY@33$ytC6}QE;B&(90(1`PMVJV5mCoOqJ6bCLlD4LSbkJIlz`cT}nt!s4Lz@r<@+Cu<}@e)$d4oBRPn;?@({p*fQt!#ehT#@k7~2 z$r?>{1V5AvR#-0DUrm;+vVdHi*ea}F5O3ect*YeTr#5&XV)0554}WlG#t0Oow~Ltm zs|}CF+5%lig`4%q${xfZoZW`hy=HfOS({wr^7_ni~IUwm%J6ErSmG>7^PlncNW0R;a19sPdl!OX05v{vl2 zs*@RHYwMb+2sb;Y#>@-S(HItif-6h6bZaw8govkD8OmRAsdoJzMaNdHyTI{^++!k& z9hv=-UfVB0RzQ+tEGk=q>XZKWU%o@`Z?%p64l~(!o<4#P{>Ss?c$sQz{_`Xr{^WkebGqC98aUl zLllenyef5E3Z84!k$-ic-a{1P2}ILJMsI>n7N2#c5(124*W7^z^*1}ONuNi3bi@}4 zCN}Tn@{t@hH%b=FEa4=sbB5bVIANrW5uZ_e$!M3W$WtZRXAY;9cW!Fldi^z@Q!wo9 z9MdCpQx#p3nD$)vmoW$arC1JrJal>!v##0PM$}aFrD@t0(|U+J;(UsUm(AgE7YCdW zbpd5%oMd)S+0h*Jw!A~x+l>|%?#=FRwV7Q<=j^_ZHGa?Mz^*D1_W1 z5tSi$VcABBSL$qblC<6AysEQ)ZrCG$!m`;>X0b4Hj+7uYGL%X|sa4X+UE4jHNcH=m zG8$vi7vIopFUc!S-ZA~r{&@lt%I3QYT~GM`&7hQyS=cI3P#}EmkU)Y! zXwK();@w@XD4T#1)2F?W3`1)K+`WY+aGT?!vs#ZKV0tC~Y=}XNqB-QuI-yV~ZT~0b zh_J~U%U2AzsR-!q?Q5`$OzSg{dql~{znm3G0~3TH!>E#E4_Z_lXlI5BUOK494nCIG zd#)spI`}=w?7DSUHLw_k54#6K4Oh(6xIHE^W33}rVaLQ&1z^*!DyDgj2on$C(F*<% zhHNN?KAK={^-|c7k@Ud9(g@ke$!Wn79EKmaj9v(yFg)7Sk9Ug_X3RHCQOA_9bxYK< zwML8U)*_}7mvQEOuN7bFM{amo>8?gG!b6W;2 z)u0?T9G%ET81Zmer*6M;cKJXGxPh!pd@{uzINF%7*Y>@NbkRc#-0qFTN0mjPIpv3B zEqN%MdN!7C>(6`YEIJhH$+iSvT?Ppfp9y~RVF16xjFZ454WlT+Ey>{~casb}`F@U1 z)Jx`HI=qSsXKf!ia>~unz_?KytZEeLo%C9xO>q0We+!QFgI&7{-7WEXrj@?>{*}=} zyWn@VYR$f6ePlBB&}b<`xh>$C+|eFeBI2=ZDGIth#M2%)Z-gsr=-K;Qt79X4z`B=~ zBpHy1aEV?F2y>Zf=Q%@h*e;7J6b;KR<8O0w`j?s? z*vXyx@z?F;Id7sgEHGgNn(>q?1Z%A53W+KVygv$f5U=6i5K0oT6d==F7J`bfP3sPlC3ND zj#tP)JXERoUoa3_AlS8(aV1e7 zD68xhW;NO~kwd_6-lVXgw!KXbEW`gXVlKwvh(DDdBh>V}r^UC%_+w`sxIJc$zY z^QF0Q)O!XAF0|iFd~ka54+Z%>&>gbYX3bU*73f>+?G&+q)jehQu!=-gf_!{guknWS zZoyNDT|7+#2TYans91d&=?5Qj-d3ZT0#NzpI{x83rT*{YTr6ERX)gZ?{}%iY&0L$c z{_H6O*s&Z!Lwx;ZP`UJ@`L5iMujP{aDZaJ7H14()o$fO2v619##9#B=FWE}MWRrY0 z{XNl#V@P8xK6I?QJSi?8g0V+KZ(`%9oQ1BsW@6Ju3q~)`$S{-wb1?2>bdJIOT^END zh58r~cHgVxP;!v;Dwf2DEl20?I`SOo@=4V$g)8l}8RmI02WmBmrA%;q=riUi#mnhl6o9Rh#55<+k`C_YOd6G9(h=vK z9he~|Q79vq39r6H=0Ivg!IK6~wB?Aec%>hu02&;me=a>AvRrmd>RW9npmYqZw{NF6 zYHit8|Ns|5w~QTWkd!tEpIS3(GUS8!;y^oMrz{NfhQLe+`qll@geJ)O7+p z5{POU6E=VLQl(T82M8{DRyjWn3Kj7BGHf|NykWebHYzs&fbO6T|uTO_{9@d5(+{A2tqsOB`}&u z63-(Sh{aSs-D0+e$TIpmmtCxaE36Zh4;nN2RrxbBi5rOkhc~;8c%S9)?3EG;yW584 ztTIx?4(I_>Mp0bq*oXH40mA6Sv)WQ?qKwW?1#-fNtV-J;=Nd+si{Lpp}4myak^qrpFl2X6A>>#nzGkcCjWc|Tx9&D3yIA--*f8tX z-eZc@XAK}&uDph3SAK9b{~I}m!M~s5w?fL;+e=5Sfmq;$i8pH-l8zoC4EeKo&=IKT&^Teh!Pfu$RZ3O}M8M~$hy zGxn^vI|!P-3ukc7>4ncZ<1mxhqYuY`U)Oq638S!fY#IksZu^Y7dvv;AB9TztKTo+E zN1Y6(zTD%(UQvLdU8|KA7y-_V*x*wqQSaxd4EpNP4N|gnvfN{>^5a(84k>DjkBeQ~qA-3O@rg|PgE zC~EwtuR)wd=NtIt=$KeGnxbIqdEeb{E$bzz+c{PvM0pe`qUFogIdm{Mu6}GotP7$~d|huLg+m z_4wt%AeMQy<^Yz#3?);3eZ2Hu)v0d-=V<)H*;vZ9eW5v!2av|0o0j>7DO7ek9x{Paiiu@Ql|AUf|#D#?D z?>6fMyl_qAv11IgemWZvcCbX|i9JsAL=H_#Cjb!ZC0y5`fKLz8jJu=X}-Y)js>0LtoW}FQZ@~4%9o$jiMiaqsv33n6h|--Q{U zq8~U+Vvz()UIjgAWi%3N=X}~4-(z$*=eh>u4^56v8d|>L^8-coME_Y|I zjrV&QIXhn?L|RKH+`3J(YkJ40_M?Byzb{m>E5^%RdcqNRz9Cj!kOx|hih>3j2WDS7 z`wB}xw4FKRFbsSYv|Ric|9+31h#yV_3Cl9gKBxH!FIuqiEOc{0s~6&4tA!vt;1srv zL-(O;Z-#!F%j^pW2vCCJpQg-Z{A<(8u-H=61KNV_uUtDA9w*ywnjlyk$H$g<=p5AY z1(R@jv=bi_9j-h=j?j&a@0eFyyEpP7dPF-SrL?F^ojV_9c_^XoE0CA(O4Q)(Q z>3T-MZg+n@P3c3NoCHDpN|0wbCjbs`C<@^TSpf{AznqVi7I{90rCP_auP6C}MA=h`xDO{R$+ z9(wgeegqQ?qu8*o`!DibuDIbPMRDmb0ildWU_Ny?e;8K2#k^Vcm`NpOc}C7oiBF>V zx2%)rgbc3j3Vjcn^H&pG^pfuyXy1eU| z81Pr0m~H8-ZvP^09$s|TqxbEIRttOC5}Re~tSKymJ<@ofctnna3(7hdUZeK8yL>r; z)ZLx{G$Syo6iBjdc#&f^clU;57WEf5FVrP*yE5^{C=FA}v)w87=`qbD@S;&=*_%9m&m?$^JP>cC;EcQ9udxZB8B0;6 z8Bn34IVq1*p|7}1Se#C%0(iLc(Qwjj;=^ts@$*+p^n_G7-{JINTG5y^=yBLd>vqr5 zB^V=lwcMC_V#PvuEH1d&=azaH>+3sdT%3jaz%+z7=)0N1m}{)s`dwC~?g1e~gH?NiPnJDZjy z14a7`@$;&0fi{Vx;#uYcfmJaBgn`Ac&Zz~koWGia-7ck-!_+UsPVfg%EN9b=(?3jX zc-PHu(uF>ik+_p>Ba-{yG;2H^2y?lp+PQPBUunVbNR#0>Wn=Lb3h_g@$Hra5vXt_Y$?jqoMl zVQWFi1WgPYP`s&{*^{kAvb89cn|MW8S}f6JV_GO-baqV_d)=#U?Z4ds%a#ao%%qZoM{wnZZD%6?w)Die(*6ju}2d~4`vxAZ&MuiL^ z0G?i}dA&8g52`^`J2fj7n~j&eJ|N!LQS|!^O2qsziq)-!?~E(X*uWp1{g%>X?AjUr z#|D=wmaqbnFJBO8PLOgJ)EMN%sC$cAnl7hXlxnw9Frj&=9;kf&fmR(US_!!oFt~zm z)>%<;X}bcdUKE$@C!)gX$G?acQ84UrAvKEPGJuNz=-g)E)C9g+Fx7VL!r(a@6W1 z8Sk;dsbf+<%!K${y*vG-oF85eB-OZJ#J8zb3u~yZgCfRt3zxc`ClwY$=RAD=Q?LC) zWVI|@m-~!cc=?CvhHNHm0IzTEIoF9b%%jE}!azj)q^otV6R#?UYBdX=J!)BIyJm)8 zDqx=ybF+)bZ&%Iy7xu`0575>P>smn;Z_9UsZE}9;V1cHcFAU7JD@@P`ayfJ2zk1ty zHw080Hf+9gATf;BN3*3LdsNsY#En_xNyijky6yw|$oPmxL3ZO+{40*wm^OUI-!7*@ zKuKJUEUTa`W)tIMfh+$vML6VNm814klJnUyso$C%^Zgb9NOUK4>Dy-MK0lT{gu4nq zhQyFEL-xq-8(D|n+E-QrhIX3ldwa>L7kt~ZOKCbN^?75lLmR>CK!JB56M!hRMV5Lf zAN(t^(q8~=SXihRAU%_IQOwt}N<;FYaBX$c3prup2csZ0W_e>2YY~_7is`nC2opxX z^l+HPkvWfoP{3+;Q8mG_M^RCjKjxE;T5vmRedJI3blbB^?fbec#p0Ljm=Uq!xvLrASqJ{QC zyZX;mYW_)ugnhM)VBG6>p}sKfmZeo?H`^C=D2MS&0o^1( zF}~v1VU88dNHAPba)h|*Zvl=;*AnXG&Q(O&e*VchkXZ(F7%6uB@^G&wEf3CvfS~|# z*PJ(!#%5!z5J-f8x1&PDLUn~y*%|HKD_RP*`D7vxp^MP(kgP7EfV}evm7PT_uKN3q zSUvZjqKCP=#y_4P&eh|MrUCTs)Z_GV(xL`s^0LNs`CZi^{w^8LEH$*UW&(*(5z}n1 z`I1W2^FU@dJ3VL3h5Rldxbv*UN*dzT>2`0v-3)gaWD4SwZoS-^#JeV;d)&-|tuL-F zm!;j;IQPa!H6;AwdNbn5pqmRf}dcOqrFGr+0=bW zXED;@&}#2RB5lnByOKSe5K+7rfQcOqQADC!5?n7mJUVy+2D7*kw%ry83g@qY%p79w z8Wr;l|DU}r!B|6!o#9rLC}H9_8T2>D)gxRjNuE1y^(9_*DV*?@@9UI$`p5|Exs2H76t`={ zHr@kVg$shAJ1y9&E_<6jV!RTz@|}TYIvpshn+6aey+zczU|1P5-G(AWvq5l?R}>LX z)-?2)cne)55d}H1S9nv@AY9)xno$4nj_L}eN(MNj3+l`s;8EbpwqoUt{%DJ+JxEVe zv7EI4ygDS^T_#67BUR8+Z4%ka?s3E*oIsb*Td@TKdM4-rdTYs;?Qiq0f0`=Vw}KId zx97ztslD!x4&^g7&Exz3A8GP3#@CQVluxZXx!OnSe=sh2Uy;6(N3?CKa8kaJ9W(iy zHoRo6wY);xgP7W%cCT(?`vj&_VwkFp#j85w8-sb{+=!bdo=@CDz}g%}M$VJ#T=s8S z-0eG|!_v1Byg2!uKK61MRS04P@}%i;6@nCGa=5WenQ4|D%jGPnCwoCEvuBxSDA+}w z+p|Q_9JSmGHK*pZA`DDC8B$iFL3C(IL~%8%c)_ma^CX^Qmifd{y#BX?GS`e{$IjJC z2T(%Qiz|$+CCO)-^u2G?8bVz20h;Cc^3t7qqwqI39bqiXeedn3-VgkG|urJ45+=o;oekPL9ooK(IuAL>uBgAyBh(Poz&FY{Y61ip|*W0yZZ10@3 z)D*=DM4G(vQ3XQyXd!x>t<7X+1?yjEtoCIy7r(!wY~9VJd|@F)0FI*c8i%@T&JiVQGpsqnA7}w{<>mkd?6Boe!3{^kiKL-C)^YEr^*M^<=rH zH{JiXQ_RvHy_4YWr0x?jNH@ZiLk?q5gTpZ9byixs=UbHvyCo9hqh3JoT=4mHB(r=U zt3^lpYnMJNd@v9b7nt>-=@F}j7`?J@(+%nbf(`CC4%{?JUO4HMYCR!61c!_;uCop2cD>cRFQ`Xf5=r<)01*LiZYuh% zaoD+J_uGvbCo1=lo?L;{#CC!n-7U_cVkN>~a1DISzBiF2 zQ#wyFW*k%uX;!$V(gGOvWj2b5si>As;trd9uCRoxiT~CJ6$-X6+G@JX{>VmW8i8OT z7H&BdVfM<{yzwG*z4wjO@Rv(*s+D?7_{_$A2%T(K3nN@FlRl!KLI)kxf7m4{LZ`iJ zqI~y?4qBj+v;$tuE8B21;%*_RxZ$_1yW31~)QoKs zz+9V=-RKm}`I?hC$kmB`s~OGTu5DS19+J6}x}5Y}E;x8>(9)8bLbM%3Grx?q?to|ifJaov$kTV+v7N{90p>R2W<*EFZML};+#^*akmZiim$SYM#Dde~;LRq>0EvMVU8O5;$^M`C)4qM^MC4 zez#WP@+j%=0@CXxJnY!?r! z_F<^}aNQ_>iC)^;W+fymTEC4eSm6ey7lt1nPTm7Kt;)ETO=Dinik&%o+*5o9V0*NsMbK@+wSuBAhdO%>&9b$W|5M6<*Uuyui_b2PhlKJ{mmK&S*H;}~EfyGAq(e%&%76dgfgCi1g_m)L*iH4;0 zKfk7_JRAoQ`}Zsf!iRvW=cXTJ<1y0OGj?Zzys@*9+=(~{as=H6!St2_J- z(2|+`%IqIU6|+sJgKs30dVeS7!@oOfm%m|jQ|9g7Rh55|ul&4WCLOwNs?WIk4ry4M zv#DKRUQq+<-0Uany?&V&&pd}!Aal0K2^SXv)|!sYIG)thVv?K zs6Vz;!Yp^Z7$gaeCn}kHDS&K1rdIqJ6Ck{!7=mvf(Bj@BCV>Z<*mY)yJFZih;T!Zk5w=4 zI)kjS^9JTb^asY&*~(=81oe4=3`gjE10`pcgV#(NN2Srt;uaiN_R@v9CxvS0AB zTO%m=oD3x{*fM*{7`m`2cmQuX;EKA;PAe`#52eF-{skh4xvU)xq~7WNM|i^KF;rBR z2;d4LsoQQzM#Wht35(5~V*@|BcV`|s)ln#{*t%1W$}-(l?t4R@fTXzx4S|h%bw96=dyeerJ(wHB!iK`LL&xJd!WwI3v^WH3$JEitH?ED!uskgZ(r6L zxT$xB9Q@`V>*i=7Jffx*);8o-yld1h z5GB(L*zZ>G{}l;XdB5zlqTSscA2bFk9*6s?s5c9$?a<#2>`kk=oeDA~sJm~r47EpN zt;+mcp+(ELZ*&OkAIfXC+HzLIA8BY!0`;mH6%A&__1Sy}iLDuD>P`nt0Y@Tp-4iL< zSqpIv?^<-LE(U>JGR$1{aa|8DZ|(14W$qG9vtLgCuxa4>c$Qn${rQU>H}M+jiw)%c z-ZWPO&L&ABk+TO+Pr)qdlo~}3J@DT<;HVr_%EAsithQ?i!)KCz)1$s(R_eWA>ikXG zeC2%v^M5qcH}s__BBY`D$4hoQ)~WEI`dj&1Q)yzOnVeiN~0=9i$s@h6SR(GqisFX z!@#JNE>iX0aYvbDo-7`z1rL|%W#ruO1}(>@J{N30jyCa ztKR&v_t2IM=SyTrm#sZHdH~#rpk9JSH>eHQk}7=` zdw@{V;;F*+anB*GMW1f_<5MSpFwGH5XFxvIgDCGYJhTuZucNjJyrXT~+A(4i!3LF$ zhxYnPJ}Y~DQ$C7Hmesw%W;<+8Z1y0=ruKJ2$LTEnAV@epJ%IpeR!FlpZO_SWY)qif zkNj+zS*Q9=vme~2Fx{(I!#~&?M9_%#94HpY<-lO}>aK?|nnvEx)iD8v-<08{)W^(M zA}ondnfUus#EI1tY4m{r7(0CT5`G^!-D#_YjYFPQys?XZ|0hldd0A-LCvlH3)DIIi zR!Be_GR(RJCzCJ|JrNe0yzlmMvScr}Mu2pJ?A-Pc> zLSlZp=3#CO@(9Bcnf5NsD5R$G9~GUEQRLW-=d@4pU9YbdSvE*%Q`f%M##JMjpn*3u1w z$8+ooCQqWEM3Kk!e{6JPP{n??=#)UKYt-AYo5ZH|x$D|Ei%OYi577PcjHsPYAH($l&; zI@~d-Zgrzmq27 z!(!gN)}?ZJwa4Y6H`ISDmL6GJ;6<2XT{F?Rw<+gNoa@-P;el%#Xg8i?ezzj+n4y+b zY5bccZX*SQUnCfGe0CF9gi$Qz(Ig!3Bzv6 z+O{!47i4H);cyRv)72B>mm-d$&ubce?A8Je*7Y_H^mu|Q{as)3bkC9#Rsc}z9G@6) z90he$`me6!nz}r1W@n0A&yo< zgK`&|U?8?>2cX%0AO=DF7y+p;gox+RefI^|18IkSYLF2?9Fr{TaD2q4%B<>F(TAG= zt7d<{ZJ)vwNb?fr76%E0zkjUC;|0Ovzbz-#-Bmx#`7?BMN80;z7!M>IXg>D@679}J4ZHDs@9DTJ4CtRO&y}VmO)I)CMj`85&q4O**)P?JmC5Vf z54Uey@~N3DXgWXBda!{hJae=06@X`*q9DK`qWR~9N&vYn8?7?@x?e)oZtT@m6KBR6 z>KZEL#teVHQtO_Gdj3<;+iR*b1J%GjHANI>&M|A+q6}C5vs&t?9NuHuMO|&F+4D;a zHb?y99u{=TS^`7iHVt7j**W~tHeU1_4$raW#6sy?*hycL4f9dMPIU}--B{N!te$vj zz4rXZ6^YlCp|<6j@7P*uW^dfX4h;%~#MY5V&;8uTilCJ8=nPu(I+!QM?*r8Ill1y+}!}01`)`Cgo%MXk?o3Sl!Q_ z-91CpKs#sGY~LhZYY4j|i^NRC8~|;KK;s!U1W;5#KMU!!Zbh%Ru&qq9V8d-uA-fHz zfwh-q8L6NdUSXk%j=e`W*hYp;oyB!Sfl4$`?unu7!ocqOLC2Ik3NK@&HxjJF`A6z~ zD@uztGw~&S?_{H3h5^3>Ya!S^x##L#GSxosFz3oxDu&y88(W^5G2Uhtq3)rolZIKv z%#-jnMRKD^(h&T&AY%ZVR3~X&pjXqz4TTab0aeH#W!A11X}e%n6T#BP8l< zo+lHsTi7TV3v`F!wm|9w_Dg3SP*kHVfkE>b)1f=ZC~i_qql5XK&UxtH@5vrjSAkbq zz)4$)NGy>BMKFa7b>6jUO>M!$)c^GSN;<;7bSwYvW-5Nd5#=052&K5%qNCaB=WE>W}>RS zv5FQ*qZB}UKGNsQ(>;sDG_R^{(CX--PtyI|7SoD;nI-*X4UmLTm*d}?lLtl`DsQv1 z8HBymsh45B8O%7ys}Y!ZADJ195Ws8qUiQ@i26!Fi>YQM! zfwGG!Sj5fzvU_21p3bKe3zoisolW6X+m={e!wc#>O^#xx=VtBd_F?v)65e~nx~6lh zkW#8_E~%+Db_?`L!C6cn+=c=52COPxzK}z3@(;4e9#b17W$Ks$imJWzO;79%F4;O@ zLgM%)x^7~(Kq_^5{aJI9g4<+b3@zxW3wSfH?0N$!$Ses+I;Vm1D^Xu;+RheUwBofI zkoD!d*lFKLPz}N5q{A{jS0YFuD^1HJq>=}TH`OT-=WS`?9Ab3NE_VB^!rnE{8&{=M(~++VOzeysX=91s4L5(R5US6UFRG zeS`)tJ(ecudu|&x#v#!_>Wh^P>I@82b%9>w0ZXVib%IiHa{k|3#Gd-8VKd{oC0sd& z=kIIZ8IMTm7KCFJwRGPwjnT6B?qG(Cj5jP2-DMibQH}8IJ2D?r<7THP5m(=c{NnVl zMXV1gXUg$b;2uxZs!z60sq}Az!6T*{&g2YBR@+1Jw{}Kzc!qfJL$qog@U{2OVU~=0I{L^A9V`BPDY2o%`;I3YpGpa>PIKQ^pO|rX43E zdqnS7MfGB$mYh23`3dhD0ZUMcYbblAtjJ<_!(Ca;$EFumS<5qIJ4J249j5Luzi#pJ z50io}b=>~%%|LC z!5$bKseL(2_ccg&E{EaKoZPxqmr3HYY`RP^7FNfQ+O4<0zVY}QuS47?eOj)@XxB*{ zNvr)SshbU#=l2vVhPffd$<>m6+&xn%#u$C3W278F_Vy}d<~!VK_s$z1TG+1lRrC=W zJtw`XPjTn(aB+j<>#w<#ybx?mxzr|ZmQj3Dn#-htCbJy;Qs2<^S?%P{)gaEbV0TSR4 zHb}zSDtT?!jsFKUzOAK1o%*9~Xu>#T%+ zh{Q)7hC4DSf|L@aFy-tHJ=fyK>fXfRyTYX&i=6qlM{WrYYV`<;)GU>l!HEt*KSt6d z-=dSkn#y%F*B(#F~L(Hwnz)8?d#MEJ@{R)VEO34DGHWow&IAJiT*zuFX`1QvwPp6 zBJ8@#B*lSCMC-1kpCZ`WC$Y6d^55CAoTqJ_o#8e000HK>6HJ&-i6yr6Qqd&L0#)rD z6(J6nL8N*3GsM`(#EkEV9L=nKK-1f4hj94mod}y%BwO5mz#Lli}@=>xF3wG5Pip zL!gU&tP>=Z_V+oKw?&3oBwc_L=nFJDT4|mXq9{#hi+GfLTRALj#dWfrA9fgYZ4F}o zAEJDu%n6Ok3tZgSc;@hGg16xl{Ql`XwDs%k#z(FSSp)ACF)haETDXl0Vf{%$qjCb& zJgbAtlc3{#st_7GD=FeTIC-M4D4J*E6^BiOCgTprSpx#+CQj!YNyedSIJuSk#YRP_ zKW%Ky{ZlA)#eedBM3VHWQz9uTSw+UAVAAy1y)g*O2N8cs8YvelN%@$U3Jx65?Wm`q zlPgCDjElx{G;E9h1gGQH!-}CTBfi#)(uJ1a(ut}b1zU& zggbW|$?{oIH)rd?xtcne&xGa+6t=(?DimYzkc+d}UPVRA*8Y9s+WET>SH)5ViP ztu3kyO4|bD9dVgj=G9LbQGug?=hMI;2nMdT8oK}7en240oD%DL3t_-rsk1NpkhHp! zf%XevRpr2rzCyDe+E)T8^m3~EROsc3sbHn9#{cBVRvW$t(@9YwxLPS(>+Xdrw%$GF zY-$rAZzbJeq;|%!qrDTVTueiX=$i-`Ee06G0!oO{K@Aa$**JM%M_8K4db#49Hq6?a z>7FOSwsg_RM4H>i-RML+iExp8*h1)Tn1&N(FhD$gT2yFgK5avR+1(0}eFR|zpOnQ} zbpT7I28bbW0Ol$pfij8|)JN%oAlt<;672DZ>~u1%ecJrgc3q#i#k;z7>AiSW}1ns;S;T}n<*9gG-B(bQL%q+4T>>3Nw|W- zZI~A@Z)n0dw-WJkB`Hl#i26QqS&JyCDy|mzizigj?gGB>TS56avDW8gdg4VCR=c zDb}82U;+@-zOwz4XbEG5KlbO5S%d^M@N)-^oZYc3S9#k*NBs9lQDx*t-j$O2XX8e9 z-2A{W9p3E4rsj6lGldN7d)RHU3mM zmYa|*Fn9O5(n_jc`uPxlN@bsYmwB5uWbW~7{zw1q8VfcAxj9!r0+6|sex==% zVCu3FaZ*BE7>~~u@W4F@z>VrqH*&Q1@juty0TfN(7x?!?5zG^4KgEd*h67cm- zcunztX#d2AN+^MXu-2%Dv0pCI&OMrdmwyM?iP@MM_5tJ_6sl7_nP@)(I|P*!vTN)C z;uTi=Stb6_9Wq58%fekcvRzmX(>>-*B=R-%Ln=vP&((b0^y`P4N2GrYT2KBW0>PoN zn#t>@eFaiT?5SXl>%j{MurN4iQFTjN(>0sn(LOqNFG^x-qN>iM3vKJeZ6r9G@jGCG z2v=r6+g_rifg&|A4F>+C1$W70=G_Bia14I3`PJrYFPG5ZlX_LuIw)^_0B>7h$lS%3 z+&gUNHLG`pOb~0V{PJ402S~oyIL2HK6^-0VqFw2s4@=7Wv7t6O-do5bM^$5pL`#dS zN7x?Urs!g4jW{=o-^H0Sx3ZPPd+rc*ETex16Xtpp=b; zauFexZZA*NmWQ8hJ3I4ZsY=5uT$LxVpZ*&Ck|7>Z~-8dob zU6-(V{;LT=ntO;C_Lo18sXZem&S~!FyalKgfw#-K`=!mttGQq%?L&-NDI9wLXfW=; zxY|637a~3ZLAnS>w@W2TKRz$x%;-IlC!xtw?_le{b$u1!*4SiB8vq1lZB(884-Yu= zp~*Fc#z!ynd5VwGRka-hNtOcI9M|cH-$n%i<|jUf4A2P>-#OFl=6L#nFLixr$L2LY zq9hY=n0d7xI{a2z@$y}o21Xd3Vq$YFHQ)?JR3*3Ew)bBcB*7>DQ*k`hPHK-cu7A!v zq-fQ%c;SR98r5=|5Tz0OQgJ77SnNY|?9TB}q!sLInOrCkMF~4@?lLIAI2 z@%7s6vckgQkJ-uIwLfMS!h2jI7-J>&qJy6(LmONSxtH&2o0BBQX<{2x%?ie=Coog>D2ZYoIs2B$bQTHFOnsF2#{9P4wxs#60HBxG%v!1~NOTMo9p4iQG|C3C-#PSGS zRx}RCL&6#JTlWQy191D2c3v*{@{Y%}3pVou;mCY>znRC-;rOJdl9^%OgM$q%K2ewV zs)B;|ovKFKS5ZvQj^2@0LrszF=}a`vG+;sx>m3e0l-@nUo>Bq;3{<^5)hvs6YA4x% zMJdWUWe=1Eo;pkh)eTQM>I@q&Um@OvTJz5qVsO2G6>G*1ateX=vF4KrDF3$}>_3G7 z^)0RSkRuFb-wW_a9r2Ht@G%Y>erR7aZDP4=%YevK^Y|K2@(fKqOlk9%_Es6vAM4W} z7R9mD3t0`@r9-#S0;S)Xf)n(=X2$CZLIRI#pEZ{YU_Tr1N>eL&CY6soN#O37t-tj^ zCYMC)Yy_l%PQPP>kA~rOD7i}E)-Rv^aN)CS+71;d<3ovXkxZW0WwKcxr18|zOMd`_ z$HkucdLsa_4^bjs^D!|B?TnJ=8WMyI1Ss0LMB3Vsstn23>BvyM+oJKu@U_%<430_6 z-`RkVJT2B9Y>cs3?8pn-V&inJF}nc9DMD4uMvmZ3136kac}*?cDPP*jZAdK_Wn)}N zPP!HQKUP+%do=yR(M-FQ`9oHI`J~%VHLjPZEsCy#Y>YKT;ibJ?^EuL{;(?{a&at^N~JjMHo2)U<@HNI*(u`6hstLykAADzkx*^z(T zOdjTZz^438NIDD-Fa2Vdb~>VBwbzK{c63bZ?&*-sYBOUca1m245Sop(hb(S6k|$IE zI^;;{k5QSSYW{nPNRD@g44SAM3?o^lD46s#5utUlFKEu;FHN{nSXn@@?h)D%WOxs} z00$cv66>+(q5ELCz@pyRVWPP5(Ox3rZ~WR>+LDmV9bL`23Iw}-t-9@o5UT}TII0>(;j_Aathr}{FwRfN7HD*sZZBB6ghet*__{{Hud8eybkLg<2m3TKtBp+TA}1;72}Ic zj>3?Rn5^%ARAHr#>wnS&Y;57b-lvi}^1Q7>ED(@>J|svk$!O27hJ6at=k%F|ws~rA zCM2-tMh`VbAPq=&FUHr+U-IL$7l}JUoHe(`5XVAk%|82dKgylJ#;NfE{C*zD(4SRdJ9nJSUanj$x`}Dl z&$XFeJ-qtb@gg*NReMhmQarK>Md&hEmKTqW=dvDocWM52!Yfr|6)# zWr_w2l^eo0XcHC6u{$^E=;zo2%lx?QW*PI-FPrS4m_v0l~K~ZIVeZ z)T4 zce0h3McREh;=zBfx(WP?lVy$<7Fa>K-!ONv_R8Ge`}OjXP*sXyW(%X2YN9fH2zMabF~Euzu_0ygCZ17HofSK{b|Z|1 zZjkzj$EoD_@GdE{*Fq39FoFPxl6%g*mLmrr(=(tU(-6p8W}F=KG!>qBu`^2at8Rce zRnIc)&|Jf|csm3lx>L{*Wgc=;RVYOiJ5%|vGP+0xutgBwg4bwx5guwjD{oQs1C9?Y zL(=1wG~hu5mU)`Y6YY<9EShzcb@C-Qhk(c<{b8zQ!i162RFeoymR=S;Tvknf0=Q0k zpetRL+oMARGd%1E_Q2G5bpK)7fA531J1F&E4MQdKUqm&PQEr!6YDj$AdzW9dx2T=F zc8d#Tq7`d$FS7?|;Fc=H4Fh(fVO^U#YSb%v>Y0GTFu{OANc#f}J zJd-R1*~~UjXdRSsR@0g0R50dLC@U}9F^z6Txdt~8%&He-+C!p*6T2%P;lge9k{MKx zJL&yYW5|*K#d($RF1YM~)&qABGP9$|VRNPAl6Rnb+}bQv#|8-n4Z6Qz9sKLT>^@Pr z;%lXS$Gt-+cj7n1R#w|akJ@1N)hNE&`LCCqy3S(x3Xik#02AgMcHp{7_p&+EUHPH1 zs8z zO-73X-mh_Yid6Y-dxj|*Vm&xWvV13g+a(*Ng0Vis3kcSX5yN$~;5enj29kfM{$VZR zbkKE2dLRKV*}4{P0ntz7zCvy+n`d;xT12ZDu~-~jBz09oqD6t>sa#TkQ2nV#gQegm zia&F04k*g>AMe#Wl-PqNEG5hejsIU@tVIKH0&nzRe^?!EA$xFv12mgx$E&0(%n^(6 z*yE`YU(M*%FRNdr4Tx#LY%*ni3)J28;{PLYI16+(4T!P?r~O+PQ{|iWJ>ocdN!4=G zq#s{WmEIl>mnRm2O;h}Z@>2|{DR3!j;P|izD!{ZCR6JO5I8t)8rCxE5Bo;Y=>Oqxv z&r(y4ob8;|mnK5xMuwb=`Gq^3-*>hO3dyME+jMs~ z=p;SjaR|BbWN%i?KNE zbUF~V&Lycx=R-{|O>{N9&Gen7%f)V}W`#J0_YPYXwh6G1<43Xu;9TWXAB;#ws-&?* zp#oAxWZnGK$}PdT>W*a75&7fPd-y3S)u@ar#yD;s_Ku5YU9SV?8g ze&1j9rGKGzj63n@dZ4G^@Ofz6tynnkiF6RY3zK&DL)Yb*$K(Y#&PH_*a_knz78|tFV!NOl5ema+s_k?(ysI#G%++w%xo(Cll)Nxc zOu7W7N3BHqw`*_~S-L&$PDI^?TAj&@;+u6_z1hgbnsRAPCBD6)$&iLYiQV^Ahb zLqr=)@Eo{4+W>laRLx4v3lV}p`}@BF6aw;8-U{bn9Mp+YfgGYn_}#QwLYKjPAVi~k z*E<+Ic59mIhOnEWhv-eg9z&V>cMJWmXeIQtAp#O_;!()VEopERjtpj)ls}m37(S%+RqkjzYxwy+3x48!| z`G^A!wl}L0l2WpHt{yRC*TV6J!8nS z6F8Pq(H_*Vtw|KRP-d6U4Ke4mwqZBZjRzy&yk8!=wPuazy>mCV5u&|$3EGR1rtWK< z+y~g^Jy~NYkle%dl-a3HUdZt^xUQvPDB;gaDwU|{6PPqnlWL2aAU?HS)jn}00Z8U% zXbpcp&!IkncqyhrkM0U%jTZ%_1eqXd&h?(iUKvjWCvRvf?^q0J8>%9yd{f#CQzpkqd{zxH}%9fQb>H9nq@ zGe2*4qH|xd4&_kCX7tv-hptj2Y15hFwIXZhIm0gi&GyATK`rb^d%_CQd|n-M)6~*( z2QeVbGs{kFnPf>Yn7L%#d8tWFm-OlDiXB4*HeiQBMD08Q)lWsv-&Y1`;CFR*#2D-D z0wPl;@S3$r51!e0q?=I?6#%p9fOTk|`Va1z>eE%fV;nYj2cxiIhQw(+F*R7a2vGyP z`qJItTjj(*{1Vm#sN7iPvN@)94vk!|h9cq-+MN|(PjX_f4?0~}~+fEt;u^Iul)SK>T z)8=Rg6m%6obKd=qb#e-Xau!5LCcci|q8e>Ab5#JHkJ!ALq%n-I4727;V?g3#9X|sy zME6Rmu=^}DFEABO`Og9#hRdaH!}cW@I{+;+Y>G(Wr@S8lprYm3#i<4KRWDJPveaAT za$v7X1|VfT2=S=8A(oAcZQ$dj&M7a|&^yDDuYI$26A8Em_lYedWH!!$%C?XY^$)YLhLu4_KSY?IuL zH+Me?5%S)Y_!^0NQ+0yqpo)cz#JK`uRj)c5w{NU=b9+49^X&*r;^|kurF?(?yB3_? z^XNx=E8zYs!KVxQa1RR!zLki_vUiK%PFJ)T<(Q&QJmhhZkLmI8d?6pX6^KV{eop(n zt2u9T2!QFFD{o$>KXhBr$N$)b(b~PlEfX6P<-MeH`+C~Ry9eTvrmcX4lk4rPHnpN;t81PZRa4x;QP4)C~CU0Q`uF)9xn785%_S z4?*NA(Gp2tloFKdywfFe0UvnSjX=pxpG22#dJb$IqJ3Co;z#;N*Lm?>fy> z8-Si>)Q>*2dLPs66~e_z(hD3db>ds zi2|DI91#wlt@ia=t*E^!qvz zyg!cRh`o=WGMSQwY;HFN=RD@|VkG;uM8F`N>fLK^XyYGUS5CGnVVlli5$ZeJ&RJL^5Jt2;8#3U4E5*_ zFOtji>aHjj`>YsPU~6do3?Yvp!gj0$xba=9U<0MEXqkp92BtBA%IvA!ZGl%P+&2eL zd_%*K71+BrPHYWv-P{~Ig8mDxOyI)f8Lq48B!CuNyyuv4$XeYjY!2}9uRpov;gh;X z#aiXqQl5%u?OwALJ}$HktZTp zBLOc{#K54pJw*kp3oIR&kMRQ5_)Kf)9UKj}!-*0Y%kvPUO&Z-?lVHE3azxt^(#|?Y z1gz{UN~tTLT*SLR72}6NP_HJ3Sq(HeSOn z8)LxV+p&jHCSc%0_GK~sidnRAdRDABRQIC_>m^~VDWJAeOS$82cQt~Inj6SGtgm>^wQH@s;w8iw#e=p;#C_?t?BJ*g53{x>$DHx({Eeo||~f`41vwQN9iVu$FsjH~rE@;0lKjz3{kc z@gO{BECH+a54%Y2BY^}}nvvqM(V$q+*?X+_!W$1CFI)KIBnmQuVD&pTR-Bcs6E9B< zNpR+%WusrHXilp2z_wRElA}Egrg4fzYchgti(aN@1?b+k?B^`ZOA}hM{U>z%dA)8F z^_Vy2{W}K3o}>Hi0nkPr0mLfg1M*;vm)SGdYj z4KVCS`{IU=wVTZu9dnq9+2a!+o*np|C{p-vDy03y0aR-__vEJaN-db#U`!XU(i6;; zIMoPf6Bk7+t03Gn^iFmfkSG@?yY6L9V$250|AVx7m*9EP4x>nye-INMYhm%C1+6%0 zGi0ZLh==X{rhF;|&AHd(&F);1)N(nQ${F=lXAh0L4{V$^KCi?2m?m0IYdg`QOl2oz zyr_D~Vu%eRA-?RdOCR;DC!F3_ACB?FOZWqdP0qp*!o4hoz+3kQrmnK4WCZ45@u&BNU;z|Mm6s^%cAQ<}_9_g(_!mq|(!!50vHE}*0+TGs!6xtTl zD+{c$30W;5`j?8%=FMZKuex3njP^$wRz_FZ4UCqBQdwWXKi;l(L`i_df23W}6NL3!O~Iwz-T%jQ3XU7I#b zpqnZ7FEq{Pw?-^)Zue772c}%bUOzyqs!vT0l=FTyXJ%WNj+XVH?;yarO)_8y^{P^q z)2-X@=u>43PJXxo$)xx8sZ34+7;uDhJS-t!Z>4d4)%x?(L9vN&dkPlYy30xcbLAxUg+IrCswSTBG}pkm)CKiTVBu@f3$`T$j3Pf5cH{n3h%TCo-+yUN zsf1H8ZK-H}uYKLjs4QyQUK`P1IFU&*FQsTIf4N8lA>8(OCg}R}ephxX&i-U2yIlIZ0ckstFUH>b6Y2+1txWz$`Kj&m_SBE<`72!SNY#HKZzA%#v)rn(B()# zrqJ)njQ2es$nCrr_G4MXPs47fKJ+)ut;*$;&k#JyDllc+R2QY%KT#D#h}1u;^BD@R z5|=tzo8@MRM1|5hPkjoRYMe%nQ6hctCKfI+RG=PlgmeYwF7z0ReoAFm1PBFa(ia~# zXE6R=@Y*YhV*bvl8uArPe*aY<)@0P<`^K?!A5`j5TYYX=<3kSAuIBUEo^6?SQGGXH z94qW}rq9=z#$5h9%T>n@@zJD%t=h5eJB2C~j}IbW{Dp;T`3TW9*XVJ3!FzF9(+t-{ zN?R&Ggy^e2fZ+{8{v9Re8tUxXh@#D}eWD=#`~wu`E;>ZdizJ~!5Ea}5tJAR_IiM{W zLvH-|Yp(PK9@T!~s#_@>6qD^RdT|O}43%J^<*I1)un-~kzW77lLg(wjY0vQ6{*rn6 zVHKtO*eHYuPOih&FxFnGjBW-&r^hvjc+TJ!OoxNOLMtN86lhzEHX5Bgp&ufw zFL4~@hkFd-8arpix-@>gYV!eN@`gV>$$crP>{j`mj!Lt6ZM@SiSp%)^0c56k0;}=8 zO1kJ_6~OTjG<+do^WcXHw6fLxKgw`KiAnyy?=TsJGGls+0xrt?d`B%%ku%NMMC{nb zWKIy^swH7X1WLm{BCSQaK(@YSnhBnve6TM9NG}}~2%g-I_sPB;k4Gs^vA7gW` z+6na#4Eck84!Ij^zdqEpJaqkg@;+$bhE>~Humu>&>>Vtf8I%Z*O#NrSbvL>QSp6E* zx94#(e!@@7k_$heS}NV-83BiaS*bg7QPF`ahnvAg#h4<%ODmzhzc_FtQL@|HfL2AF z$;gA45p?uZ;$HhSqYHin+;KPM7~$i4T`q4p*soWYSv!<*JhPDF1ozLDm|1^A2D^TA z5dKf*0xeFi6k>#{FZ4+!7tv^FYV!4#iRLbELZ}5XBVCb;dmcHwdp{*NQxQlthY^L{n@}(Bqcmc=SZs)sp(&YFgtpl4n z5yf<=r?_0Fbrrba*hIXx6yi7Nr@BpRk^jtl#`F$ToN8Q!DxGgrH+`6)tq zbcZp=!4jbh zrEO3z+KEC_IB4F-h=EkX`o}50$_6532k);Hll;_b$v~D7empSU`CTj zjgMW>Fil~D2ah*9Vrwnq*m^#x=K#7|M_eqvp#X6}=zJ-oNZ#!)QQCbd28#!mv64TV z1#E!GrjJ%YfCnroJld;cD*|5^@U&6y^__fkVO-^k>fS$^r&TS=ine`yauc)U!tg`E zC<}j5n6_v!I!~ zm|GZ~z01wMqs-icPoFllVq>6v6OL0D9EI#qpKk>S+quD+rI4#?H5d!Jit{D7FGSNK zR92Ydl17I>>&)>xYbNef+E5|7Av_9^k_FHe*G}Xy3%<>s2gcMh1`M(s0OiMtGDwy$ zzpkCUbvzmJi28)ZDuF#6ciP;#rcb_ofa7xsLK$m;Ydv}xoV;~ByF&Ug11M@{Bmi*` z&YHIdYN6bVVH7~-LbmdSpn${3O@Z*!lAEN170nvTmB|(Q$Jb}DO{e%0^}w%lgvN!< z7s1zu-_yld(GWL&gv1@N^@had?LwSIE8Bxj7ZXU;xvD*Mgjha58wYdx9+M0KtCRFq zedqYf2Ezr+jY$rRRL;a?iir6;EjxrWBEJX)(Kio<@I+o}=rEZ@~(sF++JUPIT1mf2=$W~+<`W6e+nsS*7p0t-NY1y=wQ6<-E@JWs6W zYX6!lHzNp4P=HIAA-Yw1Zp(T0ZRR!E6S!aRoM1XpRM!2pC#EwMJy)ny%8=nre zUhQ$}unsfMr0PyUZ_)~+PYR7i9Caz82ocShOYnTJmFt?t(B_%-CX<{M4#r4tlS54$ zP3c_8kv@PI6)?@IVv8H3ao|`t-sNG?p0q!y-vI;8zxep&E|$yeaVNwQwmGz+M8YYg z-xfQOz`B&VSBj;mm_)@%OQx>3XuQZSR10#X_`WT&+bIgPinrxoZO67RwlYq!@%BUF zB=JbCZ%c&1nBv#%Y$#uRzzG}{M754s@zO1-^) zo-^#Ik8cOpx55VONpoiHEm-QJcA*bMFGq{#>j?_270-3a%wgoxRJ5&3S350^;RV+u zC)2}7+?THx4+W8wHfT-!26^{BL^mJT4-Vm=xXXVz4Q^0O8kG;YoIow)z=Sk``GdJd zszoFd5{YU^PBsu4Xt)kdUw)Z_I(=hFi!N8X#acSqR{co)XukE)ODXiLqY2A*8r`Z` zT1L(dgWJ!b5Udu;U_|`v!lvBNT03cey!wm2drXTIV8f5x>W>E-nWmP6E_Gsz))1%L zKbt_0!JYuG-=@p07&%E0)PP=(3JgXGG|H!)lrX|juEa8b>>mCFjvmqfV1_KHtM{XJ zhcV2m&NUUfSlqENnFD)j$fkI`fiG@W)1V)()`Y#v5!pRM?D>hcCngrY4 z!YP*uD$fQVw+6HArKtI%l+AXkzalKOPS{s$$VV?qgn(C;8a4 z^b(lC;Ksc}H>0^mn8t-ZwFNhf-@=PipTbzVmf$@|?_;gA0^U4QnVn>UNZU zUgVw7_XY`XJI5}JF(``q)RnVFCFnOeePTedTXZ~#tMbWJexzgZfbl(5J?OZ61G_H- z?QV^WqECv`CadP68|g_bORemw!^_!3z%W5Od@F68p!2CfdzqM6=OE%5HE#y>H0|_M zn7+4!zahGpe6v>f15q`&09A@>v0}=%BLj%>k@&*JgP>b;xN30Mx?-FbZFKd5+7`Wq zYf6KYHQgcsA7B>N&ok0JRBQz*RF3eH3eYP#+ofD6qyJfpb#4dWLP3Z7`Y$@cr;J3l z)u2$~I)B!O6RntJ7{B7wzyo!N_thFh#`;`P!9j&$*G-&+GJSrG;eJy<_%L)^jDFVq zS#&w_DDC3UdxV%#c3|f~Mw?JddiLWICObAkra)d}vVrMnarZxr?v&)o*}z28Z*DxA zq(w&(BE|9I{81kLR+B`rckctPkY z3E^#o|MlKto)DCUj>`4rX>E&a=D&!xckR8f3!lxlxK)CE_6_aia>WuCJH@UxsOF?O z>KU|*4F&uC5{)ucq65dnnJdGuL|7>0_;}0u+BiG~9UXze7>;Q4K9(*CH9XGede=5m zSfF4m=@|lYhT~^i>M<14!$QSt@l6~L0r*BE(3x=zdTRA}V=5VHG@@ANTS=yMCEJ|y zf+l*;jCpojf5tp!v*q~df1q7eW**TnlNO}BaE)0s@2)FcA7gUapoRp3T63t~o8 zr(wxRWdnc^+gOr&&Co@ef-yB8^(ojD#kqSzOdHh`=0YPt(VQtKw(R-k=zMI6p?6N| zzMF*of)=P!-{)9t%=K!DuOYZSuMZMxt+ylI8)R^DISCF1C#u$~9&m~Qd%f7eE2WqG|g&w6yvlt8FG^!U<5<@nfwoOzaZh!^` zM}Ix`m>pZEwE|}V5Lk{|9L*lyRbPQVj6o?jN|5@ret`5YD0I;f^4ol%!JUS1tJnzh z8^{rC-CB3|eKNDmI|XDV(dKqxwOnMS$cI6p|Eu52C?y0xjc5zD6_he2PMq=z;p&Qcl)l2I>$tt%^R zcBm*drh0U~*zTQGk)#P=nyWYjcU)pVl$lbMd6ihg1h!k+=|;z!9XrUSZX$wJgV{JR z7`c<{3Zo4O!^$|5eB#O0(olVQ1ITE-&}y}m^IQp0&^F({HKV|6Mp9iFeCPn6)k7%H zqQhy-5BVQZpR!X%#B_oz50A&qUx`QZ)A7z(C|%GUQ74S>HTABdcU#7GsG_3*-DA38 zW}KBHqSAo_H3hz=A=j~04yuUPH!RUUi^CjRYMW*s5f(&1h7vNAQZbk_kzujMop5A; zxLPf%EagooH*rnZs{^OJql2>zCdMtITx@hI zqy|3`XprnvOAgjIjuI9>_eRSOY_1-Zq!D6Hxi4_gH~z_z+#e;UmrC|U#w1( zcb!@Q*J0mF-a$vER8Qlu2JE8vO4wGXd8mo?M6KdxUao0%TcQ=sXx_^ZA);YbCd!kB zY8tpaiFz=i9igc!!o^oRXVQ_=*MYi4Y>8pE6!ylHuFRAUMSN7d&pseacFs6?SPrbw zy@uxpgzwr~OIiA{Ix-0^j&H=m8*iXqYW#Spou#eE+s^&)1he#^G|@@~*`WYTF!%=# zyKQ3l2&@^*R3&5BCBq(6oBddfAj(?yI6Mx;2P#B?Av-^g2281i=@XZCk3&3P!gq~g zRP;8%*5`A5%Q;oOobXF15wuL+b9Y5;L$M5{SKcoe(6A#0#ERPApl>I<0xZb+IB#|( zSG7fMGqp{IJbeT7o=k1E%7)D?@RAU%WT=G*9Sq77W3FhWIDdckX{V~&;j{4 zXcl*8$HtP?`#tre@Bnf06W%gG74@%d1n(=I%6o`DshEf)_|gkR9djF7MdMRXE)08( zAmKKy=&2l2H0SaFsx<$T)4dhbV_Y>{UMSlWSd#@L))fbID+3XWyJAh~#hn{5K5Wc^ zAe3w``to};K+OI8?s=Ph*dlOvF#p@(wchB#M{}aPLq!u_MFu5u>@l;csZ#U~%s+bE zOa`dnsW&AC009cU?G@zpr|-mVQo1wZ;~DH>9jzxzuNt%R1nU+bnnaNkGa|DA)qipB z39=(z$}`E(a!3?Y981Yd*Rvqf1eE{)1{Y4-AyXcLTy=5VUKwY=4%*)W;R%1HY-CLK zE{p-Jg7rifW}HcH>HRWT`%Eq}kU0WC45(jBGB#0yQCjgy9%N8F(o}6mH}X~$t@l~) zJp;KFO2PtUy zujYzaIRQ%#-saoNu`@ykM?aE289ZN`r`Ofl(gVdnJkbi$al3y z^q`Uj#{4mVMd86_5TS77Y(JsM-s&onKn{PVM_k0CBx(eJaf#o6__~cv%{#NmTK#rJ zov~L9eN~dP#DRirq}WPqgB(ao~zU0mYRv1-c1n_eq3Ct}YbC#sw@IAQ`rXH`-Mb~gfbu0<~i}_>j z4O_$OP>od(wqz?A-E&*TI;l`Ayp$xsL*YsAP=zy%R4J+831Y$U$RL)1$&T(>C6g#v zin+qqy%78UZ0kuTWE%|!|6W0XE9U5Bv!9Q{qk^HF*y*h`V*(Y|s7oAyh5Yaka%0V& zx4>J`^7;j|@!VXsxA)PEsGVH~)CDCR>L7Xd{DG0T;DUQ9g1H09YM>kaoSu0&mQ2J2K#`BU5iN#gevdEDg{>hf-b8-1K*@*Sbu|mI-6+aiHF)G75!Prnil|7yf^fuwm%l7 ziLtz#@e{fE^S}Up0CG|4>0LLYO0u{h(`eieQAp}=iNu({h-JkWCNGScwjckVrfWn_jgBbJ;S;WXaAkGw+!ATGSh!5kabV0Ciez z39q9VCE*)rx7#V1ve$wix}ZQ3f5$VaSyl zBOW0?Q!*(a#isSQ*_xo4E|gWCcM{>dc3>j;XlUcR=V~RBeX135FD6S)s>%u~uv(8&-8-}?Ac=%Dwuf_a{d;1sTniOZ%yvI8Hh@5?C-@OT9LqJn@00bK(S}3*4@225-y`v?cxfYL z38eGQGB7DaAXkI}wKUjkRThj6TUVX)p9XH%_ihQ&)swgLk`U%zLCpH632MhqA#PAY z-{|?QU&TsGcnGX(0lb@^Z`6E|RK{ScF!r#cG)CYo$OfbzftoMPj~AL`Bg1YP_;VkE z#g3&4M~6P_rV;U0%9K=#fmx zHDw~52<;Z2SXsqNfY=`*5`6A<5+Ey~q?SB$w%Ypm9bW!Y^N|rrzR=f^2ZtSQqnNxj zJ%%E)8X$VIN3UOr^eoF`84e?bMBmur(g^EhJe8wdAt8L6V9<`uy{Rs$wJdg#p`@u? zlJoWv&|kXozKsp=H`GQfbBgnC15q%LViiuhfb6);#jkzJ5&)(baRBKc5-#J&2EWxg zDcs5}7S;LeZidx!h{{Ly{0`=}9rY?sK%tc}E#saLcY@8BKKIr-BcdtL)&8DtA_P#( z`P`~|dtqam5IKRQdCdQ*4Krpij%PN7l(6bI9bVk^WuA6U^^Pt;@R?MGr$%WQcP1^F zPR0?iT6vpEpf$1Otxz|CRe#O+0=PGuyi9IP6==BeW(B93=eUEFEmCRlPQst;#g{WC?s;>DbT1!(7(`FlyORv(qIg@+>|TA%y&0Q)%p&^a2a?uLY^UD zv}Z}Q$@?NXU4Cfa|5j=d@-wk0E3uSI-lV=JDz$z;lvq5TpfS7?+nCd<+og7hxdMh# z-OHiM8)uEqaE&o9JY*7me9JL>aI%Hv&B>HYAKY(~kJy@F7_a#z4jDDX3y1M37|KMu z;15ZFG+aj`EH6fmA-pa0A<4jaOec$jS!YjmWPDPc7!?v&fUtR<(@n4U3x5a+UCVVp zQ{7?nmeA!ge_m7EFCrS#LM>sk=J`#@tRy_@gUt^iHxVnb;AR=v&RCRd+UY zKlx=8tv}DFxd;$X2lD_Ot>J|kd<4Fa+XHJ(p!6ktb~}BD7m7rhZv5JEDS=a5_(yDs zybMg&5qu*vstnKzHBkBMP~rrcPFb*DwyUrS?D0|>N>vx-BH&X?fyH$7us(x0=(9@? zR1XPE9nS66YhI~;^$!=P5XxW|PX zThJ`Y(vGXKBdB!D|JT>-00);D(Pt@W4m=DIpK~x2{6o@A9AFIMRC$%@i@DO)|8*R5 zRA?h+yva%2B%s2*n1jv2e2WX*9kaYHy3-OI+;O%?u9#}L*vxe&;) z?^Z~Nb@OroOKi~W7tx$tn~kSF|7>YTg}I1v(2mo(EZHe zE+Yq7-2$vpL;r7oBV!MJnv{LIcC8BtJdfV?#m(j}KVG?;P+ z)GKO`sU!k|u(+_t_Y;O4;pqzZl=hqb+9;rpl58B2SV(!HltFj};2i}SaUPi|w!DJl zf2RUH;$m|Fnh36h#C+3C>H_l8jTB%^6@626Vr%kUD$GgzFes*-hDaJCWHlLL45y5_ z^BXWNv2)MIGrQ)JLSfkBLScJgmH~sk=yQoGa6e(8h}dwf+}VTw6!`HI@f)M>X7{2v z?fxx`{_e%@GEv7-uLSxlL>?T1*?#2Qf{&yh6Lsj0vBoP%0>);Y0j6F=19_nEiDvad zY45=j&Q`4(nTyn{Un`WTChRp2B<67NI?(Sb+;;s+E#vAy=E4yw)Jr ztqTVgnY;2XvcPt^-IKevo%X-U3a=ayOw%G|rv_lz56ovEJ-o!BRsS>R zA6j*dyI`S?mZJ!Mp@Y|SQKB021GNFy#}37&9){M~Gmt}Zt)ualJDWWOG~D_?Xpzd^ zA~_2hE{E`MLAnWLaoA>3c||+nPoQ9JdIl_xa@AgnuRNDmlX=Lk%ZqAgiQQnusIrIW zGpn=9jPkC){OG&s{pbUf!L9^zN?2-WwUPNWLRgl%chdT~mt;3I8G!MEe z_UkP59LUo*jwV{o-5q>bAXzrh6`>n(mUsLsz532j$>cGH0o3+Wk}`{aZh$H`(zl2D zKB*=@kfAXV*h9e`E+#wAT7Zbi9i+NzU^_B}SQJcTvVC_#{1)2*B<#LoQmB6ja&w4h zQIaaN4_XZR(c65EhEeoQglgVh@h*~E?oRSH0t9ej(*N3+>N?Z|lh`!!p4l>GUNI*e zNT0$|iwyJaiHny1z`{gTBayMTzC52XiN^U(wTMdxbpo!X%ioOL^&akX3#O#G2>kok z4R);P@6oESGK!t)&KC#rSS0z%_s`MS%mYvP^+QuC6-%<7+S7|3UNdf9QZWZ-%h3T) zANJc6euHY1PWRfWNZ1)qIBlWIlch&tjY3ch>%du^8K)J?aH2rBayU*A{am7l!Tf-*n*S5%OFVQc-vAbT8lfj=LOGV96ILC}W{CC<2m4_sBF>O$#KAEr-@aIFBp4XZ|KbZ0Pjh z($V(s+Ac~D2{}D7$0v7PHimiM=l3$M)(>uOtiTz*t@&b6i{eVmC9n>DqV|t*MchsZ zdG#49$GZJv{QBYy2)gf(&{GWJHiTJN0FGeLIa&QGU;f*1GW|TJ@MK?)*h#-oCz|95 zo}bD|bjKi{ZIg=p`HKt9KfERlrb>4b!dyZarQ8Q=`Qke_+ht#)>jjhWJA2e5xvam` zu(SWmP3#xBp+8t{?Ej0ZeSdO5^z%v{)_^^=UQsF8dbHI(SL8Nq%7vImVv= z$VA){3yPPkw~gg_O&-xf%LqH}>Iwn~ZV1e~?61NcGcsZ-D;*Y}ePZ~09_Sts;71+~ zn_ig{gJQyWB<{2`8E7=l`nmpJA`x5NTtek2aJ`EJmi;|lfDcU?E)ppo6`8}f*2KS7 zPf~tuGPew8%oShj*7lY<1D)bg5M*rFSff4Fl466TA@l>#8Qu&h&?HM-8&0UleW!l- z8Xq12hy*IhM0gSA;=p}(K?tcCxtX0wstvJp(~6DM0RRbtjZ2T=nxyXk)4YAS_D{ho z`)P8^DvKsHM!!>tDn3u`7b4U8TW`vBT>(4Z?g7h<0eVt7vZR5T4BMi4HB9^o|Nh|) z_|Bqo09%v26pb!>+0OHQ*tp@O?uxrPMZc4lJ(tgGIQ|2b@Mm+N+556?D-qc4y*94Y z(Ps$2!Yxk4;HF7*ZCF?*)|WCoB2iT_Jt|Fi9-jcbfM%x+ud!!*ZqV2Y&m!5ZjxE?a zLSwRoWtOvggeX~A^4ht+sW3Rlw$j`#F|tcnl}x62$v(59N`dA?`hx)VsjGu%fo?`0 z?dS(a5@YoeOdzrO>T_?C;twSbqi^oW@zuI&Q#RNMikB)t`_c`W$U#`8=Nc_0%;a@3 zS;lA3yan@|_l9ct>KH`ri#+Djro&|G?dW%aj_fSYtS*7}HFuNkM45HH@AZ zNA%gU?~>)-@|fn}N%{sClf>tfY6KKg>!|@+*Lg^ikWFxhQ9qc06v!?-GZT+twvNcv zd$M9R0?|8uns6oz%jUazskL57nY}~5i0MT>I#m(#CG$TY!@=bzm;&bmd-IdfDj0b= zWbEATlIBdpmH>?C8>76F7sx)sIIT$DGDC0U!bSUqqIVm*0pzKqaegz5%hYk2*|Z+= z(xkF-R&_zx9I&4!^y?M32o*^useD`Js{ajmkQUHGD&&WZI~0y5{W(NE@c2NI?eKw9IpoyISL_xAd9xtD4f(C^r=)4 z`^R~%>ri^nZyWZ`b*Hu(S@#fDU=RCbcKG#5<Q)*Ma1 zPvUUA1HF2}T6OPZ9;Psq8+FGg{8OA@sYIyR;l)C1oeH%5G}t#S9Udxx-Ac;CcY0bW zx^K3>5MluFi-0mP>t5rE6Gey)lVudJC(8hQXJtk6**bvz+RKL>3Q9$?44MX{WHTy@ zp!u`})?;Q-(ZMAy_$|6BABRBDP6UGL7|;Nc%f*OKi;*I+oMmjw<{AP|28eNv#pAFD zR;K7Bc1Hj8-iNo2y= z7;%Ao>VKNxA@EKniZKUZ;V)0n&bZOQLz7b$gmM?Aji{-KYsB!z5%j=37!m8ai}Go8 zDu9cOUjOZw&}Yx)&;d4&HE@%vW67ggHOD>!U{8Cg!_ktN=#cK zK>S(@g>`*kXb-H^bS}?b)jL$j+1*od+-CfHiS~Xpcp1+D>=$p)iWCAj%afODTv5Fk zf~bFIbV>KjKa7+3`{R#RnbIM)P*cnK1Pas+=H{!>Dm~>4zlcsUQ9jBLRls;geRQ|f zu36Wr=S<>C?f%G>gY-N3O-VJ7pIT88|;mmUe$b`GKlNx zq=%)mDb*gd@T@`jr$q0l2Jw_6q3a-h3X{MtgkkFBWGGg&3Os5e%!6@W#4Q%Dvjt4zE-r|4(SKpKGtW=jkdYQU z3CIeKtx4@Ps3PP{q6taPAI~3tR-r465u#LqA)2d}7O4+C)3SJDYS$Bg@JTt2K81pC z*c7mYfZm?A=B?}QCJQpV7xc)3VQ- zU!X(oRo7jChue^*82;5ppe0{n;f7X(PH-dTa|bofquMFPGAR#h4RhMcn?g8@7<469 z*vr>y&iWsk%*GzciAU<=m4^HMnH1(1qatGhXXH>D!P4V!s#7>b|JYM#MzBkH!74#Y z4bG0vNAYIt3mD-r(e)Tjfl1ixNU;zV-J=tdbfL>I`_ycNzuj*WP43=_)Dw%nF{%OP zy;S>X)JmRpyTQ<0NUFZx&^4HYBfDZ+2BVK5qEY-%oX%&syiRQ1sR1a-u)NHCz3zr7 z+l5U}J?n!4th9Rt5X+Lo8r@1pWi)@Pj3IdS3h1n!HYMD!BpAk?&4B&N4v`?8Oa{=` z3s8}kpUImh_>>iBBw(}W2@BL9xbx*+h_umfDH+VeI$^VAgvLMNWQnC&?`aw}5%N36 zxolf)XFu{O{#!LGRt;oGNgLTt!(~qvnX(n>j8Rg^wHy_25yS5<X6=p5Ba=weK3?%D*AC731G^3@Gee{kXA5i$1IE(X`a~v zv}^w_aTBXK&FlHyjd1~sTURWX@PHFS@Dw7ujWMe8=INa59B}m~OhrrVwn!wHJqZjI z8j#dBlUV_i2Fl?U^sz#_!jR|Wz(D6*JIXi?CVOv@k3*X2C;vojX2LT2UNCp=_SOL` z(*Q#Vy`cZI`}zAeIosh}-@B2Is}t049XGZA+@$c`ICmVv_o?y>RR}m0{QQ2{op)3R z47{LNg1DO~r)Ig_Atz#22XDXqp|2g}W?G@9BfPJxtMuU_(N9{j8=1p=A|uK8GDnFJ zJ1y>#RdJkp_-h*_{e(D0vJy9hWScG=J+T|H+!b7?zi3|^;fL{bDVV1$(-5(Eah#zb zEqJJ8UFE7cvM=;C9&R`)L*it8Qf`k)CAs9E*@TnmHa25U+sJL;>DW0G z?%0}V44*$Aw`&Lz`J#R86i(7=#u46CVi5%dYas$oN=F~IP2qk%{2`~DQI@|&eT*4* zbWfD?Q>C0e!1}}|I4aC32T;7>q^7^aiFp@W?0=XSLk@Q4QQiA2Jv&nLpBczocL97m zU0Je!qTJ0xGsefXz^}=ACm>jj>kDO_n(qKSu(=ogCfzryx7eY(SE{M(FO~2=%TF!? z3dXrhmAXi{l0EOlXZv-a-_0%3`^f&Y|6y8bUfZB<&+u*NojLGKZHomgMQXUr9=*nh z7rrCwL&d4){%JkYJm{3_PE&njR(6~aRSF3gUJFFYdOMJD5T*V6Jd~8zb6eVQNS+Lf zdU8h-duhQTTaCC2F>iR_&S9C=?eS`DVQ3@6?d^#+NT&fjsc-1lKJjhH4*G?ydS*cSML=#kIKm;@$aM4I#QIa77Me=p56zOVwKp!OL*JLE6n zqndFHN8E*Z2{Y42n?o4yl|#`2)v#&a@#o(89urpnAT zn}KgKW~)Y?oo4>+)ChAHK4^TgrmC@yX*4DFW1k0+TcfUWOj{yzR=wXOpk)-S>)bmo zGL((gO@)Dq*0i-u8KvM%C@WqfL@b3Zb1i{8$aA_EQ#L2N9A-$A1u5^8#cyrj{MXF| z5H~JcxtEOL%uUybv5l_J@IW!Az2&h$S7;LC2U!ze!@{v z7<~2&L7SSqYq9{QR z4z{Z9f{w7eYnUnVk~x8lk*K$@wiN<{pe_1V2-r5>gLaTwnFxmJY~E_`u}|vv>Z<18 z>ro&z7=Ru6X3@cy9vz!Av+T!UL6=IkzU0LXdut$Kg{5xg@JmB(8Mn*()wCG36NWFk zO$~65O7Z(uYjf;s!SNa`omceZcI;r*v+*?5!Dp%LzMIFQhGykhZYE!BW;o3b>#fX?^{yeoqI$&2p6 z!l_rIi~qVgXOAw^r?y zs~PJG(Z?M$?x8wR(_0cz7)sL^ZBpt$lr}XkRG6LcjYrba4TNSAs&tejtmScN{zwM2 zHQv*6xc=Yzv{WsZP8-%uX~GLcFKagcPSi1{H8e_!i`Zvc@pQ0X=w5{-jc z5%`Ja-U~#z?btkHwY{$ zp&T*CV7gj0LKZ13b|JMNI?&?V&YfBk)HQ(NfgjPQk!WgTuqT&bbhMHqjiz|_lJ`N6 zWLxuY! z({F}^r1(|s%qqi5?L4VB3`HTv|Gx)9;|CP;MP%+-n<&8?_r%b8>Px1;fwab37mtqg zz6~sa4ySbOI&Y!ptM5CWvVF~&sS%Ojk7rYv@boMiLmEVzliR>9Vt0s5%Wuh6~cx|u-v9=!TQbTMbII8G$;&j@S^kE;%3G+==(4a4& z=pKbEZ8&-=3dvO%f`qVDwsz7}`TOr#o^Gxt+A8QTM~kT%mlnGegQDrNiFDYh?jkeH z!kK`%2@D@y^aYQ0l2g{_t2#yXL@u0Z&zXtsXdD&_rdUM41KwB!FG;p5q61is)<)u zgJ-*FZNcdL>fJyF=uQa1l)4!0P0;eIfBIc|lD5TJVn5n`fIV}#EovI6cN4OAU+!+? zUti3)8h8C#Z&23+cGXX?eH;0x^Z?n@HR#Zq;%eUQ=zoJ3-*#wr=Tw z!#|U15k+^a?h_=qHvDB!CR!YPjfQ+Q+62(S9J~G;fe~72vkF2*Y-mz&%9b&J6eAl- zF{+y1A%sz>a5A#z=2Q}1O>i1$iwp8)76YL)rQd`qAv%|2TWTBa*kJP9g3^IgF1o~{ z4TKwzM{58)-YDdlkTmSEXBpmus?=_LQkdhFW$N8|Ec}tsN2Mx?5em`?omlrO%U*NCZ$3G>{K6bH;Fp}M29~kpd zJd+Fx*y}P(AW>==hc`T0=uv+#sxW}GNG>C%D<0|l?Zyk+ei)TM`V=L^Mxm8#okk^! zW5vnoeHaUSYi$oi)qfD!=JIcE9U#Dk&@j)O za!7^J#@zZTb;sMeM<(NRuG@FDY7>uAgL_H4CXK;$FNu?>!|wNS`~64U2$HEf!}{_g z8h3iT$dj8U-P)4U#yD%ms@3DUlWylk&T?WaYx#(%#+DI+BZ0Q?fz=8~*@~|h#lp`2 zVs_n%-CeiHg532L_jdXOHFV#h93ndH@$S4`mvVRjdO;Jul-Pw{Ct&!!)X;2)lX(FgRPfsFei;2CK=W=!=u3?E0q(9U%}ExoqfXf}eYT z#9zp-di%2UQ-pN$EFLaXCrxea%GFV%4 z&KEz?9hv*zK)Gt`;3KUf#my$oLSuO>f1@~^HlT$RQ&kj0d^6L4?ZB1h{N1F2 z_p;wKG9^mVGbu|gshVQ !JMSR&z?hd!&>cD8I%hf=L$?fd3xFl)Ko?}C^L=7t@U zf3Q>7E4D4cc`rIL)67d~e4H`3eD~r?9!W@NJztj?VC?SrwQJ9Ah`}@!_pX*D1Z*(J zGJj}2!YUn6jbT*qcmV_4`t`ui*Q?A2qh`3Xbs_CQ2HJp9ePc__RZsK0WXfEw(WC`r zy`-#3<+w@YswAKs+SK`OMQUo23l-K=T}3w{_;_=MgzWfAV`UY>jmjhXFpjxqL$Y+g zfc1rA82$K|)Zn5zBbk7EZ*0$?Xy@K4N;8EGR*=3qjih%*x`G(r*?<{^rq#{BdMAw&Lo9kYulSs z`X#~SIL7ntS1>TxCKC};%B5rlmrqC1nwrv-3db3ZTLPjTeYDi`@#>j{{jF_^pN+!s zqwdM7<<~tTo3e#b<9=u*XwXXE?Y!$y&w#vYXL!DgH4>-ab2;lWnp3uAXZ3--SWtfI zj6wP85b^|uND|;Bb(zKt06IkKQ*2SaLU0O99EzPM#`U|F2Uhuj{&^IYBpV(Za zrt*LG09uU;pr1xWv63A={d<#$;_F}L9G&}qVHgo>`yX!D>^QYLw{tS)6Q6i)vI66ycLZLc2isrk0T!soqSiHz6rkyxOEBYPXIg-~ zq+t4ta{?7%BDv%~%JP>gl$QPa)D|wtNM6nYS08eyBmqb zife?u1Zg?hVq-?!I<*7b#qJx30Ud{=65574Y)C|s!-|JwKnxH#3u%J?Qm)Y4TQY6+ zwH@5(WRBigA(_QC_9Zz&0f`0?p*OJwb?9yt0W~cT;wE~R-%_V@hy^vN4^3^cT*=8wUzjeSw&n?ZXC~Ju zS|d;$70bN1CKw7cQ5XonFu~RrbjY=OSeB{Ow?EtW=i;8i>7}^R1J9_>%}tl}%);rH zufIQkQTNo6vn*SYKk4@l<6+!myW^>`;1|hIE5!ebr9S|I02vbJUFesg!O#@4t!=iP zh%xRk$=QL7+v~l)b$zGaUiofL#V$)IIO~g&rt~& zxeHbC?`DKjWD?b;q^V^0^3Dk9Rm8@Vkuk#`IsBR&U)yIlBbUyfD{K^CN*iD_aJLheCY-By@r zLvO@4gG}Tf+7v;0?#2Bg&cwoYTa|xON}Seg+pgo$$?9;2o)lsatZ_4Htp;TQP6CGG zCjx4CNmrbP*>HR26f=nMx<6H{N?Poq}P*X=;rZEo%X zVX-xx3%0q6fav8!@aq5$ujUwl3`-o!fd6b*meVYHLjT7`VbAPSs}p_j53_yG%}gZ_ z>Ezu%2f*~PrW}{}83^fTqJ94WRmW{)Y=6?UR@@39^1~pB*el7|Yj$#SL z^^M9w6t^YSu7$A4kPv0<6X#ZOo4gFQ?(vJrSN8&L0CN<*iDSXa)vhWKi8Ypd%e_r& zGu9Fm`Tzs5=+s)Q-*z?sb?(tg3#c3l0^Mybz6z|o`wR`!1Gy6e2rWbtgq!C*%<}m7 ze(==ft9rye>tZkEeabMB@@|T-VpOC-wkf5fL^}{8D71sPD4|ln?T?YHdl3z4pMV>X z{FF%8RvrQOrY?>cz?@}n4*)Ab)W6M7gdN-I&K@#hhr)NS2JxUUJ&uB-l*w>t&c=d|%wRBgtYC zR#Z4~Q5a)^yjlYslPx#xylE&-4RVA!TCK-D4~-Wm^!e@yLkz4`k`}PQ&H+osSd8EZ zIOjEw*ugkWkN6vrTQfP}-%#BT7IV1>q<#0|8!fJKC`Yl)R3rsgUZ|uw9c64tp%tvn z5FlN(=Ilo$m`tx$6{Sqx{{h8luvCHxS<)54c$NZK**{tSoTaPmBI>T8j9n&yNRmlj zBOx<5DSeBKix^j7JP_z$5g-U%gg>1A|Aodo4{ivo&KD>XXiP^6#Wdt0=RO!5X4*E& z@UdY8w9xgN7C{a}RES#ad;?JJO0gVv1Rm&q~GP?HHg5Lcim+*WlcarFliI}n?`HdVG(NHaIi+KbBfLHMXCfR|B0FUgtnZ60`9 z8N&wJ68^9aasxW+?TH8Y#TIfs*(9yh_FP_JCds(_bfQe4Hqhz=D;%gxbt*rLJdNG0 zd)|7&W$j2sW~(CK$hw{Y&V_+bWq(501hqU;N zNIDR&+G6u$Sp$fM0RxJVhasDkLaauxURW^OJ=@GKJ~g#+)5x&Y|5q-C;OA_*sRP^K z-OFvzZa65S_0|mXpy-DkK@uA_2Rrg=s6>4t z#ebmyBu!IEt;S{uqokcko4ewwkqiGrpWg`KpatYAUy0JmcCwtV5vDVl$Q_>dDp~iS z!S&MzjvaRLQKS_RWxm7pU{WXQpa`gsWE5WvJZ`P_LYpi< zG0@|xKwj(K(Yoi>i&iVDN+@%8b=>|*)(otTt@3qQJN?U0ZNHIB1tZqHS&wp{# zb&%7S#UUG2r5Sar9hiR(uQS3?*5A&?CV&LJ{R!c|ZcgLRG*Cz?{JZ!_2qcwi?=}GJ zH^#ux#N2#C2bvm{+35e=K5vD{Js)Dg{8*HVc+kL3j0g>b48~po{l&fz2A$BE3DOC? zix~(NW*!S_u%foKV(`f@66}Ph zB6VORk}hq)OjA_XobEFfjn300Ls6j?Si@AZmBbSuK)YI51yTQi2=P^DJiW(xhtf$VQ+?BIK*l_@08Xv5H(P^ewM}!G)CGSN0j%;H=wek= zPEzGJ6`s3Gjf=|-e-bm@A5CG_CaXIGdN0G+309hhY^Dtw*aJ_mh|t&rytp|C9+4vE zWAkh*R&WqoMfiftcXmxCDSQX*`gS*vEV`NYhM9Z}2UkJo0Ee2%}G;yj0d` zsAG?V7{47lv9|hrAUDMqKe)iUYkwZ~NAqbu)Oy0#I>rIR-je-_)~Z&~pX?$AA43Am zOWc1Bg7l?^p)Mb$W3%|a=5JO3n`~UaA>8!gM$S{;@IpMws>rDi)W;SQ7Fd{ifpSfxWS=3uHb2=|x7q$2P6oFp&K*VpT;b8!y!?OVszRs98I1yWg*jz-NChrQN%Q zCkut5cppWg5GGa6ow$I%8Tweeu)~6$7?R*;42IHaP!o-b66sj+BRl>Y9xxaQ%t!%66 zfppJfgF-NHc?N}U&&JN0ORL>MBvwfX%%EnL6RI61g0{1vG$HEFYt z+)0YnGOWRmmE>UW3bz zk;G{XX-k#rgjM;8%t7`F_Dr$pfdlTxpV<8475_fL^7{CQS=-uhvo+zn5v8ixjYFq) zG~8)u25?nDY$ZTrp>uknm(Mq)d$x$u=s~nPzKK{yh zTWudHdOLrq5FQ_j>?vr=?*cA%`u0Z!<4lwee6A2NsOT{z;SDBBKo>Q7Hl5+MS#^HZ zeN=^J*o?u!F*i8=jrZJJ0d()lzR~sNDd2w%HC5TM^Bstkog>I1@{6OpPYhoLcz&>w zVCIUnp`BE(+94M_Dz)e^>JKfQtZ7oPx%ar`9{?EBO6QJw6#j)CeX<)6NgtiW4cAw%yS!sYi(bZ}TR7cJ z+!n^Gm}j5107}<8I0|^q=_w}p4qyidae>yuY=T% zAl$xuXlD3Gx*3>XOYS}{NvNk#k$RC~X|5BAVmYoD6GB#YIYmZCM{(Hlyn7cAUqxbk zMatQIV{dfvDja?9&6;0Co<#8*S?4{rVuPCZf?WVHo{$kJ;1QAt5d@PsFh5ht03LXo z7i1ukM3kRET~jhuzDz)_RRNu8i(WYyQD}*?94`inXuBLWi@1$*Hb2TxR8HL>*y&Ik z1&_XvZyE(dpSp4V*b1QI4zxd*fx;I30*c@_3o%Qwo6iB}TeGz{~#6CQJrtFTHT9l_m#nK#g*n;0>zDJz>G&UHBk$LI&H(gzcE#s)hHKh+f@1+$iur z5Q#xGIHR1iauVSXe5&v2M#7li;nak)`Xb$5)xF4tcj*rlBe(zI9Dn=)WYexs-OJcrw+@kynEj6B7PadpLOd=u6v zrINwoJIUwQ=&5n{)O5DL^~N#m+wvRi?bK;(xW6S_idT5mPC?@bno6DKZ6sEyTkj+` zv^EY}45*wEt;3ma4Y7<>JBAcX1}530gMqjXRfPv{r~0NtOt}zsm=BlLoT-|$a`L-7 zx4b8+YB!-r>YzYi{ut^)XMLY36sPTfxoELYXXA*n>!AhN?Ukrd4s@3SC1G$;g_069 zT`tb2i11^@-_yp$!+RK&H2iZ%{Ys*dtK0WhMpBU7*a|&g$Wh<4T{wP)RfRuQALO*1gT^t|G)f+=G1bYiodt)pM;O`qQ`ADu;?GqmT}h_FcxeJPfGVtq9IDqEUrPkv zk=+OiZ~p6LVU7;K+^Cj&hD`MNV8Mrx^^qfihRdENHQM*}mJ_|U%?C%*iU5J)r$wcBy5?5CrhZC^4kB9{<3U}xcP5`ZkY21<- zEMKtpu?a(hH0@^6p{K--jgNPS`8{GpdF^RjiqHA)7Adq&$E`1?&coRuNK+u73T|!6 z4(TVLcU&HPW$?uwvAB~h@O@0Xy16bZWH~$6XIs;6RT3p*t^M;xJ00Vf^5m`%LGXGT z#mzGzoj0Xg%!WZu%>;1iv$;nCq3)*FP)W@6#Cc#qt3EbBDutps?N+QioolLq4e7rF zXYLjzN?}J?+_(OgA)9)lq*ra7$UqQj$bE^@#Pr4Pb2mZV5RRB_@!6UeGq_p=#_%}}dBVeay5RDK7BY5WdciPeYN_%Z2>ogRDZ=TYW|y)kL;X_cfKOwe|u4(hm%cJUfxQ!L}HWGRFCZleq333eXW{=R{M?Sh1aO zC6>w>S4DIfTbj2QT^gv!cO7T*70c@XYXOO+8)_@pi$e?18X0_)bg0a+JPG@E+uv`# zOM2vhNEABhKbMUceA7t=5bUMd@&|UUxJq}ecF{zeu!bpIxGzT^S2@*3#=E$lL)~S> z#KTE54svpxDRc4n%-dh^ExfL(V{!ST080J?5RG_=i~`_?{O0PR;K1eEH4Nk@M7}QR zdpCFY3;cyAyu{l;FAc%i;6EPzCjB6>xmtm(req5WZih9s{Op5B>Wp|+DEY5mV_Eun zl`v@DZbFXocECTk5w}7VE+y=48GL!!>Gx0-d4>C;(QQ?_ndD!TP&f(XM)RhR zI@K;pari%nBSozWxy^)aEnEr{_{u|5pj@f*H&8X7qul2QE@=5F&U9pb6bv&Q1yGm( zqbrF z61Jo`a7q0l0j1Q7wZmZP^lx5hvI@)Ift>oD(D5qeJnaR=b||h}eF!S=&*`y8fd=>G z!9Gz32YyyOs#Ox~(xGW9W~1|jy%)Zf`G+t?2O~IW$C|Oib{~S0>ogJ2SWo(Mix&yN zUJX8mgqLC}1E>Q?+J7cF4C%(dBzDecs(-0@`}MMiyBWt}&x-`f0PzeY+4k*V-^&sv zJ3kN3Xb57lktTP&IsfHtr%`39ij~<#!I!(z(@^owG!bJWh;~h=1ucrgyXSlojOGj^ z24jXm3MmUTX>Q>1@S-8d*hS$%N|F{bwu{I^B)5`QX?neaBW|mLy zyQ5FX>xoxBgMmi>EcS8+0R~ddPR2ih%$ymN=z^XFgau>7*aJd)lq{;XFy?ZrAg-s7VRO8TojEeRS=)+_23G!U!UV<4?^$V5{~RC zzUD-8MSa~U+wS8!kwSC@-fqHsU*n^=MRHJv_?&?Gq-AsHK#?;K`xi)D|u6 z8-0$9+qoNcD0Vi(*dWvrwhwl*Z!$>Z7PJp5u)_?NdJ*gc%?IUjI0ulO;q7P$TNMMx z{4P>2*2+a^Dh!>TF-`fN$nT3$dV=EVe4>Y(f`Qa1EA-;cM2oD??j6wRlj9%pj`EQ` zbD`-0``!()AIN$0q#`Rb6aWZcWb|3e^3S2BxT!t_DrPrV65}@Qm~MFNqjk}tIYD}t zy*NYylitvp(0QgBXwGxUOPiybI*o{q$7^F=zCjjwW68@_lrj|8@3CHi4=vAcMWJbb zh&DV62x?g0_M6(y+B2=8D={d6M6udLjX%De`!i}Bx;qTF7dDUvlp^yMv{oA%%?Ru;@xs5Ky z<>D`GjvswaqM4~NN41mfs~(GY|I25TFHjOtF(4~bT!*^qemChHLy3D`TdGKH8V?)L zlB(=hF{wM#?$;Y3ec6B$6~&!6Pj&U}S+@50Z#NPk_=G~)fgrNmOFFw+#eP(?dEygkO+$EV?w*2|w zVLFceuQ?3Tb24hoP7t)sL)W_>$)oO1p>+_`9|pV8$x{^*a*L>4IY`?!g94Grqi2vr z1Av4@dd4B#jm9BMBss%LYh2Z?>%ibn0V_Q7fah`q2c{UVC~>KGV&RJLcsF?Y#x&!U zJG4J8h!=>f{~JBg6y#29GC6FE-qr36h9$ri%r~w+a1IfR6=asn@VuBQ>QuV_(LIah zl+5ZRJy5^C*R?pH#<(f@y@6aWCjB3tIuLBGA`>@j6*&RxL*CAB9?N~xB#mWmPQWPT zzLxY2(D5EbAHM11m3AP&+L?gz4Q$=L#et$ zh17CEA)jcyLu;g@dKeeO(3V!JfnUQ@c$T~Dk9rPXY23u?_$KtOux{=#Ie-szY}5I~ zlSh*A6n1+p`y_;lTW$o}9ea3Kd>2)mZN5QHHHx^vTn0nf*KW0DspW1vore6M+<~`! z1{64Jei~Tv{dYioRRJKtWFunLPF3X%J>fFp%JPb|<{h+P9Mdu4b;RkExZ zO7IcGgAlI$LU=){?O8lrUF-ea03q+2Bl z*8_r?eiRAwW$x(vK&kGLxcQ{xd>D-J3H%dA!{M-7L0!9(-$a-om>^{yrw8c$B|%zl zwODMDH)=Fd!@VAO5&OQ`B5?(ptv)oBAlubhlhvXS5g|blnvRQ@p7oSOHyY6op_)%P z+6INEzk>uNo{nHkWZ>i(cU_&RhW(K1*HoV$iVvZWn9F%}!`Jv~Z8z@16SHAHc?!`8 zf72KJzjIzPI4EO;MFBx-0z5aQ3(~Rba%6o1S!Zc~%13re0sqONOT)aPC(&<8ZR)g3 zfg6|*H+9a}BbwfroNL3gRpGc5@#fWvA;2V6ua>xCiK+J8iX8?lhu~m5F@hj`YHbQy zDc?P%(m~EZ++!fojQMfX8M&({QW`+<+plDTS?GPM3PF!mm1O$U z9FzZSU-tchM#_e1Z5sVwr{Y(QA(xHb;(y_RqPASUUK~3oOe6!xf?xDxe*P&*-UDGt z#l(e^m|vdBF71aV*yJj^=(-xhDi+rd(}DQRx(=i0y{LH27`pO@R8Tc*=_!~4XIxa| zokVE&eC_>1^neg{3y#K93^)2)BzDsj3(7_Ket$d69Eb3iqL(maYF|U0H>+Gh&N8J7 z#oOk0@UXAVT(zPubor-~E{le$(f+4`{4{w7_;%=Gjz`N+jD%f3#PTBUaV|(WJIK3% z`D<1-fl*ZPp7B}Zs09=_z~FwS8GZAW|Mtv@WVGz%PmvG8|K$fvre#G2U7b@{g~MJ% z+*C4Xb??Sk60&4O^tu0`wgPz{2Go;};kVl{;;C}o){NyMZ8^Xab8QeHeTc)1Wf`~U z6qv%+p(Qg51B_Qne%Blj_3I>jxs}bhgi2s{7~Yg)PY7Uq@ua{am`G6QE_dqXwVSyP zY`1DLew=^uh8ldF-_$(6!R!7o2TP@#$^1UvyTcYp$KT$8yf1}fFTI94;(U59y(u;%yxf(I5e_Wlg*U5{2OIx{a1Js9G`Q2Avcn?36t;9Sgw?zzW zCrvB~VFtG$?H%Q+*-Nw4+kEkL0#Jjbz9C^Uk?Ami0>dMC#`xw*E%B1IS>x~3&icG2 zK1U%@IG(|QezG~;Ad)rDct6UtR#WA=6Pvb`(aW;OKTMza<>a81Jk{MB@BDeWn|N9< zTH@9*#T&^7_yD4V1l|*g&3jgp>V(-4N?dt-P|S#Ak9LAVA9?>+w80D`zViz1YJmV# zx6W}1ea32G6tD__C18;(2o$#1FaxvM)3REdBHPgefL-Q%32n_N3XDJjUpK07r)!Bc zzH2;zYMZnzGOk{?r`~)HTXf<|PaF-=cRk2Omkt!?HSl=%`j48*Y(ztSp$swhiOUJa zurHWbBUW5PyWZ>=@_Zeku4ok;K^>pZ*z#=XjChA9p(Mf=QYhXKz=zCIdw%h?cuz>IK|UjBQr&WYwY#VruY9$%vpfT&v~!-bWo zcUYV&0saaM@dDBm2jJAC{9_(*PL}OF?5=lou&Ss4gW&8uF+jFS6rt3#>yNMxh&*Y5 zs~|Ef-s$S|=qx(d0)?v8ABsr1PU@d+{O-7vv!|$kj+h_giNKD-&}Rh$zr*Lx7%116 zpQ?kArSSN?qB;PtX}qv=t!~!($eOAb^ixeH>afYX_@2dA^Uxpi9flDqH5dzS1IDfS zYunbEUtk<|#VNH@@PwKx&DU>|ov2y&hb_x@`w+}40mdB5dfHpLuhRM^GdGR2gwCldlW|JiOqi# zQkqw=;j^9>h>&$=giFWPn|0E%9vbTD67v4duVo6v?7mQ8lg#Y`iv!ACEKf;zr2L@` zjb81-DI*Vgb$fj2rs^zutP8c z;M_flys-~KV@JZnUc=pcR=XxYf0pi^qWp`=_fyyc$R7d5{SnX@r&}z@47QnZ3?>$U zam8Fs=*Duij~lNq?S~E|YqfO<_TQ{+n&AlNEyUL-Ua8*|>X9bGPzzAdKhb-88g3}* z5p%j-YGvD7KcU<=?HFE#_$RDtR8wT^MEw$iLK1@G>Hz^#Z21~CHyJASjVgWQ(++uf zVt9yAenx~>mjwMG4owIGjfps^xim+TpR4C`)Jqd3Kul@4kPViencT}WU6^7K8hOE& zhAF|lFoI1`D?kHKC*81^=z}V02T;EK)BkY_gpO_*DyXzjq8bj#FkO#f!qwOmjhIEZ ztWxlhk~j8G*k=*%9ol_g5;SOp$SoYaDP@84UMw9ID zTZwkznH+ zNIdi|Ys%rN>Z1?51K*23O7~;NwtR3&9fvfTEw7#MZRTd)^wsk>+qc!gPjquTH{|ym zE|w>!pMdtboZffRW_LVhx!pE$+bxPHQun9r7!RnjtFS8kDh)FdRa1N5*s2&@vH_x^ z$+VV3+!*y2TA|(6S9{}l@5);X3Zqb{@fQqZaE8^o!EongB;C?xoi$Gk@G2yfIT0X# zb^nUcT@z)xdB!5Co9%P_P$)twGyI>2&^~JL6bcR+6?J-y4B?c#9mOcaC?8`m(HR7>Cf00lr^IGx;SdPE(n*{`%o|u3<5^$Q#hu8Ph zXGbQ*ykE4_)ZxYJX#t{?n^NoBlv#Q~$NZHW?%f(@CG%?dthq**X`HedeuESy+2DGL(^*SgULar@*oh1~FBpiQ;VOdPX1)qBH_@4M(N-2jTPML2LE=%9dEf33i5)ndRb3O2$3I>O-qSj?R^v&P zonewkC$Fd-4jMN8s?C2?TJ#3^$3?QGS76uE=-o*%JY`grnO++mh`#H}Xuyg#9-ReS zDK}whe2lr>T)P)3Y~WKsNcP}(AGY~OT~QfnC!>p^>Tu#fn3JPas>;QJ+>;vs&c&S} z3J>)h)oPbfopa$mGyYO|hLf$n3tb$7^nkrjW@8<6OCbqBeeQ!8Vh8Ox971^I&9~OG ziZ*9jba-yfIB(!FSbEgYoVEvAws#1-vyX^8@b(qT6~Zj>!6eU}ads9Ji%~GMR?y)> z6cHw1)D{7e@<6JHk;Q9miF_&g_MID?#9lANMaGa=sS!Hh8-M*o;v~pXQ3mF-dNS50 z*UC=OxzP5uIG>ZY%_GT9_56YLpM(rkY78*--BO8i-rldr1tO%W(g0)8@FT;obUz9E zt2=qfM4yTZt=ChoNM0GXA&sM5iE0+#z>B)A9<8XZ838F$l4Pm#T!a&#cTQuGk{UY3 z!*lp@PPOzu97)8Sb{`qx$tE9rs;==LXC{Jp%2IaRpOOq1w=& z8g0YhBhi->8v@=Ag0vYRJ0qI?;U8s|j%eM2L_4}5j4h}^o7pN+ zyTXSXMM#nfQ_xXPlGiRMrQ^S(CGdzalm7Tx4MIfa!F@YlDc%W4hEds3(#7%lo5nCe z;076$JM=D@XIRb^|Kk)Saa?xY{JC%3xqd0yS~!Vxe2Yu^$pn_RV1~F5JP0j(__|6 z56~}2nIfVbO=))z%CbG4s?l3NB}_h)19+^ac7fEZR6r7q46QC4j_V>rZ0fe9v2zLO zDxcI6`TmY1&%!2ziTl^)JGcvnWO0Q2|uQIq0(oRO45Wl&W7xG zg}`A@gqQIO*IcFD>Fx0(vU(0$>$JEF-ui|SFzz0WiLUpn^ZqV}8}<&qy;dE?#$5ye zU&XXSO^!&orGSZcRq3kKOHy}YTQK}zrNm%x`0r=PZietGO{za{r^@nnDCD9R|BL@? zDGss>o#*vU_WpNG+O^{FEx3RRQ~XdL>5%I|Iwl$nx9~rESO{e-zHblCyeK0b=`J2# zBCUg-g8z3T?KG5UmQ$yOW<2VR@dHj|XP=x_8gxDP6vPj3xbbelB}HoE#GdQfm2V4v z5L&pzeyxEE{`D;_ztxWmUAEar9;~k&rPz=U!p;W#O4p4m7-Ne67cyu1x?t+E(pLK` z9f8W0boQw%dEzJ$I_(7;lg&j$Y8eHNIBg{SmcMk%97gOdt>QzApIB`cqK0>VHaqIm zAtzwt{BdzV+%_Q?nA##T27w!_^Tgz&nd!3uAyC8(0|*qe;!URR5V`Tsttn}{NOr6} z+X73=jAHvzjMi0ipIkYm{W0+`5n+;%U6YO=f!HIx!;srk?OUZqYm0;JTO|3Bsrg z)UNyZ^H@Um(*}6;vizr$Cerh%4O`vtvZ=52$7{FJ+#7H7j4l{L62IW2^n~r}QYg>rwTaB2Izq|!QD>7QcuXm8ej)!V$muFxEwDI2)tp&nmT_U zMP7%#+@*XBUagjOFOyKo=w{S{10fzc(rbtvyt%dL#6V0J#=QI1xrJKbHnD*`E$1=| zt*JVdkHZ%L^Nmrm7Xua!=v0I!p0yXUzSNcClol4f40V!WQN^Nb!eO{yKAT98y@WyL z90?fKF4eX|CGbD_~WKMM`NM&JhMlOsxNKC~w?-VZe(>k=Vb=Twj1TbU6BbRMxU?;DT{Gl4<{DP=mEqeDEltCY3>NNSknY zE=J}KI2rG+27bp3oS6@%-cJh{E$-|_kN z3eGXIDbMI3*fL-3$F($5we82klDhQW->(8hn;&XcmR<|KkM~(pHn8iFzk-@ORR@cf zeJqWCL4?FyIncS8GuFE=7E;4$Q2ATpNL28da3h3edb$+cU@5MinT|t8zK#|4>z3|j ztp?AbubU{Z8Cb1^x#IgBo%m?gBLAIzLJkR82ZomsZA9Oz-rAKca_- zP1=;uEFFj9h*$OuspPsPCW|%5NMtku@hlDHDN##T*N&#%tbkYv<5hIoISZZ9*){(y z&?KF;^u-(R$IX9<=;-z#Z%Y-Tk5PJowZGc0o&d_H)~^b>{7yr$bU8cw7Ma#VfqBx} zPB6N$Cm0wZ?Oq5J)?4vpGxx%@gXCB^vra|(^T&zGxP8w9IP%H%zEI-f(Gx@y>j4iL zJlAU;D$7wrn%WR8+ky5^n+~d&fmLL*Xt+d>s+~d9vZoSBNenuuSjKMPx3mCo7t=m4!7syHzo_Ky5X5)Ss z7>wi0`iI&+Pp(3Cy!}LBd|YgXoC7Bm-&bq{QIr0{qnS_(_P#C^^QHeP+GZ(LOmQMg z09)*_dQ^KWT@-z$R2gg!HL}=cL3m&A`as63>5i63<~?@1HQ;}R6Kn6t!HzZo@e^g_ zjI=RY$F;CT&Pq*S`imcH>T*=rrMZMN(>&ikVLP#GyPID&p=mArKuDBYrPb%ivJYZB zARQ$xpHd*C7SHa6XkaR+MVa~}OL%Hk&|cfpQ*z^+wW43j*FAYQ--{o9kid-?I25=N z+RH8OrMEFS*2881&lws9%A>&tAlHfzpI&ta6C$icEp5n-1Or5w5E2lk|T1jMhy~ObX%@B0J5@-m8 zSMdHoA#bUOlHvcoLv-w^L*x%iNEwde46y<;Cj`9S{v^}>Kj>=JdFg2#?KOm!%=mdqa=#y4N9lhX&(1Yu)o|`)Ulo)Zi1f!D(ytt zp%Z@<*hf9WX4PyjT7CksYFtfM%pjY52w2^=0-^~RR5gBulqlQ0DH80S0=>lxV{U5z zKe7E~a6ew3^eI_NHANlt=SQYtE{D2cl522Ug>j!9mAMm(PX(+&PA+TZx@fQnud#<6 zw5d3M>(8w?I^$BfWyl+`=~tjLY!|xbaVWLLh_<2XUg1LfeJiSjF_%T?iI@U4aAzDnZ90*=pP(0Q*l-aUZp=B%pTEdo82r%T!CG$l8rhQlR|CdG* z7fdm0zh|-pyI^yBnCsq2o{5I~$f9s>4Vuksezm&8L?vy6$VPtNF_`0sWnAhPvGzk7 z$UWaNKb^1JdNm_#vG!k$*=z3km10h;`SK@`JEpzLpBJ>nKqUt(#95^Ni9bl!1R6C z2U5oy${A$L+8~Wj0F6h|s@_?#6gH1GwJ3S}=7>b-oP*kB55V(k2{!Wbf9_B;vJ5)_ z9&NXZZq;jpIUxO{?t-IIh)$HqAzX}Sjs&&Qiy7D~8Gx>#He3jD z-TBkED`OLgh3C`c7nN%(s}7P>A={9PuLhb?5av`I zIk6x?LO*~JZLwbjpBh`(2lP)gF^Mgul2h!R74%KPCP~)7;wILXcT2F^4F3*Zao;XJ z0kdZu$|YfEupEQ#Uu5uwIP}=ufvX7rc2a1<8Mya6l72jsJp`!*p$JgBFyeqaW;&ou zFsjWF_@Vm~c6e__wnemg!5%<%&UE^Co5)<9`U7uC&f1CqKXMt7s?4kv$i%{TZB#|LVzjwf9Y7(f+`PE286h zayA1W|F4-R(wN|Ca_(SvOLnL0ok%*gsgpl0NyR*6gZYE_*dAk^o6jG299C;BILJ>LCmvqt(PAW|2x*0lbn8*0sqDB|BW6M`q7d-h3 z+ar*O=;1tQ1G4Up2;j(DtnX~D*^bAHZfh^i4zTS@%*we%Ws@!Je!R1Wa$4lhc1=$1n-jM#ok86T%Bn$8U zhf<7)LNl4l;H$cF$FC*6xk;2r5FE*tR*~Z3n|;B=bYIKK}NPL#*i?(y6e7bPb-n4 z#;Tsfg5)p-u)sy4`GOdbA=$L}*A%DoT%`Xb^cc(=Pr*buG8b)2!Sc>@<8r1`8myn7 zmyP;thL20fV3Z&XYMpv87i`{-#0k2z26ZVVV`DRDGAyU{na#)zsI{bxxl~K zIe923jT3$(tPb2k)E={+NL=B+_W~BcjxS`dY z9L+*gh@q{aNXWinu8yKp9VocYn5(mCq*w;-rGTa%KDf=bj*M4nr4}y+wR@t*!8Dg? zLr$ZR@!M-7@4MAa>q>Uj#f!3xL3d5S;O3UIczSDumeyaJ-=)YmMl~yBS)F7q&Niet zj+&NM_b!W3h_>_qUo*fMETZT&&X6A@j=RyMNGVFGoy=2pFWilyrLA0 zJv*|2yMoscS$7)3F&0F-@O7<^j+~s$ve5&WJZ&eG$Vw+-j#p?$ty0wMfX z@Q1%5*S8}Vn}tMv*>;ti8p}Ygew8<@WKt7fdq(R*PRUAEs7lenejw#5&ey0W=x6E+ zL3TsJp^{md;ZAq1GJPsPhz_b`RF9x>tCd_YBL$O0BJ1F%)bs#qBw}1^j&!w7iG7Re zc6G?u)|lTM1uF=i?bh;ecz0raAK|K7-hh&9%XZ5!e%vI1H7iA$iT$RohzV%aj#O5^ z-`##Wf{2#W@xA}_fO8L^q6}2o-yVldPNISBeH#&ZxcP92v>HZHp_7!(PCl%-;vPy+ z*E0o2biaSIQE`tHC*y@Iu|aq^1Z{z2}<=Loj2z206h-;57} z5o+b(;eH`Wp^JQ1l=e4iI|a~tv70-fTdjTKQmYq7x>CIore{mIDkA9( z-lJE@=5!ld*L>RZ5;R%D4{veSC@}}BZ7* zXrC%;E`J^53|A+AvyEQ=U)j}6OMSkJz7@%@Iu;y{6B!)9pw$kw&Fp>M>kHmAie&z9PBr^|U!oCJ%Q@i)QF#GUAwEYn%O>_3 z?OwtKnw;<qN6CI4;GU?nO@FQF0YYhf z!4B2)*!oc)1xvI2sBclNq7(fVKFmZy{W{9@ZhTn+dcvQP+*5RguNIwnaji6vt0bEf z@0AepF{h`hRu|unbIhDS7R*sJ6qDF7b?5&n@YKF+^S~W(KxU(qL4r|UVg_l|oj1YA zLKLSVboQ|D5{pqFsNBNGEj3OlqcKej4cneTH!TwE%;8401Nn)u*r-?c`Uf65Z5Qe! z@EV3{Z6V_206I;^AgsX+w+c_iA??5x@!IfC>S}l~HGkj3mCY}6@4`F4zGt56Y>)-$ z!MiV8B+gZ_RR0Svc3)9wj$SMS0;TOp6PS z2SYt#xd_!s9V2=)P)=Bk?8edXf1jl<2-^t%Lk{0 z^DkoNG)mCCr^eGzC5?il9+R-Bvm!mB*J*;UFeo4)BOoQgkaeJjt`#S7qw7lnq{khR zla{qJJ5z3gqe}*0Za<>l<;!%iY=&mw!YnhguIhTl9AE@6r$|qW3Q=|p#Mj_c$dC-qn?>menIOsJ+9C}d` z(!ygCBl*3+a4gaRKR`hQE&KhIq#*XFOb(o)Zp7i`nlgu9Y|veTDsT6_ivxIGTw@vo zqWI8EHRyvnnP~%VD9E*Z&E$U&->I_I3LdyQtfT-*OjDAzzmU;yU=#yNM3yU%{+wb{ zE(v7P-+r~txSb8BEXZ^2A!o=I?uD46@VEbQPDI6H=jO-k7BFYkox9z)m>Zn0TWi~A zv`@7#N#MeSx__+gi*!H>JKs|No2usqD0+Um4>W7{T(wQrf6H6fs@1!LN4)sJfM_+T zfJqZAGu=BE_Y{m8tmYgPp!hpLGDXaNsp>S@!7yyqwm@haJ3ZmE7IBEEhk&DBar&3T z*#*nvjepESUiCuhoH1xRXz6rylaC+r4WW}JJRFG80IBX|_gi2ygm;;sQmQ=(%2NWE zdF(sR$O6716CPuD{$8Hx37UUGwg5^3Hp-((MNu~~&?^IY+S4l!j@7ME?vpvnUnSEA zQhIAX$4VvSk$rndY^7nFtfK9`<&VOA73Q7>w6C}7C_8CpgO z0|@WCp&SngZ%1IxtN;YbFNNcYsKdS7QQ}^P82*u(@)EBztoo@0=cfR=tAJvaEA|Sg zZ;t};DeZo2#uij?civ<346oF3qRQ}DBTFN__+x%38fPz0+T7eB1({geckchSwqw3L zatQTO`%1)v$h(ssOOt){>xf>YsA8poLxP`Ct!=x71L}EJ15~x~)WDQGKULxi(O%$v zUQxKpf4Ii>8qwBW1`Ble0&;a;%I~8~uRt}RFXv)LhsvYis5ahg@=oxogLr6LZQa7u z`=B`|?_vSSl?N6jHp_{Er&iN?;>QZw&#MX?i=3yO1LU;S$aSzEMda8RwM=yOEgRNl z`$AB2Odj$~u3r>8ZR{Cfl*dVge4~S(x89MN-y{&wD4}Bpm?|aZcjlu~8bnUS{sQW^ zjKX@NWw*-scHc;@N=~BK6>vhb{qeHJW*-I2ND9sVrQ#H_7DdgAdj2;>XRM%Eg&hP| zW0ZBXdI-;sCkFel|5BJfhmU-#Lv2F;s@+ft;{&7p&_DifAH^R%2{pi7Xac6$9hqHd_GNkbP2{o4^BkxnA4P|CEP9T@yJ_sY_0{OnToXB}uyDe$ zsQYq&%5r6u-1dp!Qd%pMb=Uc8kAjo@{<4?!ilMDo@CYJ25fpNH-2lEYpFx8{|K>4# zy`UF`nw&nTkeciUBO>-f%D>Xd4?AUQ{EZert;2MPaF^@dAB`q6FBrkaA>?t(@P3vJ5JJVNuMcS2@RFj|mDQs};{w=iFI7{&M1ITq3|@QD}RtZmQDm2aBo z*gT{$c6)>kz38wY~l zedZG^ugzOaFn4EjOE8M3Z~QS{Zy}xm5<4gC&Pe~rK<0$+4l?ahh(i!S++eTSOE4nW zvtva#`LjEyacLTmn;$D4+3SWeVUA`!Q8P26R}k zgZBcK8mBs86?*-%88C*BQtCPHf!CG+K)AM4YoSYG8Ejtsz2dR>UM_3G@j&qbnln^WCO3=UdMAW8;;YrqZz*^~1w z4AlHzRu&0Tcy%8klkW>7jRI}PBSy0WuXd%ikr-_PwC(TimXb@iUUUi7rdf-}FtZxs zIzH85Z6NFh!IDx&{RgR2ZMjY-1W;a@HrAOz)~=bPmGDnI;MqN*_9#U!4*4w`|#2m{?sK`aoQ zPR4|o{`8TOy{d*G{=-TiLxj~yu7x4lb?!|-?Ku_{V&)kip`5;CR$+bSfeCD+ZC5V& zN@0kk0pgKNSS_IL$n8#u1_pF^Fw(?0oM`@AF*qJQSajrD!N}tq zA`5W0OX)OWe>Cs-W)Bq=CIVL}d&dIQ=4f5C7jyCYy{?A{)Nz&q}%3PCWJ`;q zI8_0ve3lz|7;D|C|MCFQ29D5f)P*1=76Pw`7M)|lf0RKy(!OBXVhh@KAX!Pfk(2V} zY@iFZw^hAA48bPF{1qX9s=E%_CK<+JpGAl(9X&{gmTy>DEc#adYt8>wb(;~~ zkg8i>Qh_^$P5O|wgAg=-%Cd2d#TPW2Fupj8(vB~H!C7+pJb$x-#f}3>_6~uSqv60r zfTodYUIKvO2pgn(l8*4B-8oZ~qCL=eJ3rdd0=2 zsq!Hh+AqFfJ%2cK?CYW8Oe}$w?_4M2KFjZUtC3sGz?zt`(yYRkJ2Bh9CPTk9ZbO5L zboUuTn|?FxE>D}?0AFXqjZPTg!#iF&<5m4A=@)~!t_@m=7%@Cp(!gV(MDqfRt57e}N|j zo=!DgX;Q_p=OgH89fQhVC}ErCm35MQjBaA-5wkOpgv3z)wztFISsS`9Mii7ACUwQT z?O+A$dIZC}xYI+qRVOpgr0F#duJ`^y#@%3#TdilvjUk1Bf~SvNPvL#-&?AT4=KgB< zstAgIHyLokR_dZ79Drqhod7uxSZ8LhN&+8qi~2hUUR(axf#l`sLY52vsr;vlJ^HAB zVz;4l76D2l{4kE4%cH4$3VBGSJbM(QLUs&NUOkwo%aMPH3leF)pIhag3oGF_Egf&O zZ$V!}6}T-Zbc6l}H=cEmpasNcfgGFmOCV8C_mmse9K|4iBYC@`NXJeP!e_t~{ljou zzmLP826{;sqZIP*)*&V7VY@H;$8QDs(xOXugf?RzZ+~w> z$>?ki2h){K65w8L(Oe46x4e%S-n+Y=^()}}`nPpflG`+A@~O#aka>v?JF1k~vrY`1 zT~YPp+<<6=p5swtfHf6wT~0&OM!;9%{ZEA&;H)NB9_CyKa=+P>Ly0*TFZ|)bQt`6d z_A9*rqHLarqraUYCgF=PHWJI*HL9Sss@yV%gl(XJ7*T9IasG=<&pkPp^{MH1s$S#hBrvn{B{E)i5jP?UCB z)QAC)yn4@9v4nSJg>-Bfp|?GWMQ+ z=^F7Y2?!E0@fDwRzYqz?;@St=3+=B3+(kKoL zVQkvJz#5?Xo!q#j$K@W@Vy8xiNM%&YMC0X+pmEBf5eW-{9fy$bqP3M{c&PlEZI>o` zjV~t5N7`41$ub)_05PdtvBvwX@m&t~1enCobA3G<^LFV^9=ucq<1X+;d_!$e6j=YG zy~(fC+(0Vd2(eZNFa&%LfQJ^$@Z2!?DrWaFEhsUhc8WPj0$b@BP~NyVOD-F2A!Yp5 z+uz0hX3II0imFM854nh<>s88_;t?ZzBh(dclJiuho+Xv4Ixu@F$s2QzF%i8*fBF3; zuM}SmV&-O$120*K2xg4xPthg-lZ8MMVR@?jX^?Z>O?HIqg+mL$s!N@f9oG?`{kusR z21Jg6lO9<6a(zd7v%XzY1y+Yp!e1^#WxNMIikS_188WPsy@B0f?hrUdM+Gk2c!XaE zQ)^HjFE>P9>P9UE7$PK zfDPPij{zsdhCkLvbzLO|doB2XAx4GltvbCthvsLKn`fJnBbb3?b1bR?BSN6w@s7J^&(kD426ongyzh1u0a>Xnh$ugr7rup^ zCoE2n?Uy4?t5|W>fC1k}s?t&!L*s{9DD77jJ3zVmpBaj$Tx zcR8DAK|Wb~r87REXAE5BdsTd0-nyN-%#*!DL~P|}#@%CR*#_V}w1@^b zDRTK17SsqaPb6J5kCKw0-^@cl-o%-kNhg*?2-!{ z$nq9&x=c;IHGF91jZEgGgBe52<Hnz^9NjPA${^Qd$yK5(-j58{Y370y@ z5dqFIgIda%Z9Ho*_w|2Ri94j50drmxi%yU!_tG~+iwgfX7=h~{NS;Z!kCvRb<$@Id&>fmycn-2prlL-9keY(X-PwxH#G6;AN)V#uox4#=laS8**#3_3MBMnFr;NugO`qPIw*KSooO>zn;gL`n))s zQp>S`dEimLM{wamCo+TC_?@0mk;5$EqTYe2UkdLYZwoo{z$E|Op1>y+d-?|I2wGV% zGKpIGNHe4UGr;U}%e}fMK@xVOceTEWZD1YxgGX^6%e3(hgg6WHZ|;+dI2DQLD-qvv zr#4^aq$p+YnLL!TvsvFj+}?ThzJhNojKe{y1TolRWEtOF>xf%JO@$$um!YtYlM1rA z0}Jk04r9R$?)SaABta-JoL5U9!_ke(-I8Fohb@Ftb?0e!AqCv1!KzMfRL}0foaiR-JX7f51;$)L*(M<4` z%pMu(=E1n7#BJlW5J>?{9&|*6E2A?FlcCVV02>YEwLoI2_X*)agvi9-wUIvw*ZEHloGQSf&-4;XNQsBKM&72l!%|OWBZtAfX zkXahILnSi8vWmZtNyqQRsVVZJ%3Bm*h;JDj_f;3{tC+-**6`xTJ&>(>mvh@WUx8V} z2{7x2c+MP=?tDtW0jo4hk-_JLa7Br>w{meC@}RsblrqI=8>PK zZq|bU#Z{&nxeeUSMo_9U)bdZ*A<|w>TR21xgHV<@5I{JTa)0a$;I~58uYznEHni`> zyyp<4EFbV`drK)HP9spJPR62Q@PAT5x6r}RS645#+^lLPlKu9E3sh&JgS zDGP>PZVe<{$#MM>^R!g%5mxXuQWgiMt;e=+h&u_Wk^blvaKwIf=_tMV&t-FF*Y&GC?iknqKO2mFC zFC%y(l3~mJtiLzwrszIm{B#|n7`d%|1+rf98=94a??a?&la}k$)D(rWzGp+8Mc(zs z(Abx=W{#cYQAs-cG?wxdK=ZtDUdVpj{VrH9FzH+Rb^)yd;0ovd*iE`XM5Ap&AIAOD zJax_GL&K|gE)zjE=Qm0eI!KQYa)_6{gV+ zz-cQ4V218HhzxcQQ?MGvlqZe8UZ*jtG3@5OI2;KHIjoV9lF|$at5^JwMhn0sEde3s zU@JIFDP5)Ipt;w`Sp!JkVoqx|S=Kb>;tcEdm^ed|A%kGy(v*ZU( zmjRSm?%byiRODviLI+5S{CtwJHHDJh{v6ke3h#J9FQ>*WCePNuaK7TK$1YN!^YU{ zXo5`+-}i@IY52YZBGQVSigqZKZ@A*zhR+XCOJRIB+vi>XdZaaDTayGv&r@3#g3%DAr*2AVRu?HgF15z6ygQpQdvr>}{RJqYtH zg6((2m%*rj5~b#YM#)KOYvK6Q=o|X(AYg7RXNjt|_zA?-21>)P9%Gkq7@%^jG8m6j zzE*3a7PbJ_sZ7A|B&~ zKV9~YB;Maq6#}Lh#hmtMdW4G2QHuz`z+E1}RtU5fpV$YITe>^rp3MuGVDnnrFoU-( zW^9!**quYQehOD@jh4PE4(~XR8VLZ0t%6Y{*bF4|Sj4 zyNhsm;)V1(vAf}W8)dqh2F5q)O^6(AYgV)?Pei&DVt_4xhEdRix#_E~5z(R`CzH7{ z%+NgnEhLzS$4M1Ai@G837sH4clCL(?dBZFPJR`cfQ0%btA-!o+BL2Yo8=Tnah1#!O zXnFy`+Z0jd35B_$iM~yynV3K)OMgTXnIDmB{2dE*$ZT=080*iCo{{|XDg7?cFS(g* z0TXIkSYh8f=&CI#gf~YnvAVv48WQ1S<~&{|25%}kcR)q^Z!iNhh`xmkf7I17f~`PxK~j3|f<-32SI+_vBX z1-2RW!oJ_fe6d{iRea3BG)3>K!j}L(Qsa&pWLHK!k`m~V7*=E&`=Nq%b$<)0DRT5H zKML!#z+IZZb=M+(N&(iH!wTIiMMc_9Ld+?t6{r>^OxIbWN<>4SOZDM+vbYcXshR-N zym`3hE)ZDfeEm7oMti7fp3WA{>y!Ry&P8qVwmGP*Y!M8Mp1e`4O>W;AaO}LML3lQV zN;R#W5*DLr1n}%kL(iK(maAI7#*R;Emh~Pj(FJx72rg=L_C&mR;)7@|vf0ZV-ri85 zQQgD5?IGxW-K)QrTVaIX+~k_-QS5!xrZ45^3`6n8fNswSTzQh^p^Z|%`4W?6&Ea}J z{nWGU>r2hB$DwPieK5;e3VylqUbAkkv+`NYV}1jRLD1;F80`ehN^sSeGC+-xH1eb^ zxBB&K>8FcEA@=LtU^jQooH32TI4Tn6|4IUNn@Ei5tba$!`+o(#b+3}_r>1F&fz2!; zvhp%Z3zcRV!)QTM)BWBK>L<#Yah2nmagJ zRn|ld62yU$mm#&6<6UnpZ_;U*UXaS~6sIVPT(tAQAS%S~k}hrqK95a{4#$+r%rPUQv#MO0pmXO>}4Cw!w>Vjpk|MjWh@ zP>;ow^XEvMIyL^~(9v>DWn_QU=7260AJd(_2X8LO(1Zzs=1BkiMXzJZ=jHJ=uBc^d zQ+YO3V%P1-Ywap(+2|2WjW>$iM#|-c?5XP|#@SPcFobJis#6oZ+-R^XCui>}k2Y_~N)$+1w|47IYh%v^FS#mbsowywsRu9w zj3s8o)f5ShSL6PK%MPa6fnw4QCdHYL*UDXX%Gd^|CTV&7a-K)a8H>LKz^c7W&|gj( z5qnob7$~{^v!o|W*z%*NJQhnrNWh%w8m{=ihpQ^kso|&m2--?&PIhEq zh7A)HzQ{XZ?0Mm^#!$fugXox`HRG9mIn6`^ZK3KZ^x$(+$6#bkMyuw{4is4%0Y;P?BagK_J$kk5i23TYmNCS1-a9V6Qpw<$pR{Z(k!0$g zw@8%j+6bj%0NRu%=T>Guc+i;0cQUhGeAXsMT=(glQ8ywRr9i;#*g3g%k2{AZfpY4e zxxT=$Maut4F-5ML=xZhq*#IKxR-q;g1jSm_*oh>_3cKqt>9<+_W9IB%5p-*)js6#H z4%Y=o(ARbnCBe9+H$g)o3)qPntZpa^Qq7<)>QQM_S&N;SG;Nbo(ni_on4P~lOzqAh z$%*O*$?n7cA&rWNqRf8MDH+#xpnZ@262;c|osHJ2C|yZJZ6HMk+lNq`m#6v#@~O4d zxfw%SHEP2#W2>#r&<&jY2Y(vRQ`(8Xe5-`}o*4jRfj+hUeHSW;@QUzA-^3;^Pk%}1 z`;OT5ICp(Bv_BWQX!=^)<9ku?d8RPv{)aO}6ZZV%4#nM7reuOPRq$7pGOA z;=Jc-rJ2+$lUEO^hezULNqH$m{e~i0e`b18D3-L7Xa7agJSREtDs!a8P)U`dvwC-h znIcV*dempbPI*^sELg5v zSfL1Hy3QyU38Ajj$s75u&sa>CbRRPgYuIZ~eTfCB=T?47B06)<;PyQZ203#LgrntO3?VFi?K>VC-7aTH=}<1QG4z zCTFara)25lVyiIM0zchF-$NS|-?4B4yL2XEb&Grn%|dIs{)rg*!;ni8=$d4)jtPDR z+CxY#`4SeZe@M2r(zOOG(w%q{y!u*|Gh7m9fD4b~x9EGu1d@`j z+Zb$=Nq6#pZ`Atv1d3K$!|jLpz3p0?!ez`x+pg+h*8=#!K6wBUH;{{CpZ_9pI`1rv zu~Fn)bkMjrr{~zH6Qwaov)YkaFVzza~3vbnXYP##K z>pK}}DrZ(p(>on>Ts}yVZo`T&Je;g=r%5Gu39peNIVH5Dq&~AYkr~8lcyTv&OY;Tu zd%d1)(B4mkIZ!*Bu1%*#w_^Be#~VOAOW1NHc*9YjD@bt^MkTB z*+#WR=f58OW5I=~tQdnIw^Zq6=Q<%_{b7lit#dUK+`E=A^O(McD+8ChlGSSz1hp!9 zzsR8<2^YQDf~6`jW*3l}O5Ss4A!82y&8mH6<>g%Es;#Pb9pJG(i<1ttAL|M;&1^py zp0P{p+)XjGqRwkSx%JCfQ!P}Pc{;rD4`}FHLvCxT)7fcCl9W4o=6L%uv$?@vhhH?o z>v#*&ey>?f71R@B#&1M<1Ic1P2yFGs01~_S-Vl7@wvaR?k3oj~xAN(*8h+boy`5-- z_FJL)sP^=QJhUy!Nj!h`^%n#KX~tL6L;gq-+l-HJCShIx-8Ux$L#hj~9&*H;o#lxN zv6AP%`I7U0xzs_!pA`5vqCh|Z?d%U}&Am`V@JZ8*bIH7I8E`xW&*&-ovqJVKCsC`j z4A)nt;dD~*RnAak2kknn=)T!QKFq<{<%qafym@I0ybKX31GI&dhH4fK`dCik4$R`y zji%EkVxSxb-1+G6AFytGmqdW6SzS8>q`Xb^MZL6h*UWP}+=*?>7q9Np;|6{vA6Iq} z61TBtq%8#EtGx0SgRMfhet7(~Fn)=#j5-{Kr{ zb{Z~u=k8&*@@{~_)DC4SqOR4#7rjQ9P>(YX8=^GErhS=`l3@67FZx6EdhLeTi-y8H zloeOGG<;XRl}y_ofn;msZ|~@<4vw^mC=nUNZw0ekV{^~i7pIeHRks~L5J9bLN*cDO zA=aP#i`pMT4KF9z3E4K33B1`p(#{=|yqrzhxH7yMe!?KB%e12keIVrz*C6f4LU8X~ zbXwy4-6c$CE&00u7-YmQWA6=y>YDWs&k_cs-P>+ofUsoM+y=@c9xE|*tPY!YTLNRR z#Tsjd58zBWrKPUM3RP%bDGqISU^Gc9r17LSRwva^&QR)Obaqtxg%$c5=7PNo*hGI- z#tw9Pf0YKA6fEKF5kTU|`R*STCOo2TL@mmXJocH+cNQ`d+O~DSbn;uBrYF#>iw!5j zZmEaQf!@(DB;!>9*>w8X3TG6t<+48GvZ;O`2|jW2#B^dIJSrtYADwPOzw<*`f1cmq zzZ0{7=AsN{JHbXiyDM+?oZ7dA=E!tWa$)?n^!@6=RUEF(SidT8ExmyAvE!kj>@8fc zexZ1xwY+#l#64W7f@fgM(SEXehQ|}OYVJySg}_&2ev(H>-5W5$2YZHpKZ>w^&MGAm zTO7{5I-tZS&psx{>P}2{WT*TZmbX4tmy-?I{=iXZREoSB(JYy1oHfNL@g!A3bSJa} zT<;fZR{UMcKwC^`S#h%^SrzA?_Nw~u37Ao8aEf)oWx8S^qERM2&;?)Q+us4(lxxPy zlknxb{Gz9G{6NF=6E}E&A5AWv?q)eLDxmBpdV9W2oz}>3Q~U>@0fZzSQR=_YAnM`x zVZ85PCB@h&T|L?kds&h{^Gj*wgKefLRYP1kam8J5xVvG(Zq^vlZw7sL1JJkG%d=w; zO&_4pPhMq@4N2-8Vx{LJ?Rxwdh9%Jeshx9PA~KFLCFwju0kZld+`tJ}){F7BJf=p_ zk1g-Zu`4BG2RLUGw9e37=RP+K&8=`d?J;-!;6k+A)}TnO7rJl=nu3P~_%jc*kDs!D z;DsU@Fqm=!;auzp2M!3`5b+L9I+S~j-xaYD9B}bKjKjsK7aCtgV|!bqx_%TCz%jL4 z*7*@|QaHL3bntWuw>=YDf_5PL?m9J*#3<2Gy>S^zu~eQk%at_AD{@w^#-H?LXRXxM zzMVa%1A!>Guk`6%EB{4H(wR-6fb!Jglaz+gkfE|C;)awAoiO^=Rj?s8xF1mMZ|*Io_`0XG{HF`UTSGdunf^4MT*t z_ky{2$Q!%(+Rn(>)o+}$6t_^zJ?YmasoY1O4%ga!C+lzikU4_inADWU_Eoxf-?PD^ zIcPfxGV``L@KV^BmCVTPHl;A5bz1+GJ|QU2oa*`rB}(_ca|sE|uAXq-}< z=-9&!rF>j83^aF*fq`fHf$um%Lt*^eg2k9+IlNZ!ZO>?Wa&YWEO+tbMxa|}!GB#wz zLY7wb>G)xExlUsXe#ds;-(K)2Ss+BrPxmy%{R%Ri18T`7%yLG>?adnYXsi`|7@YD( zM-cn%e6ysKZna1Z-zMS!2#3hTFLNwMDrzojDuJunVsk;JMBy!nY^*EMn$MPQRl&{w zFq!rwQ;e(3AOISYi`^6Mve^^d8)wrRDU2}rD9#G^!abizwuHW3T(4QXO%dJJOhbVZD(jf6T(b>)&h%L_5My!3(NP*Jw3 zJArzp9HJ8?r5C)j?Koq5R4G6m0JJk#L;`l)grR1&W6F@@b9tpO>ey{S8e{X%g*W&3 z!#2Fr=sJQLae~y6j4ekb1lAj|Rrrkpk|1|0DSlePI8frKs%h~AXF}U7tAZ}04$~2O zMen!ErZkzn^Uj+RjA?ETX%14tAVK794Os!R6r@Gf?=3tLO_Y>Ya3^GKktJOov&e$X z=zy}Q_<%JyRGXvSdVlU3tE6L!W~#i$&)?XAVW~lBzNBs5UXzp@vk8@|TmnK_Vv^s~ zUE2I!3@c1B3JCi|HgzX`jKuXy%&3bfb^2D;oE^rs!I+t5!o(mn-B$*CMp$`HyMa6X)Id?+a@mV*B`DpGa3s33!Vx#jXZ>YB+dZ1R+l1=>>QS+LItu{80|hvIJ@H=-(Xi;FFFzvRKvK9MDLiMo zCeRDnQ95+qGV^eh3hn<8SxH>lX%YJG$8UZ)P~{$EYTqX4hTZ|a(2@*&e~jip{ThAR zn}2@8_e?IjVJPQYM+Q1n_RKqhy`riLgk}5=p4hMB`9lWOMSa#|?>3#m&c+D^iInkA zAy^;q*L{ag1<3S!@R3@8Gyy;Gxf%6x3ki+H%C+s{Lx1rf>kBvW)pqxIb||XFA}`{W zMKa>5M;?#+57)2Q8G=?pT%+bG-BP=l)dNUb^(l2cyKIhf#lQuPI3g(OU-J)##*pEq zeoKs8xwI2tJ+!Ug)u}nu=GXptGQwE8j@|qMRfGfr%#kea4Cf{hNqdzPHltZY&iJah z=9EXJVM(Vb9a{q&9KzXwSj^nWE;6`LibZ{zzAm=pz}tcKgF~H10m^w;nURGQ|_h!W;!NV`*=D*G_8>FcFcEtsfH#60JjWg2m_d%VUUG}%p1wr z$g$}{ck(+q|C=m@vc@u?1CPLNor=)~c{|rD*)5@I1$>__fbP>J$6y!mX%85FnE1KK zwDFagD1v*QRA4bngsy-{fxn6YG_w|aSAV{v4i6(+Dl&b=VsD=cXr$`Y;g8}WBeIo5 z^U5R111LcmE;{f&nt;BZ{Rrv@E6R>XH1Mu6{$r(w(`_+((KWA@3CZ?cPJc9(bje5u zfc52ZFXoQG0#;#*vmat=MWi|r0nx*Wh~((JNi$y{a76gS~@9{`%U&bRx-)YZO}drkmnojO*oL9aM0pUl@L z2|JC>9_QgXC`NzkI%w78*=5$7=UAtt;i6>e+UG}b8Z|2J&ebg3tZYARo>Mr-5Kt`+ z=Nj)x0GH!EyjyDaD8&{_t!8p8Bz#Ph?g)QjmwI6oG=Q;$%0aRQckS%7FrEn* zE}u&X`bHNg7kl+R{0XI(V#rdr!CN%(io%MqyR9RrZa@DIsIZudSkMVYE3e<8Gn;(- zGkz8`j?#wAO~wdaF@M|TdFkv|J53IQ9pzS&$dn|T&Tx^~T`nk4*P&bHwJ!0sJ=vCg zwPwes+`3{tK7f4np0 zjzjiktT-=!E@Z*-z6Dk$(PyuIMf-qOI9gBu(tvG+`z^L1aDPWX z0dT~XRT)lEwDlAg0#A5vjj_QQ{{-x|mszSQ-)qAQ+vVP1Dvk6^!YEb2o$hy$$J@Yj zyefl{sDIj)qXPeuqwo-nGzMyEPh&u73g$wpnj|Ai0G;U0w)}ktb%8In;+tFwKaKc< zX_7du6jvTLlQZI*0UE$s#ESqYJ$320+iACk^zH5)RgXE)QYW5#CgT*6be%SZWmM0> zrv+2=eiQK8(6pvmB4*dhue>%Luf>#^9T*qmp0`qM_R_%Mll*{4m;ddvm1b2~?~TVK zdwLx%6w-YVXXYTT^`@4^_L-OJdajz^%v2y!TSI32S(h73Y!XBD-G{SUI6X2}(5>CE zxWAy)aqcZ4Bp0kWeOK1bh1xoXK+f|1aFL6Yydu<%6S9o*L>3(GSl&jVRj9o;2 z?zWmi)%m-u7$pF6mJ2c1PG{Wn&&oF6X}mh68b`pGx#1a$ebmeh@yvx(RB5{S>V%CX zhA53^Lj^FkJt#fAvRur%adG?)UQexf)WhLdUHTHNB;2Ne8H!m#U15zlmT zbQhvV({3s;KO&2*y}K_okwg}^v%&84GZOJm7xS$OZjVJ72C5=@9k-s#O1E@wlvK(Z zgdtFRX1i*CWZ8Gpp8;L9zabU_d@LF@5~9Y)({&b3Be$1Ny)!;4GBbN<;kk0w5`B1* zSZpJCHnl=FR4d58(it=Vo^aRQJ!)hRN(4>WHcaX4I}h}izRMuJ00X_;uHl&SSvJch z$M$5MueFfSJ-Ch5jL``hI(a#qp3{{SRa-obz{sm|DF=paQ6%Sxn2rmrQUj8tNK7`j{OxZ;m+@}B6ZL?P~N#r|r$ zfp}YmR!!tiE(YqY*mGd}F4<-X0;G+HdND52#<>0Nt&F8rSgoyC(1h8bKAf?MaDeU? z9DIB`>?dM_ef59T{ki6a+d2?HOb;C)P+lD+YG}FcPMZP zpW4rrS$1%={ZY7|5-v3 zlOpZ9&$*eS#uvbcF4#3-*h9}T#ELGTkL|{!@0-1%h4Kcg4k5bBf>Je~vm&PK??Nh)+@3&_i>Oi8kx43=p`b3-nl-hSZ9W{q zXtL2qa;Ak$pS45m=vmQtMX&F@BX6T4>F{mET&A`5@%C?dPIPRq1W;fADh`PAk8-XT z;?iz5;AtWyU1&0Ak6m|uo@R28f=)#3fa)R@2~$a*U^Bnq2`>-C3LjMeJblb+F?7$! zoa}vGct$%eLpGhTLTxch=P-fT(_QPZYlohG?5PN6xA+*JiJjdH_tiS`fVrc~6O zAg|iKI0hUBubN<}*4CVXtDPD7U#YZtu9-!1f-o6iEUlv|g@#dY@dFC)vsKj!^9;?I z^l*tvDfYAzll`EbHJq5_P-XI@9faCF0K|UqsfHc^;v}_t4W(huN=9>&Gh378yS%cvT7kcCkQ~s0Kp)4vg!c6f>(_>;i|tib0WOLjGGnnAyRK zHh4h&BRxCzUJo5RIw?N61fNz^k6dh|jbma#9y8MdDhz@#@pHK@gG(atin-~t(X>Rz z?n`NrgXr}w=fQo;4My?TVN{lZ}XtI#Tl$dYi-%q z5RHc}u#!$NhnY8{pVEKkhqxLYfOTR>XV^V#H!Ovz4E>jvVVeu`+n|$P;jzLg(#NqV zMD%vLSS#zdZye#W*EtqinWuy#mb4n9U4a-df&(`oO3BVqqKH2P+KutSO5GY`(F_u4 zDBi-as(!|(#xCXU(l)64c5VNY+nxeo*#>!erd@<`aM#5`DP?5}M&-{EB=4`-H`8f8 z+_r5m<+yUKQowc*ji$)8(nZ<{pz?l%>|yxK<&>M$i#%Z1l?Yp>-)Ct-53OfvAZyhx z;C=gj$lz%Fx&S3B70H;?w^%A{>_9PE9yhT@{Tq_*(dTuXBtp%-u}ab9{avS2wZn8A zfi0%IIf+V0mQvN_2kj?HgWx*AW1lL=3yPHFo|uGFT}TZWTQ<&xkS9kjR&xs~kjH9F ze=xiV+1?sYGgTQn*Q*p1_HxyZHl4?S`r=f9esam zHL-hVFX02}YzI)OP`5n!Rwn~Nyp|p~to%ME&&y*k!^s+TBu}-Iy)=e$A$nlUeWnIs z@+%I?3OVg*k%EIer>Yy30qwE+vuY8-vC*j7I`TGa^n1RUVJW55=^9IL5Nr5FS_sOu z*gD8k`6WL?e?U6&9E+(eVgpslXA@yoJ=D6cy)Nu%!BCA_YSSdUgrdX*6n{bEd_&ER za$6B;XH`k)lWQM0Odtyks*!@J+B&|OvYQ~gcbtkFff!-ZRlFSpt?U1ZJ#v`7SE+Iy z)}z$9e%6C|`rN@GvPl3BTU?x#eI(N-DB=zFd_M)I5gK)mhbGJ^akGwHwP1EgG#e#( zWLy@og~IbETepZcsu2ZR;Et-W=R|~2d<1}b@GxM%D(DH{^WC9VCqCv3-JMC z02-fv8Il#pb^lG%2!y1;s?D1&!uUJ=z+8GjUkSFc+cda7$w@3y%4Gmd4r?HD;ilUc}$}Pl^g2?AOf7$5yD&x0d^t z*7_oYQ7G5yLyyUJ`95g;9!81`)H?~^iq75vfvfG!fusL3NM)ZPkd;I7C$fg$-h;wH z?Q_&S*B>I}DHLl~Co?XX)TmSe=(Bh(lvdoFMOZrRZ&u{gIjlM+(h^`noz!h^e4o3M zeBNe?hS4r85?&PQiW9VlYkj6NhqZqdj_&l5nCTQcZ_{>!+&9O%e>c%6-Uf)N4R`Cd z&*4f5((=r_nnw6CBSIz(@&h+)OmTJOF$^nRpPXKqj-?Lq@6?;4Y4zl<+^i`;jvyUc zb*S-F3)byMZ)PpNwSGyVL7?ewZ>5k25yIh`PR@FE{vt#gi_nf&`nXUBffKf5c!V;r z6XK6B$Z_!n`_vlmiG##c{hdn|=Ys66Z=EWj}&UidNYJpdqP|8CK3WBXeN$M4!PM|;36 zq8|vd_jPq?vJ=~N`}-*y<`;sEd9Z4c%q}roSz#PIpP?3BeXU;hRyr=x_pHg$q+H$p zfW#>3J9$2i=r<=^ci2&A6W*lx-QN!V{_`$U0;OMT+O_w~fvA}Iiu2lI`A|$k;=tx^d+z=($_VNrnOC6bu{`I4YtS zG$+nRbu{M`O>5X|%8qSEp?DP(iFqmIM!BupVY%{Z8Xc{m&pjfX1|y5%?!+t!(a+_e zI&-}m!|7%PcbUnL-E2}~P}2}*m5`g$#1NZTU8Tl~{j@7u<&}e}%?Q;CFaOP;!|}es zoF|e_{-+6iBtUMd&DWcupK1KPSyjT^awiO4PG$0t3i=W7AF-5Fl_hf`lL?1(nbK!L z>c7Utm+iOvr>UtYWsU!6HXDY@Ap&#k!Zl`sUebf@O;C%MLyZYBH$_ld0A=-wg8a^n zkwdjyBj6E?t+xBFuubz?z%8cEHL`BX@$$+j$Z_2_E2jze?2@~9kDSfBQn3Y_OdWTz ziI}smeE(k+OwmWPL%Lk5u5E?J-bc+REzT03RgoJxe)}FaSEFA@MPKl=EYuMJos-;_ zN<^S$zcqFu9Zo9mB4J*(UTf?sjxzu19UZSxE(_LMl~$Z&&0ZTtC40XY$Csk_Gv20xXqaPkCIqMx(E{F#QwSD21BWSn9s=U|qIV)2AQ1GAkJJLQ=!5vUytX~)!FWmhlY z^drmf{W8)7RgVMAuyC*Q_2x#6)%t4#%;c()T1Gsh9&eiK7Se|RhwLKj#nn#S7h@y^ zYeL+(f2M1V0HTS&fOO}mX_P?X7^L}c*4L2kb_jQjUPS+=%~~^>y<-1rWa1YG_sVB7 zeC*6YM9aFP&0)yTichFr0gDhr$3{mMcmLxxk2?f21<;AN15@K}jVef$mxUzlrR2ghgOg6VouRdPuP*zH$2}G9}0BsIjfH4bX(Nm)~Z2 z7H4MNjWg^0Kd7k-AUpF?etz9;o8nX8s2{uevR1FLZ5f91MH^K;8uHl^NDBFS7*#tt z42jWZ=K30US`vNvokSCOzk|g~Kh3X1` zITzHVw`-~cfarWK7?vj81Vt(T@j=SLRzbY$UssDgA#MD`1>F%F&a~PS-ur-<^qDgC zQxCpHVoE3KXuu_f{gWs7h2qt#1cF@Sril-aIOJ+K`s!q;Z-7#oJ^u1=I@2@1;J{o< zs5znr_n&e54t4yQ&xk(;fbt_CKl{|aZ-T-l^Q0Hs%Q`N z!1a+%->~|9hkK-^qce&IZA75#z?rt9?2opvTHsF+HY+$`HY0-+5X9x3VD-QzegN5N zv4H>>ku)Flx}(CAO~_8;wXO*bsdMi#$rF5oOp#yy&)Q}KFWNR!+FR|fdl6S4!=mWt zzllJxziH?l#`ye&^m;3Jh1gk0tHz8}ok$LxG9O94{7&sXz)Vx!@adg_D#r1A^`euI z{ckvfn(UkOvem%*L4I)Z^|p#v0e2GHNY80di-Gn#U|_-IUBV3woLYxsXmDq*s|!%_#a6MqR$g57=@>_y*?KvF@zlL9OD$-e92C| z%z231I_Qxn7sDu`%FKMcq4UEIcRe4@(>g}J>Q)SLnt7kMUPF-7@kJ>B1=47w zpE^#nG?XtZrNAFIrQ@V{gUvIkSqf&rngkPV=dD3zBFbMU`g`O~^V`)ad+@ip{bp4_zfROPv#7koW`JpQScQI4-ukc%(uuh~Yac+sv}OD0NklVj z?*;bNvBPj9$FA1yh<$ZT8RfiMeUZaan_ao*)+hMyCMvIeN%9od4UdH`W9NRsLi%b> zaW2c_`8Xv!LG8m0Xm(#kl1r9!ji=9%q!>$$>2V1Mdu$Sd58r;uQND1Ob?zJVL(A<6ug@z~6N_7Be5^JL8r}qQSMy$ERR}ZCjMo?W?&)`0 zjZDm(8?0+ge=3XWW52w4YcJ2kXUjGmbvlU@86nDGkhqAQ7@7OD4-#KRu*Y@CS=Tl% zON_PYIVm$m1FeNZofpmW^Qwfhr^{`(7Ec&OyFc+h*ywI#7C2(GheH*G7?6@G>L%36 zS9(L~R^Y-7oljB*Vp!Y!o$V_6tl28CRakhAn)_mU)T60@m7gTJXRe?IA8au~sbW2(D)f?qf}JBCR5FHD2u z8By~Nk@s)$O~0A44UVb~p-eOx6+d=| zSYFZTzF&Js*uK47CA5Ezm3J`+2{hpu|Kxx#syYk>=aS8&H!>MDWa@7{&D-^vf)&`& zxohsm2#DQC0&pi5sR*X$I#?Xn;C%Ys4fpwyqGivi+{h=S-hU(yES(9I+9`$aoX@`Q zLytm2<1?pd* zCio)=qou!Wz@QH>vdv-#2}NnVu+w&!H)?U0NpPOU%G?0|LleJrE7~R@7z!oQ{fmR0 zc`Fbak|}C`V9JolUbUQJrlXm%W9@lf;?*ge*S{}(KAH?oM>6iZv`5mH?JL!lckNIwjdA{v$ zVq}k$miKhr)A8@K1*X^JgVa?zK~ye*xLGo#hQ{W^6Kq?ztGUU4yBF0XUmYD(4$u?- z=)A=F2b;bKQ5Z!=Q;~mMAx?1ark>m_n!pAQ{lO6Qa6oO*h+?RI6MN{T->|6Cl%w55 zDTr)VS2_!U6mU2P$EUIkadX&_bW>GG?D_ zJvs#jOuwC8aa zOOadQi+q(tz&C69s{BwGjEZ@pvsBU zQ}T1{?ffv6Jq|r?4J-sVSfYtn_-B&N!k&)}Zvavnf~%c3f_CN@{))JW5=?N!gC|^s z96kT({- zmMfZWL>{gctzTS1Y|P*?LrKx?iSI&uIfSpDg~6d!vKaWaC?;^ez;|`jD;Txf3iiek zjoow6#IJ1`EX{n_^jof&`(LAO#4@SEP4Y~G{qdfvSzrcC$v;6>J?$&v3Ki6ffTQg= zMU^uFZf1gvX$20u!!!2?76YP&L)>A?0t zK4Q+4s1q?yuY>udS-t}BWkgo=x)#|n$(R_q^me`o>Adr;RbS~yNZ3U3^{1sIznhkb zk*#YftOMu4aom(?=Y={zkvN%=2Bs%IG&R4fNzu`Q}n(a;8Yk)>SA`O%-qihhS_ z84Ri67VN~^^o_c39_-hD0PpT7kx%2SZ#r=2%7$UtyC=c^w1NSL`t745!PPtgG=||w zBeU8-ijnT>okEG~vXp!tC6@@)FD$seK@=m^2nd=FzG?G$6IdPyB0*1LoM?`P-G#lr z(gYFB1=s9&`ZMBO$+i%%1eW6;IOO3_mu3*!50W!H#X-hYMGi^8w|GS_^V$|MefX{` zko5Mo<@MIH=L>7+3H`(tcTbMM)DgJsv%27(a++^-Ll^aQa(g(JqPGHpRPC_g*4hh~ z6ptyD1v>Xdp)wm3c{y1O5*uW!PP4#HR@EBHIc{Y{N|I_%NGZ7B=)S-g)2u_8qnivh zuiRxbJV>&jn78FPF}%7iRcE2%C70v>&SAy^+Pm-%plRigOban^GKFU9$#vamKFw`? zj&L+&tiLH3^RibkTd8vq5+iINQ!B;oN=olOlW%hgI^MHlR?u+z2LjarKgTtFWQpE= zW15W4?%28)WGCH~xXb&6#Hu@2IU@KrqjLo4?%>P_BT$4mT=FK4GFDWUo@WMGSjKe2 zBw*$^@theQw%Z%{?P$PBV++^I$uNJml6DmtVS|^+8FwE5Mk@eA^p*16l#w;gH)v(L zcJA}KRF_$}>|~H23x>6fQs&1$<(OM&$OxBR@5%8#Zy8If8=#YQjxD$WXzF5LS`U_?o|LhTrg< z#`*XAvz^qn=Pm0jv=#>Ct980Uq#CL3P$5o+5TdSONR^Q%T``}C?ayTQ=&PGE1;G4ES&slO6{44 zDO+iyz)|5|Abj?Fug3#7Yuuc~B~2?UI*PEBB}0FV>2MAM9(>$3`q|WJk-3aG`YpI9 zUNaw^&fd!UXRU}h3R+bBmnj+x`JDtdsubRFTFtUEGK~TyF9u#$b9&1MiP3v>KRNnP zqOi*2`t-s2_^B4f&p907Ds!JTVcOGFb;C1^s`kO%H1lG~S$#45=!W#GZ<}1l(60K7 zFFfw2BYh*|U*+Q6I+FXqsRu5KSrw!a!moTl*ZYDR5w61y+QG08cSid1OU+{gD2o45 zyCB$U!*67v zRM&d~xX96`PxXS0Pph%w?Z$cqAVF8}Ql!Qr=YNXi`x)o#pU@QE!TJ@Io&d5&2M8RE zVZ~p!@e+-u8VRDRa#WM9JQLL;xn`T7G!STOT@U-z>|TXG;D5b<-SS%@S!=d3hs~l% zyE|dZUl6fMAbEg1AGCe;6k%ye5Mq5OistzFOTGqTkhd~^i3~>KWdgoQ8iyC(#m&7T z)5_C$68l<40(FsC>Iv$UifqQGRjco6XK<-9L12~7`K58F%gRgj9LiVRjXeRC2IFP+*T%+et!N`MM=o26n%D%?VY%V7iej6uD%Uhe<>DsrxG7;|IWNvB& z4|OI?f4aVa={0)C!P6ORAY+L@a~*YDzg~=ZmTof5B}LxeyaR(QPIfK%{O}u8LVPe= zjlGs^3?XhB=WWN4HTX@-vHeNyn4tRoRjLe*c<6VVWl~+c6WBQMv}7!u<4MHhHt(_1 z$Pg5g=<5ZYC-I8~y~eNj*BtTs8emj{IolTwQmI$A)qqclL)@bpa>H@4m*wCHvN~`5 zu^)bIzu0_Mxnr?WZNijc;tz)!i&zNS>>P4ep4oq`#X^vg-*9(%l*+{T zfCnDH+>qHY6~B?-A2zR02g@Gi1Ow{fjonqUCedQ5$RwyJz?*FJaq6_7`$CCre}%oU z8@**Q6*nW&H;E*B*H1C0sPVZ<9j(JJ$J{&i{2ejafhO;tvU8ZoHa*g8b7fdU7D&3rWoYp%>iXK6&kyBFj-l{7$L6k-R0u zn`m%`_PFA6rCIh~uJ(gQMkf~YS2F+sECj8`Uvflp^5n72bnv%w{z~=c=9wZ_7Di)= zxJ?SUdX^W}W=s1jk?eNoc+&2)+*$RZLggf6kW71Em1C%N`Cs;Q6m0OTQ{T>qG3Idh z6?Fit{vfCg8JEkmC|?XUZnt2R>kixLzQT*o^;%H7)^bJngMf7f*O^_JPw*A3WuMmi zS=1jjNL0I1{c-&ML4d1OSK*KM{h6!Y*voByzu^E3;0_5)Gq|xilJH`8OOrnOsHJw= z8gmjDlqow(Mg)k%X!gtW463|})7FX}&zdB!`5yPuc!4D1B7hwIoG`%=KpisplZ2o2 zh-Dv6xR}Y9Y^9JF{~i8X(98;OcH(=i7)Xeq4bQp|VI<~3JTuEC)l+R0U>Crqh;+gZ zo2K{ZV@-IRF@0q$yD*sLwD^r*JG(HZwR=++RAaMBcGO!z=ReQPH5T>QBM)F-?ny!I zSWS1XVX_f^n3^JLFCFsWFL%e$-%b>8$7+5IBxHHkGfoWM|7AOQIKwiti3xv(ulns` z*DF}od#c|1HUmi5zxOGz{Oq}OJ>;uE2*z!y9)95ZjS(HfV%2s?q@pAUtpPsJ`yDg0GSgnr6oUq7MxX>6Y}b_U+iRg1@+25X zGHjZ|LA%(X1QmqO-4O#BR@P5(7F=c_vtM9v?}~0scPk%$qpV8LVt2PY&!lK)I>E_o zW0DO11P= zt=4??SuT{a+Sx9)!a&v|GjcAN^GYNK?;E@ok$QNFCXk zP_R;h0E{b)PhPM-t`twW5Db$Fuul4mXuxX}OMe039X?sV+ z&tqsmzd|V)F$^X95mmI*1w%&G={N^1)esNSxC%5|K!r?mH1Rqe_sMN2)u$=g(F-O* zPCd{Rf5at9DO_`*QCm!|Fyt+u7bgQ~HKu;P zSQYS`&m;Q!qt6pfYD@Y>R>EpxRZLNEr~$J>w=tloObhut&bcrJzo)&GvnFs854DBhSeSS6dE-2i)=-Gw;QTFdqJk zEyEl_MFH}>n_fH>=|TmN#Z?uK;Z39v%+tx24R&^1?dUhwWplcEgPcogm~^dldFuxY zwALJvRO4+mi7-e6#UTXm{^`3#;uQzrs^^@O^$FHFXnP~&C59YBs{PF?Cn79K6Ee(h z7N+p>2HPGZN$R}*&@#_sQm13wZRrLX< zdArAAzR@#39WAfG6TZW^Ba;p9!?$^s$eGmZEt6&CY!Lpyy2Nv=A5x^|#2CM6Z>&?b z6R0@-oUAjqReaeqk_l^j$hwKdDz`k!grRlAt%s{Kx0?v)d1blVNGgX(Rh<-9%|07RQ7D{Esu2u0 zEg{SHX>R5sh$ZgmJ!_1&4J6ByZiKIs^|f!B_Az0?w|0V%(>uh3UnBab4ypjt3-xvf z-g+4pYWvpSJO;i8js##R`Z0aldraI99PmjMcBI`3u^h_aNCHzY9nrlX(ZQ>mGp zjU$BWsavZn03HN4z4UIhV*M$kn4YV>Uf z`^zF1pZ~N5w~$0CD_EH#;T~LzCS_-1xl#9?m{y+|`t;fiIn`;4$7W!JB@5!mdO{9f*@pg+$p%Dy>M7x#7?P0|LmIHmpRO%c%^STZ?i8b z03^G3%_kvlN3LUyhF!`dteP*~FSg_+L-j3s+%dehHgilSdlsN!$ni|RoK8lJ()tA- zu_vl|QbZF~t?ZWV@CGRAGKL$%DOyA6;QdXF2;shcS3izX_Jm?HkslIgFAyu$6WCWaw z)i!)5s6E?TCzf|Q<*Sm$H&Yl=T;9&VL{UGfJ-!1*y&={V{lVNf_i(;SLty8K?)Zg9 zl`O>pDa{#MlX-pSv>=~rp@Nv1>$Sp7pgyUI)>|};K!Z8Pk(M;Jd=nJ9~tb@<{E@#wnsEz${NdoSOL{Ax8 zxGMp9vNXv%R-}m^^py<7Gt}myMxOUgB$PIEXRyC_N(zQc>dNNXL{)plnnQWd!(toa zf2n*U`4eSAVAF4Hjf1hBZgY}Wll112`Qqv?gdj}BG|~3#(U64O$`g?1{!^| zyOe+9;+Au1LdssrSVxV5W=pd*KYwk6cd{c$F3YJg%GCO|!d(OZc}q(!f!4^V0#Ntx zlDz6C+An^EKc*0oMmz(t;{Ro?wnCpCilQd)LlDwt*E2Wz12H zFKi;we;)sC0>@nmu;!{B*mA|ZV%$tWY2`2ikIcf1BzWGCR9^P)@dbVP7d;CZX@azU z-^A?)bwGgv0|3y7y)ql~mvD$P?`%4YoAn-oA!{0v$h!f^`4+AWIi}~p?{-HbSUreU za_y?q3+e?p;HDUmFeL>VmJ(^NGGYa31&PoQb({1f{)tr|yvApiU)31!M#b+oJQyZi zR`oF1lVPKzR`p$5`?dTQuFdk3~8hv@jyXbXG9qV1^C)vnMpFWitA0fh$03D z7ZfO+*qGiUm{?H2*~#qAPeICVTO`m-l(!cG0p1%J>_-Dm# zWc16Nb%Nx`<+=&uOTVaxweEjN@B+~we%BJjsOq5n%J_+4WGmndw3E^Zc~sz z1*os-{GQYPUwAOTw*baw8Ug0O&>z9F5Zu68xj=WWD!GldGYiQT}B<4h=a zI%!%)_%jOZu-cxCP6?CKB^0h@Igzvz!^}rNhCbM-XSq>K$rKmp1c-8SLD8wxx_QLv zAF0rxSI_oR={5TMo56Sj2o_vO-pemPE|5R_O#c!X0`K}O?>e12-Yl-5ZxnJ!))vF7 zD9Z%wN<;r##oSJ?dqAGjTu_@BOW+KnvpV|4p;ZVv{schI_w6<|?dqA=D|ubYnyNEt zNM&TM*oct{oln)J&K0bfKVSFOYbwgQ9~~rNu>Q88RV~Zhw-6}`US-loyHCALaNAYj zrY?qxJFd%)gX~p|A5i%eZ7G0*24bl>&+psAy2TH#ZF=u-Q{#Y|8JOJp zN?^l%ITJM_F+satuLypeBFWo2gT^`x%Mzwa9G%#Um(YJ<#BDqshpdb^zF$*%`KM>a zpVE4(R>4`kh`k<9Xp;`sr2WjzbM#Z7)Dz0}gxj6#M?yKcbgKJu6UnBhweNyp=x~_- z95`{^oO;vqy4-A3m?oK{z@O`UVw^-wXl||#9mNwH^v4{#s#ne9A0p)pn%rNdav|9w z=H{qsi>&7Ol<+dO5Ei7R$Z-#pEVv{-(X}d9-BVoK7j<_xoXbY|p%<=dxK&89NSuzY z<@r?^f8CkuO+WN1#dL4{4bnF?02xU5zkm(T{9?mGwCwMmHH$gAqbPqDTSHj!O4jg} z=*3taRR^9fJm}b$g~iuJ`#g@3Nu znKguANCcflO8Md+$saaJ^>TL`+H)Z|9@q!A*boevE|*+SNFw4#n&W=N_N|23TqBAg z{kLL%kqxsXnj6qJs8gx&4Hr4A_dPIFl;B2gpqwMApeq>fxsP}(WHeqK)rK9x62l0- z{`isc#G+j?k5!9=7y=cUnJ8dzY1h!C$M8a_L3*T7jx=Z#BN1i`ZMb};Vk{?kOJWLU zzFPHu(n|3|5+fIxN>kAvC+DQ___8Ybpcv^XJH)`i_fC57S20EeN|^%wk-7;b!2odfs#v>TJs3 z^JeTDW3cU!5imMpITuSoeu5m4$USSqRn;bHtBz+}phVc)^N|)jN>UNoB}NP~n$JDa zQYsLspi7btx)zQU;iO9E`S;VeTiDhJYY#(oE}V!heyhoo;yS@daqaNbJSuBi$|C5X zaaY z(VlRZ0MX4~IS{40q8YZps<6=oB%Jk8tmJX$VG7+2;%S5)Dm{ImmrM!XX|XsCmr@4E zK?}}U{BgO{rky(x+?hf8*aUIf*#ViOlM}AXYH`w}szSw$BxLs+o(yx-p z%X$9K`-yqz2yPHjwwKD7aU6&y;FG{eF#g_M#U9~AKHi)GP!8qAs`y3>$gC5fn!;3 zmvhgnYBV17g zZZ#*nRO?h;6YhcLS>_wLhq$T%ae_=Yd*EqOhSE}4vE?ywaW0&e3L5?6>68Y57z0dq zj4b)(Vx>z*QCt6rhp(z>cWaiPnA0*T={QWFrzb+9Q3?S|a3^PZ3fLI24~Y=fqH-$H zL$I$z?H-GIzMbjde-?X6>1UQ{VHDM#HYS!S!-gI5z+B_sCN+c-2;CGW_39RIfE9TB zx0+i4DRiXa=L0kAT=kp!fmIaK_u};OUt2d4`btqE`>+fK&QJ{sY4BJ`5O-}J-;Wp2g{-UN zZ5d_=M;Cum@pGK&VC{@YmK|zu!3SnVCuFtg?a9BJ^I=kL0P0fs%z?fmX=|tpHv|oH zXB>T9^=?&x*YrBnnF)8ldHurmV7O&?$yo?cTMt5c>0dZZcy z%FYEZZ|mPkaT3TSlawJMs~+^qE<%JGx2o;Q4mQ|*!0Zpz;kD-_x2_1y;*7d5KyrWw z3S73{qga@ioQ-7>yi}+U_;;?w-}79q2d#@+$~t3gvB*qoJx!;B!2aTU)R{~l)m)By#vR4gE;5ym> zR7IoPQ5I2E=x(?!-)KNC8C&HVt2E3UidrUB6Y9%%IH4YMzTM1;8Q}6W=~mReB-xNa znCaZMJgSSW4(6iROk$Fx3KP_PXkR^l?EB)%7^8F&O>F3<%~>u6-^XP^%~aH|c5`iD z7+}qFQnJb`xw#=bQ|Qm|rK2^=J2&`5LJeZz3Z06q<4^(rKJM5dGR|tr3pdKVrgqs5 z0v_Us9(>Gy&;Z#9%am71pHgBSbxs?iC4sN zswRe$`)F@f^7&a$dLqXOnoAhou&)un}QbGMa1d#3)0~g zNa~jl31FE8HXVhjKRV7%>g@{}N9ZMG>B+xWe<&fJpT|EDYU4X2j`h_JKvsee2`^*ytv-gKL+x@S2Q!|qLw#Bo~sC=C$=+jf;R(f zebPf_*m<)yyjNb)h5NiN7877a4Ei@-FAhnw*&Kg6L0H_8vBM5h=6d^OpLkYGuXP3dnN?f-*Z-k^@03nL z?cw4J;>Xdz((z);3Dj7XtOez})g0-jS1+(XkocZ{gHvyg_|eqBe)@#5s>y zYg)q;%WRmfqltXdE)-YcYutXR3zbpO0KMKB=2}N%+BB)5bGE$HeEAb6^jDfzTP(%YQVAr4VvMf!x7HQOe; zknfDY>>R)FN>a>S;xT=YYFiM0;nJnRV*fssNDJbwRt}S5y*o0H8UXbUA;_WpQ3vBm zt4wi*L%+DPNo^R0uoehCn%MzfeAzMbamZy3GT$(MzqgDyg&)B~zU=Vbh$T9*%u6Ib z#@&)v9rVu~5-*p+z;&LHSQ|MHZSOdGb0_Q(fLA6szQ)1YM?pJ%SkJi>spt3TU`}lY zjfms2(?ynSb6xK zjz(66kbp`?82M;)S9?6<*!&1}e&0yGT^>Ai;ki&DiXzcJJ`KRgmT}#VaxnH3M#)8? z3`gV|s~PZSCar8n%-vBljC^D9yb-`1b3boHS}EUeSR<_R7?}6)bfcIscRg=~9?{Qu zCRAf5D1$d;%1ml6uTrZ5$pbX~rXT_aeX6C;Y}O}1%*20h?hJ&BL~|TmycHEW-V1$D z!9RZG(jA>4Po26XpU$Gq75md4doW0zcc?fD&^K;53OyWNV45Dh?=E*t#0064u&hLb9W_$v9F@{|{ZsiN7VHU1RMbGbn znV3Zz9)qu%qz$U*g^ewct%!#!8mge@)>Oro|0{|(Y}kEC>)TSqjKsShwm(L`EH6%0O4aRbi@mo$bZ3T0bXTVpFd40c%>5f<;@V0| z57xm@^>7MiWAjlSwunKk!Q;m}(v~**ke3RwF&D)4c5Lm4ZE}GfYubsJk`0IWfya1W z_}50h&nm+;6T9gkIJ!LCFBB`)wWf6D5g=^%GSk_W7%P?Gh&biqR*i$-eHCo^_wGcG zjK9MGcXl|8P(A2QgrOa~b(jOyWY@7l74|(W!rs;ZJ#@YQYX`4+SWP{=ynw5nd^EQy zl$c^<;kokuzTho9IW&DuI%35zqTpQrW=cE@%`_e@886}!KbnB_1d;P~BTx;svE~ol z|D2Z16PjShTCz&T4{cVJQOB2x;28D1^->ijVEc(C2xe&uTDei07;7Qd!GgQAbT_eB zZj_(gH^fBRdBZK19anFN)Cj^wyC$%Mj)%0uL*cdr;PzUb`C1AyN9llnfVd#MY!nt~ z-i#D<=>czN{wg*B3PFMf9o9PtDM};~P+T-0T2ta<)a}adR|F*gmcVPgR37@*-jjmN z$;IyJryjtQM9+}>;ti4LW`HjqjeI+#GSgRSfKTp8J6cc;Iu03<3>XFHk%Z}#_l6?W zyqx-0ZB1p5N)c@;4!g6Ogo@f=I}r}zK?1JDI?S1qI=KKON>=6 zb7#OlPlA4~a96u;7+O^G)fV-JTtXT~_l1r$Iv^U>O&)l63Q#E_BC*BHwaRg*Ul?Wk zd6f#aLgpzW)6mSsvq9%r_=nL?#5~bEvS3-gbqU^`!t&4^8)`nC4^N~DO7c49!O;vR zL}K+!+vtxmsM!@i3Z^#3ccr4dTDw4J6(1S1$HXKT{)Y>wp>d~AojQT+JIOtOBv-qlJO-V90j#$yhTiXM{B^1}&nL zFBc$TFjbP5tlwX+!4;LP@Us)+G=bmwj7X9vRu(nS27SW3f6I*I26|$f8=mv?C5*QA zFcKB4Qky?-eiXBE)N{NqtSkeM1f=^q#S|9hRL1Sw@cc@N&@Om|x>!RrF+3N6!@q(k>|gkm-cu628T+yB$DM$xD9k>`Yb)K=Xl@9a%JK; z^h)Vv*rIKFSPABgPrEf<5PPfV5|O| z+{IJE2I57M*$Dk#m8rY+wpV+PiNYVm#w*5!!Tr?KHCO#1n;3elpQJpNySdYNP~_kv z0&-%e!zr+2!k5ERZG#v+IPzfHSF+B(eUlfLyjr%o4Irw~fdykomOIi#rnt)OlU)lG z0;qbA3RyzuJE?p@_4qcfsj{K*@G2hER8obY7OL}>2R|Wwe7B(A<_EwSy}d(0A`Td5 z)0IWEV=Z{szqZHgP@?G@Ii%IaUjyGoiH$DnK-=< z1ME5ug8~)tVEN)_hYRxPL+Ljxbc|KyHqZF* zu0UV!{{0s#!=8EMZR}WD^b$-2u z-NIgYn|Fl1gr;ZH1DfMlNQaGsa=Ovity0vBl|N0n-xyZbuF+dIVk;h%FwWuCPs&`? z;gbA^`5KR?Xa&-k4?)Vl+f(Mh5=277FF+;FWzkjW(P*n%l?n*4gYsp6aX!82w!$~N zYa$#AZ9IPTa(>s`_R9p0rJF|k!j=7B*?p?(UwnkNcH9wz;d4@$ z`N*C>fFRlb~Qwun9p^n#hZE}R^X-R7)heT)HDfnK((j%&2h9`f0u__29@dg=7@$~6oDzI zuaCTbOzf)<{3r-YA5I{WKP!3{Ne4%rq(8%cc$JPDR7KqFLhlgFN}QR++#)k*6~I%@ zX=|em$D?G+YVtmVJ$Ti<#>W7(DL(P$HdMFa7>-z@0ajB|Aehpt?;Ze!B?}qYX)SMB z!6i3zWjJSIOycxh3q&!n_`+*~|Cz*ZlZ7s=HF`89eZ6|T7a=IeX{o(4$YTSi`ND>L zByez6iYg`@HIm+cyHSr^ylD9FLf>$>(7P0M5jOrTZtDDbOd{y)SJU)HlK+O0nYX`iMeYmn82DGF;k}i%g&%?ZeoyU6b#2d@hZS{xdrn0Ay zxh=QYXPPaK)Y$15yEF$g!oX1h5KYE#p)vyIYK z?SzuLw5uBuS@#(Eke_T!S0P1X2}*&HQ)*2UQ(l=#J ztIb3`criqSOC31Q9*;(j?`I8Y(59Xg#jWD0FpE>!+~AgfE3`OY8)@WkU04v_sF(>aJzhyW>FH{oZ`d1$#e0jB77jAv#rq3WUbZ7Qj6dI>`Jw?;kspn<$f1=*LuZ~?cCvw;7lEEKUo zxH~RD!%DuG3>N+}H<;i}uRXFxYwY4Ycx_8rU@aM$yiXHqJcV$3dK@Ol1}#Tjr`qdzJ7eLqB`gZxiHB41cRc z@{EG}Mf#v_lsu2T1RE)2?bSebwa>H4Pjr2QQf0}-7-@uWH#e`RKW^$&P_wBJ#=at; zO2<*Dxun*N&xN7TjX%HX-KN0JiBW)~Ra8GGtFqhxjo4^#maA0jubrE|q(HaI2emxu z+PJ@wxWk)U?I`(In!0GE{JGMsgY<4hrTFA$1(DUo>Ca+d8DHFCN2t!6cB2s)fuIag zt|m+)HbGEnb?cVVbd5BiWKFb!Aeoq`=zE&$F^*~%YFw(zRir!P4!lO<+>UlEd95#t zO#)RH(Ls`f;soMw__DLoxp(SY=4wgnYC+b3OV8ghEYV`UfJk0L9*{m9K^WeL3dO4n zGN)$%HPaCN)c(v?ctDqp7^I~oCb@Mjni4USuJP?m>AYp>_u)LpKwImv~cEg z;|bXATXTn8YA+rWXV?Ti#a(H0BBk^wWFZbg#INad;plQE?z?lEzr$j#Qw(#=JhdSA z%DF0!RTg(RXORU0mPglLEwT{Tyu(V@YatqeCP^ZX6|^oMYCAQQXnx^kL{JOurO%K=6sh#0*E|G&wuU=IqvZ|F=z=7Xx|iw z98&VQeaB0Cy`!yKuOUv#KYcFC+vV+TNVoCEK7FdH^hOjHgCmc|Pj&Hc)9=~h(SvTo zuLsJ{G5QMZ2_AA^W(s?NwMssJtuZzH{$6LVKwYeO^fX$PgS^BdI}UK;Hfx2abdLJgOVI08YOs1|Zor$$)=>`>Q=YA=dVGpL{OPc7E# zE1c9rwxsSFw_zRDH}dixug?9?;Z|&`!(wv*HLq3qng|H|&$gG>ccd7LmFJ`YMnJj0 zve}5i1`j%=srSLWgQeqNynUc6lFqNrh3GuGDaa>ueK?+6s=OTT!5-36J0XD?MZ_BU zj<3uNn`*pq(GpHIULov*sHuV5(1cev3JWj4CvLNHpQLLoRRD|SUTA`{1*RiBn+v?l z4xQLoU#a{&-v;SLk0CGBd4iNBEq_oe>uSSD&&E?I4BTVd7qHPpr8R+p9&X`4S?y-8 zz>J$dpMU*BbR01kd$nhXFOqfArx!YjH8haPLupojL-oMA+dcZ5lk6W_hqbKCUNG3l zWH=}u=i@_ReyGb=jX%uDKqibRZl@(9$0U}84*3hPM;{JIm*~KvNH{b?JN9% zJM+*z8nBwLRmWz+oJ=9{(yhQh1nJkrP2G2GAv0ov7yutpA1I8qC@__F-p_pz3$rMu zm)y2VLUmFpVK$)Okt~KC^PUg63apz)&I41gtd3(qo_!6nwm)d6@5>DMsH3Jnaw2=Nz(%HBJ>3IWm|jHnYe3osfTL9{@HGi*t?I7UI!O5a|;9S(Elo z?Nw$TkGBNBM!Z2G41KLlV=KWkCz44eNlP!{3eIS?YHLNS+Ltq;!dV*sqL}z`AMlvd z{&qA zySg|@x9Glbpdm@7kKy7WpP0G}Gw;f9^$tq4Mh&Cow^=Uzu%$Jc|`#er48m%(gXn8y&N* zAgq=Lsdlj&|Gke(9#5pf{W6TF55;}#Q1Bg2j*-Fk;!y41A@*t-_XtHO1FJ$7U4EZ^ z!di`Is{T=1zz&a2SZSq~?A8D8!|+C5>$z@0aB0WqYwNqn{4>IB11j}EL8QPo8nxFe z1htu>9U4WqNaYUtCWxXLUneAU47#;M=_1T;^6D@{*3f^dmQ4x>u@HeRVX#A~6stB^ z*Xx{n9Y#>u()8sZPZdnVlbN zrGl+r$}VABA+?O5%Dg|=g|_3c$o||n&EKa!h{c~?2+@;;f{`}J|FfaC_y-*($E&sh zaN*k`cgjQ2TLKeZCTm+H*!ujQ|3PPGgb9~Yl3Di^Vq-n5BkCXoECFU@+iwF>e|{lt zE+IU}-n)E+b}2*T2_Gl>$2jsLg(*)fKXe>p*sKWC(qV8l=mKNovp-n&54e}8>1b9(|roNv7K4&At9S`(>jqG^o0NkW^?E((q7@KaE~){ ze3;O4-RDDew}a^#!7UNP>-XcWOH!$)+diQ8u!bK-Ub~K7DB^TW3|dB4HK{LwnDN`e z%jTh--*U&iqNv*mH}))c9`+~5P%I{#WtsEd`(o=?{UShTp!w76;=p&b8461oX3aJd zby@8`XWesx#(i1o?Yqn1H5{@ATJ>3yTtN}D%sglF>d6l)kGHpo->|=QyxdQNuOJ2r z0ARTYCD0Js9Zqnk{0~;li)rZob&n<&3NcK}_k0I6;ez2&fz%ii`Xlpq50G}mOAhn@ zrMLvasRw)L$A9U13P{&AIh^3dm?oHS0o8)35fM7v z5-4AM!py^&QqQyl6Br{@He{Cyx(zv}2dX|ZZ?KME5|h>W>8c4A3fh0odx+*iGxM=O zou*8Ni%;cuE=}!fpr0$>QL*^igABySpGU6Emd%3Q7zNGYNsEvG}sHL$`RiOWwv^FuTW6z*^a(RcZ ziquYF6meB_Al19E{tQb$PR-%{-#lFv%2h_7k?N{Q^B!q0ZOgAT$Aei9CcASKDafZ- z|3}tg7NwJE$NhfLO)oVdC0~_yxd@oz8e&^hR)2QT`9dkW^nXH6odv*AF6`#O8|%L=3y5fJ9rS#1z7%nb~lIw&}Oy8ZKs zR!)&Bk@F?-Z7xhJ(FhVLlMD*jN)FgGR7@_-4PF&mO_756TW}M>;)3(fMZX&UYwfGW zWU0Q7bd23F6@ILsvwN$@UL0tpg%?(VYsNdn6*1d%c)*&jNXqw%Zk^N}!Zl`LIn|cP z8PUsh)$~v`I=$cl%T3-Fy%vH@5=--F^p;*F9&yTOk0`7<2MWzLTZe}5oL&}c(>_@`H2S|a7&Dyn#zJ-@GA{#c(X%DI z^QP!e7sHb8s}W`i*4ClvEQdI*9U2*PDc%tt2n>geS-G34;cD%AS;+W8iho=q3ejk~+T3XWSHO@u>J!JJ)1jwXs z*PXAOO?aAzNZe(UQH~@nte4o%87Im@$q?7DG>k#54qPmX)AR*22oRtEdML))mhNnZ zR4uA!yu#?}`l77k^?7t_%2`-#TGi-=sa0xqB+GpLBfIS7x_TAX;|iK`cL2rP%o|IE z%@vuEB9muH)#25_XU~@j@#~T;f)J>BcbGnT)cCfvolthKrK&Circ{Hp<|fAh6KRII z*<0!;3h2eRsaw>tD9q;RHhltZfTe@;DH*I{(>Q5egI&JgO}d=7xQtz&pNTR3@uE@B zRd3e!8pwxAg_`f9rJj?%LCIHMOrZn5Id*!@d?O8j1zK9NXnEP=w#?=bd1^1)KK6%) z@9;xaOXB>>;+TJ zV&}$lJ|rM|IX68gBl{YHu$slnr-Ez#=KhAxu3iH5Wwy4SNbt{gRpzO46+|6f7#P+= zAjJff?})vQ7TN<*yg$(RWR3EQl!61D(_}IR=67a9*blVvlp9ixhiF~|W{a!dG(ciO z5o0Vy!;j=yaiA7c(J79>`-CiAoEnvm;`XzfKArp)M}lRx{=SMd>TsGkJfZt~*J zYP0^cU$J~NqolenSQ1U!aJmG7zt(eGem_guy!4X<*hH=AffOrII$wiAf-Y42#`}&c zdmV$ZnLB=9ZD0D4a6M9M!1W!AQ!}E4Py9MEL1UmbuMkSY8CPrHr&C7^8 z*?e5MCFfAi&a1zUb6!VCLgi_k#n?Q0O6bnR0=2X`Xlyzdb_=z0kWCco^L%Lg@(-F5 zWINa=FW4D*axq6nC+k!eVs?!V8&5xaF>s=By68bjxuc`(6=?^aksVcF`}*zyl!0?A z`Ur@VOZAR>fpIEgUC2}T%S#G=15@{=2ZFCNQ|p=yk1U_BT_rM(Kp0E_O*A_hixB+N zk+PYm!Hy&Qg3b!nyVU=k+&7(fn?J6oLAVPHRpyfqF z(gYO30~!RogZuGrt?feIh4e5%k4^o3l^kIXz+f68KYdqs%Xggu^c1tAEN(bX(3BLv z{hI(iEMloj82dQhUj=|vV*+6>dh*e%!R;XwS*F|yUO6mkiQ=o4=Q z-)o4mSsUTVl*A(4Bw8b8O{GM@q^6e>!GQa>0kDyr(n~U95e1^W_mjGQYY{twllm!%n@!uYP&F{OayU*0us6AxSTIQb(0KYdIG0*l}3N zeFR_mS2dpIzb-nl9N2;kv3GHq_udSP8ZQ`e(*KZKq#j}^NB26raC)TXbHYQ&wfjO| znEHhQWRq&i;J87bc7g(OpQHXXq!G@{M(@z*`2taD%{1c7xeD^}4`x1@q&Q?X<*53w zJuJ8|-yHQyB!Rb#wB;B%X7@Mr=k8TbdW2us91oB$Om7z+oJwi5-=yKi<%GUsjHCF& z`F8EdWC{lp5jq9MQhVV1asBPr3HQM>#+NZRYl{i%Wggt={%@{Kh)?xy&*gJQ7$^o= z(?^gHc2fgjiLaKtEEf_kjSLD#Ve7r=ecL@|(W$2_$cO$M0N}KLHmG)!OAleMF zd2ZtRmdRB8s@z19_DbEEjC3AlMqrF#r!i`0126c(jhdTEt|8N7e!Q@1EA@?GsPC4X ze6qks=}X+97>~!YaZ*xyZw_K5MifHWR2V6j>rU${W@1w+LZIIqiwx|$rL6^U-T)Wj z4zg<9g#Q`s%-2A>rdUNRhms4j!g%I@yLPD232{4Cq@6l7!YiIA#;7?PWj(_4-m~X} zCNZX{gpM$m{dtB%=(4AmlyTpaTjJGRGD)zrbr7Q>d0`j`J|LpOa} z>01i}nXyw%*+X57QiHA6T_O1^B$obeem~k{i2R72&<)t{x_?_l^YLR(f}UjFU@F-z zM=f~ni@!R7Apa5>$sj^wm9n14;Ahhw{hTo7bRzp&i7iht5cU-93bGptLr;Ua zQ?yb(_<|fSc%)vka9CR-YOv#ulKjcJYGTFrQniqVCz~R9q+pPTaFAZ0ymrBsoO|KG zIoQ^J#2*u|dID71-aKbZAF;b6N3I8uKBE$z=k#mKiG*pk=*;=xTNk!D6r5m!$l{a< zdrnsX<<#u4&F{b-Qp?!AWDJc)gOxh>9Z%;1n{q;1zFtp?*cxZ_4-cDQPi^6}#fn_2dKClf1n{3&zbS+0$}re>3b z`tE&7s&{z9@aymY7KR(U!XXr~oTlyTXDL(XZZcO~<*v&}o?Bd!{lCOaWa>TAGs#?B z$K1Nc8)+!w#G+>CBoCHR6Ji*zSWWnL{M6bjQ5@jxOtCgAWj)=D5!$E9s;R-wwyjSS z=el8x>j)3$o)psnp*gVN>`BE))Ddpx9TPkQE=Ob12rpq<%zL)kD28omru*zHjRv9VS02v@1qkUEZzO_*U%h~p9vK|5xmZ8+Y0LMvz84tL1LPs zo9qI|TlYz{U|`oEBK@@K&05mp*swVc?Ymt$zC}t4KPxo~*dfP1?vmsU?mWXN;dV@Kb;1_a?Gw7LWMt zt0#l>&4-#R2hTgAFSG1bHKA9qXA&IiDc>^E3I`|dSKNjiqHR3MU`44i! z{@+r>9Yr4ytqBS8UZ}iyl^le`CiTPbhGU7K)C04C0y|5<0yDn75M^D5f)>$$E}$oF z3L+w(h}{IMBKzk+hok_jOhq*;Y*fJ@<1%E~(YEjXG){rv6h!9Pv42kpcp`Iw zDgc&-60P}QnC-qQ6cp(BZXIj`5Sr^G#dbJr6bm(-^8_s%VZ}dH5zeJ);_7WCJF{%! zR*;dLwYbgqjwi*LKY1LEqEL7MkA7P3ySr)=^1tu$^4Px6kjZVwj0=k3Ar+(Q5T_rr zm@LpYdKHCsq4p$T<3rlosL*=QR*a2v(dnE$bDGjGz==L|=uS_V;TON>QF;`nyy~BtWH4-Il#aaTWO6iS~z`qNTe3&&#BC8-(W;E~>xJ zMkYY3^j1uVSwDCn;n-MfE1Ml8GHj%mwgJ)HadtU@Ijc}b+rqe)K;b1YVgy95InaUU zf(MW)w{s(6DsmsPC&xDMS}9#vqSs9$bX*r_KC2Vo*2nw!=R+KK{`vcXC2*ZTQWL2 ziqbzBkl-)g?p#v!P^`-j+J*4Dt#KTAka#7F7@ZpmkVJiQ%kNm3fCFSWAr$BCP{AXO zM;8IT1`IIvD>vrHHOD@rdA2Fj3Wb>VM?&nP zaQ(lgyfDL3Uh77+rf(s&D?qk0(56=4KGnH(@sEow11`*@%YTsX$JvBb$KeC%Ij1y8 zL<^WOYze7$j`V7%$%a4?G=4740P-7=7+6ci;8FebAN6|GqSs&4D>+B&@`x?qjql(> zKE3F!LDLZ?Zgp8pT^Ht()`v2$hmjo=@r)kyrjS{+J$`<8*^sh==F=Bi@S98$F*i0I zm7VO*&UwRCb}n*w_6ORH!4JHRghhaaA?W5k2!TrOyI*xFRE^?}#go#fAK>FR<>wI} z*W2LdTh2675F4U{&O(e$7J4a;=u6{@r$6BT^l@A&eGdm6y7zKOdbT&hNcN_#lF9VZ zuy{@i+Bq4U8Opbl<(qut;WkYS9T!Y*K5Ul7;te(d$p(Njn8z5yJ^d=*`ssZO34V6+ z%ZEX$|KtE)1F(0>;(#Qp2?D&J2px>7eQ6xmFFV9gYcGgfe?|I~LS#Smv_%MA@t?@+!X*Y{qEM}c-gS+G$t2ssSY9LSc5YYn z3O~@!PZO;$uXiT86-`;Z5miw63WoZx$=&bfATTqt)qlvYYw;wZBh}Lz>0-|Q5A+P3 z?m{|~lU@6xPm%3_={Icu9=s8>F(-vbf|k%h#pAs9!tLJ=A9cY~seo3LUCu|4mdmCh zm2|f&jVmY9n#~;?=^`A3ThGAP9Bk9-(RUu;dSj34IkJ4Sh6gXv+&pTQkgjm{(eGfV z#yKkXgil*?I*qUSOK($h&(a zZVL-8N4)VQpEQ$%-2H+kE<67DI-z9?FLVz}#=WuNIFU56g*X=`S}}V%JPJ`_@rWQ- zxqe&zC8UHV@l;vA-a!q(=Jmp8;cO&{c09vwNCAAuoXge z5TvtPCSVIb{Gf_>-Y50Prq+OtWN_a(f}^36rlX?CI;~=+*$rH3oHFjHyaunzjyAS* zpN`fSuU=bz=c!5a7?$3ydAjbo;{bPz)J;T&q2_3pck~t<7s8SVk7Mh#jr`xS-uDA3 zlZ9}q;w*WW+V%8ajNeF2T)JfFYY=T4>E9P|=kopP9; z=d6kh&UWv{U1OgW#OUqC)h5{q%nqn2J;U>w+IrEoe5j3_i&_G@yDIKChl^6dv`U+( zXf2&wcG9x2poU6zhM@CaHl?z7jYmfkfNeCqIeW&IpBs)L^=~#MeE`o4OzoO9uL5hQ z#smMzI)@x#c~IE9P`6;>0YXO67vEZ$=cnYG>6Fl=4hE~Ge7VdSGlSQ}$5=)~XMtfAP z`puSmoxeFi&1Rnsa=wo!rx+8-lMZi6*jeEMjn`zX@7SoW*<@wyO`!yET$Czoj0GYP z=}$<~01SFn5qA=!mu!Tec97%}jxv=u)*3ez7&+NshO=Y&uVT#|(wX}pjF!_V0GO-q z3^ai_5oxXf@ovC01$1Knibkxsl@8fz%&SKl%F%Xnt~DUHHQVDbO`1%-RrVBzV%f__ zO{NGAYi}+)jH62}CQrD?djr6P>^hS4Xe8QT^!YTX@HhxC0iD3qA9UkGQt9fMg^ooK zk51qY3@L{y_$dtx0sM$VP5Y6Lurxsx4_wBhL zBX;V7Vx9d;m`_7cm#U)lo(MYph{UkF_(VNo(L1NMZDn(NZ*p6bjfBiuU#`Dz!}PqZ zyun8A$_v4$tRtzYx&v3p>5Fv+&bQ%FgKQp)Yf z4y24uBpUEv2VHfVz1IUKdTnJZFl&GY9j$i*_*UUx`dd@{mp|6_9?o{ho*OtMR+ZFK>qMS-L@sk#Udd6D z^@k}$4uwdElQYnwPJP9{pXI%O&>gPiC#Jh)cOo9_A20$36nrz1vua^ls?>lyb8ZYX z4$eLH^pwu95`tNuJUxMQ%j9K&?7Id>QDPVZY=lo2fa5kb$cv?d-nzG_(@=oGsGl0qEe;4;ItJhUh zsaQ70VjRe3I*|`yS53tM+uAQ#PCL?0Us%&;Vc-Z%oxAif8bR4RMG^`|{qf4;QjW0~ zat0N?My#WV-Wn0t5BHt~fhst(ydp$hC3Ms5IOwpiLR8Xv#}JfumkI=wYbNYC40zo1 zaDZa!O+%+%6F$K7JxeWi{l$yN2fh~RHA$(537K-P3}}=cqFNw2ivf}k64v%D@9f@= zmVP&J=L-FUGZw#+K3)s1h<(+v6)gHDlDU@cX~n5{ZOvpNZB{Gn7l3EJo0Yk zk}%UEP*w8D12D#-wn5mLUMmVo*3D-Pmq^8W^!z2t`0+9Y$};ZHbkq}EUfHf0;TpQ* zCsBy~>r*!3!U&fYzVH?5K9$?B(PE|FQ00>`;sI+Qa52a$a2%xdK!U#voglZLPlGASb_Mt%TYxnrEtg9z>tN5zJ{5LE~wa+3GCifuLJdN#w#n~?PkMRQL zuy)660(DLChQ^><*3`%-fG6e$&^>inF?y6Gebwn6>WkLs91Ovl%U9-sIeuCg(Hup& zqXxW^W`l7oMgIqDJDDw3@q^OfMu_!Cn#BkWHS-+NFsw`r9(gK1rGWcHxu1fH<}g1I zY`S^ex_CYV{o8|Spey6&8bZ@O3V>sK6xFsV(`)M3MsRjmiYld98%GLKJ71M($-K+E zmU-+W-L!Iy0U{M=wrwjYM!Z~GCcA&4%I!`)_rAJt{%4Dif0n9bx7%?yP7qEHSn1UJ z#VT_LKM$9xPoLRbb*ujSO48ioi3GJ1ay7~!i21wjL@Nz~to>ZzZ7$Oe8xt-H|6}d! z!v$kj{1?g z8f!J{^Z6i%x?ye;hwAE-vo~>w)ml zz|`AuC5suuiodF_Jv2L|=T4Y8d;_6@Hzc^xs>suM*)tsNj^R{pt&gW(2$gt;McEAV z^-G&PK-UptF$n8sO_K^YH_9%X^ObSiXKRQLyAL1E z^Wl?P-ND45Pul9Z``anO4Kf>Nf#ODr+W-wzEnVDSMdyEXjAv%P7HniLW9sMlr}}{I zG|DfM_?%_gULIBVSaY@Oesq4FkwHF;1TDvnkrC8{HTnWhs&ay=|5hR|1m^?`_nxVx zFXX&Sw&NQ|oHQ^7Pxd0wLAKO+l)-{tx{JuV?lP##qnMjSQdV@Kp`D%*rqZ!}3z1Km*GnQrO)35+Y-hXVB>ZWl!+Y zp8s4u#7lxMA~d0lNpgI+laT!dJ45PLK===&w-3&}&mk8%?zb7GuMm(=a`2F!&-?q| zgFUUkHXX-hI&zX!KG6yc3F{U$3>A~B@|5sosaQV0j`FHJSU5-b7Ioq?n ziYlE>=5+e*#KwMM*!NTOvSua{MEf&6{KK)p=3D%I*O+#1n2|bLQpnMPR_F{RcE;F~ zHI+d1{CBB)T={soXPJ|AwFF9Os%rfY&|?`{EhpRDC1c@eURuzQot|BUV^!$DZ!#+F z(E}4E@d!tCDbWMKPAVS5hvE-Ie2h!^K(EBiZVS$P&dcD)C-7ua)k(Wuz6)O>sM zs5CcSRG*LX6G4h6w?C@tFr7llI2YO8<-!0sCD1-bv5vU9?4f3JV3l@>u zD-ZyL=P|}JTev%!EW-<#m!+*zrWVnZcBYByo}B{*XzAdJIBKoqm2Jr&;AkUgR4yu$ zM4zx~M24q8BV7A=T)Ei5FMHv3PFGT5zQ;p#E+t^54FDJuGw7_P3Im-2&A|}{%Hm^C zohZtFR^7KLLPCX=2t^Y#=7RL|0K5P^{L1Kc-kPx~jg`CJb5>#Qo zC7p?(;|l&e*OJDPQ6={^xZ%97*xoCr{%yS(AeGo^fIe-{BO~#w( zRsXQ$7Jih}RxVn0-C1uF8B4nvjEwSm=Z8$i07yca@Vt)KB7{H;GQja>SxOTr>?JAbHAXpig-4;UoR1?92NSFfA0e)0dvS{yaE@y<>n(x(`H8y z&;;|J%!34_9m%WqNCz()eLZzE{GO8b1w?hQKEfO5a**d*lU_ltMz;-nVhjE?>2~8yiS|(63Cp44*yK{f|~) z7|be|&0L-PV0^jkWuJ{+62|)3Ws<8=>f*0C(GTs|s*nzM{_?(KPl2v6u7us}ckGiF z$t@d2a0_j?`;B27LU2_L}^VXW-*^~SGp0% zY|to#V@t}Oc>C}CKJxl?$J3p1n9ANE4kq;Fk(toq>i^tIk-=TuxqqdLO%1bXs@>BN z)0qD}9%lxnt8wfAt&h6+n@3f6q2nsvBSB^Z)g_h)M2=`&^@Tw9EC!4Y#jk{y$q9_| z)3<_Z#3VbW@xm%un6ty6O5*LJwK#DI_8QFX$0cc*uZ5gT5I$Hw_Mx6)B*YL~<&4TG zu+|cH38d;jR1ri=bNVf|(>7%7bW?OwXnR@oHNksA>CN~Pyp@_#d@Bhz81b8oSbd6k z(v9q5ymr-rK=$~{3#Ixnz&#eK=LECbLFyKQ_gq6Ulxz)qAVNU78O{d*q7vT5GeY2} zjldiHNoPyE!)9!CD$OSi6+L|q^2SqX~$ZP!oBS=MI%p1KzZm&z}axjTgtb6KHX*#`U9TW@` z72#3$0uaRbAa|p(3^VSe0kUV;MH`DiRgoAph3WlQvmnu5Pe8ST;l?tz0MOTyTRjMC z2H!+n%JGz8S@?VHI#o^>RKoa+RADX!cf;^sd5hiqJ3vIiz11&|rvq3;&3ZjH|0uDHAi6N}341577MEd9PU z+*L+()@L8FRc+f(%(QS@2h^3s=*jyY0DqnRjUlA8jH7Lqll)aZe8+JF!xeyZ-kZt1 zVl-QmB?X4>dhF}~}&Y%3w zjGZb{54I{EWf{d5fE1NN7e(x}%7KtxW)D|TdD~*~vOe5CgqSanz05~S5&E=rKXMz$ z1YvTh*MEWRF}mrcJ`on$y3F1TJcc1_b%RkWT!t+Cq?v&j!XF?kT3-iwW$`-z&)hT` zg}a2E_=MfPQRu0%6z7OMwm3?@{6*jn_@;#z%apw#r6r~cQr0L9xTGV;ViJ1=aiGu) z`qFsvj~%hv7M_{R2*)qF6IrQqYcm;uMk@s`-0i)b6?uc6JwM7;mWcknjgm(%w8zO** zBJ{KzTc-uf;cR)l*LHi>-zWJ)Aq*lnINu&L(}v+d;osKpJW9i9FO`#K%v&uC@x1^8 z-EA50ZOyh=%nXv$%jaGpnWRQ*S-SosACfh>sNr2PL_lB$1+V#sx3H&LQxJCb6F?nL z0~aT&mUY;$EY@tRVtN$R(okx-$>05guEC$-UztekK+NJ|Dgs_NL~#JC=2dsa-FfSA0%_~^~$+C8D1(cIATNn%b5EXuHwiKj#HX@()|;V zJ}#9J=yuZA3uMqRd38p6*#WX)<^+@+W~im}6BTxAr1(*E4lm5o!>jZ#@%Hz3SD)>OGnB6L4A`+{Ces>7~ z`J`oV6p-Q9896%#PvEbndaa3Z8P!sb&q*pQ>83vtByQLWfncLNIPdM9dd;y(bsekD zfMlmFaTS%%$<|Ue-!JzD&O??0wWcb(KP2np2Az0ybYvuK#omAwTi?=i)Cx~Nw`g#P zI@H4=Xjx5TFpap~16c(7S@gE_qm4QD-wOO_t!VD-Zn;eo<;TY5+S2xJR?EWrycG>N zSn^$=@{tyHE{FXqX5`dyierEF764^4V_qDi|1+v*46Ut5J{-w<6(p^f+5*oB)qFJz z2kTu&67d|ruu;2%YG!uyEMaMjM`#xedbT)hYWDn4R~G+~!#}kcKKwllu?}30R=5lG zy`yaGXHJ^k6Hk(=%lKy<5Vy5zU{aPXvrxU=f${%`=PKI}VO~ECH-sgzI&nhWda)%a zCRIujgg?nq8tO~13Q4q=8&*MK^c0Z^+gY_vc_j~3me84GEQukivm?_#IY%-Pbv5C5 z<{-2Q(DJ@uPJ$aED6BFW^@L=RWW z7rtI%AV(_DGi0Q)7lxyH9GI5%FhW`s^Md<3il!hJnPEKI506Aisv1y)T8zJuOL~j++n1xU zM76t%nlD508%ia?H(>&tJ@jC>tMqHU=w`9(wAE3d=vzDRV%dH7RO4Y-xZctstLb9z zrK#lI_p&uzT7<<>QOgUA1F+$7n-ryx9M(j+e{%S;3(!0q@0Dnzd?J@UOg4InDNqlJ zTxE}+mft-kL5=&w>)&`Bd6iwi7i@OF-tB5LDl>&lC?dy2qGV)pYLWw}#V+nw68EBEs=`lE_B{2Z;6%eP8- zC$|Q9O<5odyCc3|nN`))Lf!q7%-RmEuY2I}JGf8%+hI#G~e>P{-=!z2wE z$Q2NVi}N*sQ9V`H3HV`CxEo?mkhy9n2ZiKKrkOgg49l&hR^b&PT~kk=#E%=f@%0-l z5UMbF`B9Kpq2r+-2_S;2P;O;ykwvtp^%d|W402^qfg%+=jCsZZmGMlg? z8B*#K7*p65IXIKx6d{wAP|cfS?}DfAU}l?1fQRYj3Sv(hz54tvePGVS)IMT7Mem6t zGLAOeZ)jMr`$XCdVM*!YK=aL#rrHzK08?N`fvG;a@FDa>-T$D(_ z06LtJ$%?!5geuOXN^$G%dO9LG;V5lp-lI7=|s~bu> zl6~bKREl7I1&Qw7h-po%v~^fF^Cf;}uWHOqIE{jyRQd%w+^cgMNUjsDyxCz=YrO6J zTaQW6J%ho7|Nf-r%4nq@0S4v}ehD2ZLeAL0{9I^`vnGDSH_U5pRrCJgpLBO(@3I#T z#Q@X5-)}wXL0>4jAEo(S=k*(;RQ0MV-w-ikf{bFX|`zp#%n{z5F!*BuJV2kPu$M<#HzN&ZC{_K47_Y&tZpcIR=OKCt#NT3 zlyfF$k*v=FhfN{L_Kg}XXJN#`11eJRn$k$pjt^#rLWz#apO17Vm^)r|M9^5Pdauh9 zQDn_=E*BdM?ZVwZ2TDeF>PN0j5KWP~wYqOXSmJhPq#*mq`yF$gvB6?{B_cL6{JzXH z2YsBPZT=w@;;_pudEr!BJ4#>VAOk1kl0AZ0rhuVP#KGBf919oD`TF6wkvA=yi5MBUZN~R7;nx!2*;rZu+a#JpU4LS zM#b<^Sh1}{6i8aoxU*;jga-HmFrse=Q%ORej=!w=h-2*H#=|eMd1pT;33clb0%MCf zX#txs7SW+C+1FcwTgco({Tol2s- z)d`}+~Q0we>E2KAKKPR+Ft9ZosHkhD9@RcF(4}{Y(Y<&5?;63$1e1-uecaIJe zDP&Xm-Kxr(C0~e|_<|?B7eHgmw1FWj?pAp?ueb##nCAR;$ ziyqa@M^4s=S8%l1Dr#OeHmCh~?8E@CW>*2Kvo`u!sPr&FS?k@0Bq18g+9-!PBBPJT zha^ts>h7w@jKmoXjlB8tzChPG{8PYNnh2*xU9V>(abZc$o#Qs8K%6&FV>@0~rgfKH zb*DfQLcU-0j6mzA-qU1QX`0{3Bq~!t#QxBaK{G-G)@)%EytFH>ObR)kytTVrBxsv< z{d(pMD6j1lHrn-JTnPM=8zdL*c>32k7-ki$PBLoWw>7@pOR31FQ7F)zb^ymwK!PTz zC#F%ln^yH^p%!X-8&;9xvMpU*cx>IpS|{2~_Px>%3o9;1eJGsvq-<+{S#l}_B*JM9 zHuRmypOo7Fbz2bMDRmY+t)sg4N*m2E4{lKVt?N_}5SZf+XbO4k>oRe8c07ginMwd( z?ZqzN@*q-4bylMQ^m(FcXDmElsht-!_;UY4_$xjRS+yofAco&tI`73pm?k^qBGgAC zU?3|}DD&1o7j~}cb_IIK5=34=^nW=Hc%lxWB3(6(TJAL48j}h^$+LL?%&<4E1=mQ8 z+ebVl+Yegb0reOl&&31t+%72uia`xxi$dIE)kcz6IQP33n|>PKC=YKgk2TS!AttVz zc${-3ZGknQUD;Wl_aB7ViZ>Rq+6JrWeb~@FjoC{-HRr`07QTLI3R={i4_=W&QKbnD z@7KRZP?PE)2*JIyQZ{5?v?Os}cN2kopaxNz!E^gBVC`Qc7mYjc%H^V^ogop2`YwD_ znns$_>sd4(hr56HfIZ<7GtbLj<5G`1BO~YhK)?y8r3TeB>%keJ zbLj?~!Y3$I!tchu?M8OCZzO^Ssjf+HLL%JDhwmqKaJ=x%*Y-PI`c51Ba-(vt(Q8gA zI4I>(;im2uh5wS<~);JOyAL742Pq&DbZHNyJ$7A zyo{dV^+%I7w)g5SY>i70El&B*1pI&8K%OXn+|4{~SXM~wa$wv5>R|3fglgJPi3Q261$aRrz&d4ZCrX60c(f(?F!b*t zT$8qS8`f?2>9{%!!oTy$$l?T*YB2>I)_IPyuZ`FCcu{AfQZz^8FzjiIuQLw zRHU6mmx10oME^HtV^n9BAvLnFt*1GU&8uYhj)SB8YDeWKN@?=YRRU*%)WQGFIbaOp zE8Ayz`NHMi8vB?VIz3n)tIki91^{f4SXrqdY^=e=Pr>%t#m;|DJ;zqB3`K(`adrUI zFDR-Id*w%WbzWa%QiN|$*^$TI()D;s=()i3kucYiW-x-?zeb)nAZHYj^i|yL^$pT; zPe5w6giG5o1*2H2WJz2u?WM=!u_XXOK)%1qXb&wl`LNuE7kDWF(fJ0nRJ32lw)5FL z{TlfhawwrUX#~bGqDZ&S|1&P78Zu37il2TrXbXWOCYq_!HBryyn*+F<=Mi< zyIZ=X^KCb%<$7W#CiZy1g6(ip+Hajfu2FI25$etfP(n7%8@0Z%! zIX49hFgU<&^L4+C!~x{Qfci@41>1=hhFHYnCfQB$t{{SQM%Z^$T$15+U}yPV1;^Xr zh&>DIehIqFXhH`6*nDr!IQbzV;r@DfBl%+C!a-TVLWO5Anvb(MZq2ZZp$}AIk}DhF ztv(b`gF*jkF4g|=AK&|}xsh7%%VBHH3lQ4Nq>7jf*p@%8>z2h3&|1Ku1Pqrsw{5ha zu3Xyq(}>`?@KPHB+op^#M9E#i!*7V=s_goe4qDHkCQ}DS3-w497tN##O|ib7dC!~( zn!$O4m3&r@NQN4U_vWCH*Rm0I6cF z7WE`SENbYEzu*k9NH`7nJcozZb4!zG^UUY88_I}bqlNiXB%IC(|8j-r`Rb(s(fi&e zP75(I&k1P=L`!4XqK~m0Yelk4irN4vKz9W^kY=*~5{6`LvASs&;VeFq&v8Yu`kUNl zWW5~IwVOxA2C}2V@SQ#kuWeC+e}5Fi7%{Q%Z9kOd5?{#64rYzK~^5b%(GpgRM9pVfYflojgj7mHa{EX4?&;T5_dX}GM zO{N^7P((-AGh7~ahO2s64eQO9m_yg7k4V=c=57BZ?NE>r=0&=)?N%3(_Qezndp5=^ z=d6>uFum>jqM&0%r)5)ws6^3Pw=Dy`SH9i{C-uifaqmiW7pUUGV>ys%-&5TyaG3{! z;z&$3YLtTa4(WM7`eCn>49{mybg#%YSK${IL{zhhyc#CYyf=P_`;hVqWSehrLOEK; z=5dTnv;zhPSQxLgsG9IKe-+=F^ZZ}SEZ(gm>{%5dT4wBy`cCyn2kyO2I##oZ3%RK86nyON{ z0~8g2Qf7IiW=9cbILQ~89>lQ{fk(8F+ijJbL()NA$s>GvRn;^Cv+P+=@p!;UcpsrD z={Xs>GkRJD9gt>g+dVME{;pt&MAMqH7X;{95p~bd_p{TDaBE8<&SG;4h-AMq=~Jw) zOXk^c$6gJgPbM=a{!o*Sy!C3K)%;zov}g^|eFIpj=*tuw0Db7IPVOv?!k3?w9iA26R3C5Np{S6i!JBy`~L)=j~v~e|@DV0!eWwGsXrhYLP zrNsAS9-XP_Sp^-Oy7MDp>n371mw5H6GfOSCGtJARmz7*^$VW8L|E0-`SL2>Aw=PmI z!Bb?vSS?%j0R0bV7a%$5CFA#6fam$moCr~@M`*vp3zYM@ZVhL#_qKQnWiS--rG%p# z=s4AM2>7KE?KR zow3u^VoK!l?P9HHDZb0I3sMz?!~ROB7)nwd%4|1!V9Fc%-dRnhWPIxk34xFW19yj`QLjdg)&16G~Nb&5mck zb9(s&MKbeZFVd%O0UjQM+()pm(6va9KG5pS1|6{1nOh(sdILe9U2l~_b8tG)U*eJU zvUPlc;XPE9t{;+C?1?y9Z@LikaMqlTR)-L~5>fSn_WQA442SF#4Ig3dxxS*yJD@iw zt?8w!IxG)V%>lvDq=J>Zeu5_Wv)mQ;O&Jy8WjiF+(rQK-CnU6@#B;kIE*2YgCePEu z*_#@@%i72{LoIkwpau>&sM?)`6(Lry2_de=B@Wugxro%W`>GE7sfCT7o^GykU<}74 zzxF2WA!4Ad7y2z)c2#VY$MDl_0PA+=348Be#n96T5`eW?Dtz(+oW|Uz6v95&>Lo9u zPymXTyOuN@)p~7qYI*)f6J^D^ml3)~_8?u22#sIZqZvTh==y9JjJ)u)Fz#du(zd@L zNW@{E&_WiHto}ivm73 zqJ>-IpwRj+gYmZ-ILJ6yy%VCo)ETT$h(3zdE3q8ZF(eGud~|tUd#ig>2E`{j0I)-T zo)55U!#aKm>#;#cZXwf`#VV&c=o|F&nCi>*2Zz(Y>B?pDy!+8oMY;b=&Z2?w%v8{_ z!)Xxj@x`eLcI>f&)&Q%Vh$*y?DS$c>rD%f=^B`JJc@6+LcNvMBW*?0(h3C98BQ&2c z)R;n2c*LMb(uax^9V5v%wVKyblc<&xv}KB(`2&l^rI((IBgqWqo2Ep@ky{>mIF;mMGft6=rpzy*E-|7{`lhf#HJ4kh z&(eeKg?2hZ=*AYo5yi(YgY1W@kD zQ?NDd&ap0T;h?f8=vagIa!zp2{=M7l=ZsIuNz5d~@S2PM6iL9qe^{pgnLgij4;c75 z(0>2Y{TJ3x8R#S&n|Yr+{POTcTIz^*qBug_!(4kQ_0(#k9_$4(Z!*+2Wwtx0${QPs7x+9^=7jt5Nmq~+qM&gnM%vh zD8|!8Oxf|4<}v$ilr|$7fI2NfYBv=N4>5-g>5k~oUctdHdSwDl?MxCCcveg{$PxEd zI|6gsd`Y?p8JihE#P@d+r!$O#4XE$Xka2+$+j=VYT3#qbFHp6(UUX8y56k?1@rT-|Uy~HZVR?vyO2=kv(^}loSFb%(VACmp{6O95_P!CDk#*XRpCQn@r4Zwdp)~F!g@@WB@ zwNDIk>|rkM6FlsShz0biYmkx*J~g^)2+@x2XEhbJT9!h=G1xRJ^|tqUXC3kvJU?J7 zUWQk5JO}j(!R;R;BVZ98-z3!vQ=^GFYpe%^-r}QWLT$%|{^KT2%cyJ$wUOX&+r^kE|WI4sL4q0CE30 z+*NE_hINJV4_kAB*%l@Pst)riz)}!QXmWWWtuYgg6nG9MYIp}-P7~!L28R}?TY`1M z=+YZ34|<(;C4SAR$tI^JJT+1R#A!u3O9~r?hzfE=dj|2Q+wso%X!V&^+W-qhFc~^K zjx|ZnRS)carewJ(y2TR-wii3{8|Cn(R2h)pSOgy_uG9n~jmv$d^=w%aPL(C^{384Q zgj>v;sBr^b41^nu3S+F(WU^yrfM&dEIa1-e;U0&&%=mm(SrbpAvK3J*k*;bup1HF6T{G~ z;(VCTWc3{O@mO}{2*u7b)MWt*5`nE)x13R0eJ|y!78bUl=?Je2+?hB&nrk+#_`2MO zw@aC<;YJ4=73?(}f@is|skW{jey_{RN%pW}E1Uj_AUX3-Gn^5Yp>&kB>WO73g z(3n93UQZ@f#T~SLdx!{RO8xpvzeK9eSF^^6H3{fI1e6dg7cFi%AyBS=K0?BNww)EE zpdhF;AU+B=90c1(?tXJ#Wc25Hi;SU!_YON#Jmk2zH^;tfdOztZ0>v7xU3*B$DBqh zmm%F$49S)yB>gOtT6%{pF+#YYyw>MBx+I8Z@2k#`PDkXsB3i@Gt%xEmmTHTwov9QY z^{vCQv&XWfkc(@WD52s@^aJs-V7grbSiN9?2NK$KK0ycT{`7q4ZhopP=W=(;6ucqm znv7(h*ra?bV_&B&Y?b??Xou%2bW0|2H$WLF*ZTsudmnty+<3q@YSxh62(lW z-V{1Oz)}&F^hNef9a_e)|M>+>p%=UGNa@knu|nGVH3IAme1BYVkHlM5VNl^eSG#Wy z%!GWcG!RA=CVfw@Eh_$x3;Co3RgtbAM+Er;&VIo~v7u}v3C7&{!R;<{CN{P1p@AFm ziuz`yzB|rngTb1!4!_2X3&q=PTQ45G9N#?g#<4YD*aRH3nO>%AZ7O_lS|6o^R}Lx zM7KJJg_pLPlLCn@^_xZ%n8k(0L*peZMQN6v%zr8qXyzpjWNX6UhW3PZmcmX|8ig(e z<9qWPS6bL3YOmJG9g6U^Ay$jR&q~BBLQa;| zsA-50C+|I<(qTH6-i=&d0eP)8g4w~w*vI^z0o;wd-|=(AQM?Oj!+jD|{msi6|r*sCfiUWiS&;bea^Yh`>ugby2;JI-RhDWLNPCx~=vzYMp@YX!<}u z>-rAjMaOamnvOai$q$^eVEAc9NmC&MicOVSy}U9=-vK?AYQWryaHen{!u<}|JYGb@ zEb-J;_(*{DaSO}0ToL6Zy2j@*oyee+h*#rv~xnL=HJ@) zv>tE3HqT7JBw#AHq$>BqHJ@8`KbDp3g>pDX1qm|!mOx_i>CW)G-$fUNBxhXXBqaSb zTC=b#)Be8a1Z z0^S$nFK(Iu#zd||BWG41bND2tiVfYFK45|@C@jLqw%#03(|ECvitpM}{j1VIvn$dm zBWg~;scA6Vk29zewP@}58dXNaD5VL0Mw9O3uuZ3KB6e%}x+!$gw=NTQAY@{*5pov< zw%6O6H~@37N7C*^D;b-{{vFVPW5EonG=o3BjhLj}~^z$jOm8SOWKX z`UIZjGw&y#Yx}PU;Ixpa?`=ut)YM{*LRCe8lm2<@Zy@VWW0ifwlqg%o(Cug9BJNN> zJXmGc$Y2~Vl7nn^sVHCq!|lK)kz*^GMRaP(#3b-ABK`Zh{s(2Z0-Ts`4^Hlly`UK4 zP40(i=F`?4P0I3vg+yFf>Kb^U_2ODC(O3d<=ZkR;#G+&<^i#$gbd^CO^1sHzc0oF$ zGnTMeLBn@b)#58kDUp|^1hMY&n&K$xI%_HO*Qztf00-G%KF&b5{Jz}wfR#blHNO%s z9xwKG|5ur{ClNHvgG^`Xo2RmB8Aj{L#`*N8d*Ef^btF}5{=_KP9$<>`LByfPz*%<1 z53LA*?dFE>-VaG!i3xl%Xqw=`)KSDzDlViBdAN`Lt@wAI21aIV%h(L`6+%`fA8FxE zQi^-)-jb*4JSCzXX8?hpvZV_hBo+Pj)1Xs=NP`n;nel5$6FDFI$T=-M3@2c9Y|&u3 zY`N>>ZGan-66af^QqkN^H13hYRv||C13XOC;jHiTzg{)#TFw&V$x0xCv69<-k$R&mbp!cPWI`~wsDTUgSX>Bj((=3Y z6CKfEF?SGctHXAYb5K_q$p$p6qk#_xeUKEYbPGu26uoiZEY}OiuA5q}Bb58>4#7^` zDZ@%HJw3L|Mwd~11GQ`n(aVodRZso6%84a7z#iG+5-SuApN=%_!5i+`gbsF?9=JJw z8%(0+b3W*I(K$Pw%@IAbg3%&~*Ae(asS3c>?i4swnWL;OwelV@_;g1WH+o!tPU{VB zV<~B3)c{|;L*0K}yFGg&7?=IfXJE~?^b)QUcHE<2i#9fw$vWPA?gwaCwERm&@huzd z!h-5?EUWTL@aRZVYk-Tz9#6vSne86-Rvaw}wt|{W1IG=|D>GP~2lZ$(Jy%+j|5&IY zB}U*2K>N<2w`P7Ag!yBY^DKL=@mdX0oeg}xuMe}L`@m;~wuOrGUKv9WS7@Wd<&FoA zQok-N;`}PQbdqKTs*5Q_Di?TWV94$ zbet~-GNFqt(+@TYP?-ZxnnyJpta2QJ$IFX1l?xk8X@Igc-q}umt9yNL#lq z)nk)S&HFL-Cmqtt1Z1&US-{jfAWYFRt!OD$YjWgea>|13L_X~nR9Jc^AdxRo*6_Oj zoP9+?mlz^ctZuif#+Xd-52sPuwaL0;kFMNMuY!5+IqKagKPK*uqv}k>pk#inP{0}j zmKZs_o6w)&V1V}2E^=%@e>HUZ9YO8Xu$)7R?^!K5H~LeE86YEz?k)25bp2p*m^uE66n535HW4x=+coa25Q1cPzVuF{ z8RkmKHXBsmij@qc8j?K%?mrx3OrJw4MkNRvw~%*|#N!`faCP-BfrhQWT24JW>)4CQ z0>UC{mi0oB=ou8E3!6GU#Sn6ag&g?$T@IWNx3lwiS@==8{$l@06p*rWL+H9K_Ym)9h?Eb7Qyl38_%P1xBt6{l2a_=;j?y4^P&f&IW975Gc^8Ymq1xO9zm8)fbI!c9s&ADmvC1B=utSE8YIRTgGNKdfPiqT zupV;s>&SSbfW7~$K+0T^K*r&2;lF}s;FHmQ-FL(03IkjIyCR;A!SjCf@afM|lYKu# zDEjZDl%-L+CV~l`f?~GqC!g5_mjO6UVE}INouJSxcB&b;~N+n zDck64D=@qc&j^wv8gn-xfSN5?^aOV#3gDnNmq-a=L_%CdJya>C`WO&3A$X|G+G-M z$=MtVVr4A(gqH@3tE|^@UvVcMZw}S?VXOK|VmXjR!YXhXjZSDehU_rZbis*BKfL)# zQ|1?@djPaQWUHy>4Ap`SIf|MeX1|Ds@DOQ=6iPDhNoK^c*>T#c3sY2D-d0N{pd8ed zg7i9s*wWjfwYja+ehyVw2>W&t(IYTMW|-$ll`GDh9=1J{V0QELEmEaQAxukt)C z3ja2EN6bsol1DIfOKqf}DuZMAPV*R?>$eB~)dmUA(jE?9Abk#hDjYY%+ce)lZd}xt zX3cC_QzsT3{AM`S^<1l^amFyhsi{jqH3|YY@vtK5Sm=O;Vv=SeYoL6tzIbZ#(}=4K zquk!hESYOcq~i}cof|{vssCjh>ki7Uuq$~6-Zv^f5dutEW`WBc7iF4}M#Q`)s)8PD zMUIE?VGIRIC=l8nNy+t$7O=lfUq5ro#Mg&#jmsmhYfi5IkzGb1T}#;)K12)nu%!wR z#(Noij+M(E(%M$J_6|8mFQq4ze~3g{d%!&c$&kCBrtv%6{B|A-R^?Djm>ZI1pY@y& z&cCPcGD9%m1NyMXc#s3UtM>z>1T$1j0ionVUA2OT9*bh>tq>Ho*5J8p$`?sah#=O! z@X+i$Dx1}C$WqL*A_k)PI&N77IGmI`xw|cNG+R6s%Y3Na#Ju%=ViqI!@q(p{Q1*?s zQ>x3T;`)pNxLcj?>@S#35B24wLml%N3I~T0yx$JO!k*r^chat$+9pW70e?d2@)~qO zKn8Jd#Q!QzeOPN`aN2jR5rQMm3~V@m`|&Q(JD$kX4)z49u$-%v5mOyvVJzV^PLU{D zZ2!z68XISLGNXZ{`-dw(Er(Z82wda_+*J;SI@l#O4x`roJtlF*J)lO+`*YG7B1F0( zwj>??R(rG`XIN+XK|TzfZlqpdGhEvy#X9zK^d43Q+4|-|E5iB5yi)Th&E(LcGn3h@ zA;`VSU`uKXBj^v)dj`(BP~(haMN4;MKWpQjl(pOxKrM0zZ8#E%xvE-7irY>%LCk$H z?qy9}?@WFj|MzwNL0($HeJ_0H1Zlle>$L<`BlPM|M*n#Ffswb90-;9Q66G~^ipGH%S8rt1UGh_Ik4c4j9T&v%lO|f`6 z-{eywbH4^YIpGPniZ;=HimZ$hsBs=svtJn>mA2P+(++&TT@4LjZap%KtYz6I_ot;-w8SWT#`!0; z8%^giR^j#=yP(*5TR2K$seiInor`USIF+FYf_F=?sw|hq08+s6U1Eh?+{j?YZ`i`& znkxjs7rZh|Btn)H_*v%;Z;y&*=oB2n(EEf)WVDX2Wt0iMY^AJ2yq2h;dJXdobXD8O z&-fUKM~D1Af*W421UW=)Tro5%)hsrP=cK0m;v@^nmT({1tMd;6@)TmiTn@NTvChjd zo}~Bi_%{#;(ht{T6j%ROUb&SOL_*~>rf(9>=FcXotaDf*#Xu3CEk!JjT&k+<0Kz(h zr2%G_71OlYu;Y)gU>Csq;14rb>*$@az|I`(Oh|Z&ch;u9f;Mjt;9JBo@)PkDnL9>> zTzD*xKAuN)N%t?6Xfm(yG)S2WI#^6wwwEqXm=l#TT~l*8-bR3Yt(1t&7i<@Jc(hb& z(6y>u1=QEqMVg-lmRkB*rI(6{gf@akD2sTDkC^FkCD{2}l6Lj%3aSNc6xp9>NI$Uv zzrYc>fJ#M}71XW?W|29}1IikZ9U^Q4antjfqx&!r@u^sn-tgmpBUY_|Xh&OxcDTcS zxij92{9xE|9s)TpIfy4{G`vGCDDQCd>Jtw@_GrJ2I7du_Z4{ioKy7(s&;Nm)-VN;$ zc2l}iOU<#MI%-tP$+_q*9|0$^g4}AQMyt(-Z(nT+xx9eA)wNnrNkZHB|BMcz3%a6y z@9o^JHvWs}NFOi5v<5JUwdh_Y%$}oH4B3pnAUn_xT9kts4ty>1{=xO)G9ahm9OKg2 z@+v~``JU;>~g->ET^={CyF5dB~+$Pd47N?}AdYE>b4pd~^oGQ4g1+Lc5H4)YC49)tklRaBK ztPQIfd;#!Vhbq*ZnD-p#wlqOU;tli*K*GfE5mt3G?DqX+#G~x0L!-522OPVY`ck_r z@CP&9tqYLu+D<~Q(Ws+$z$i5-~eU&+Kqi41)M$jg}ehfmH&WquN>^-^-LEq$0-3AoiDaad4i zucH$Z&wW|J3H^i^Vc9J(P(1G3t;xl3Wh-o!&0K&s?qvpax4fkac9=v8TV!$QVy?d`5Es}CshMqwH%a_HpO zh8#_9yPjkZ<&u5?XRqtm=GAW^Qc3H(GNi*j<>`6ZrXzJLm!BXQx*jg{*o%BHAVfO{ zLXx(`{zUX*-H>D&_*|(JKczTBmd7y4QZHrTOR-GOq0sK`dCvEB0iHALPWax13&!tj znn*P;Me_o#7_EU-nb3^lcz6f6(GqtTew1vc`NbzPzu~w6d_Tyy?w6$MFc!Cwz6!pj zzIaLy%Z}_JM_Ij(XI4dY2-SN6dGFQ)fa2Wo^mP(&^t+3%__NCk>-sZ=#Sc3l$j2nU zKZ!lud+ysz`%h%t4VG&OJ~wpG#w^NuYJom^P?S^o&;iBoRCf1)=4y@H6}T%P&)N}f zIDOtq3!d^d^#mc3(CVzs{tOAKMJRxo3uN5J5p$LG6wYj{0Aprc00~xf@k#NeX#}Zr z*qON=Fk7x8HE%0PYkC3Z)N1%JYld1Vym^c-m<3B7MUT`NKu~XR3ja+v7&hKFv6nmZ z`(^A0u1vk0K_%QLh?%-ex{q+l5M5=tLX* zuN<|VaI-o6MWzg&9H{qDUC(4Nyl1I{i^b}F0~&99NTC-zWem+@ZTo4>_O0?@`N1P~ zaES_LR+JeR8Q=p)RVV?uM_q@=J~%3)J5u)fQ7;Z@G*2$NgNn9Cf(uK+l2}M3Qp-Q;_x*o6=qi& ziu1~Il%PO0Bi+YJxX9~ab3>=sA7?CPLKD}t*`UT;wY$VB zV(Me{^&x~cq6UPS)^!4dcA=mOg(RiskQ zF6;}a7CkIqE}^MrJ|zn->KIs-G0d8pICQ=H%>fR%`(6PNh+`r$?@?2kLPUc&{Oh3# z!}f3(0RfO801N-m0nds}amgMEfpu04X0B!SE^s~3>ZSf=nOQT-O@Ngtd}8%~@5?@B?>K-DoZBmi6!oaAb7OUn@^7|Cc9hl%3xah`nFDM<%V%$Up9= zu}Pp-6KDK5VAiSXd8|sISZumF0JATwSk8e zDaQ|Vn8~vk0gD?Mv0v z0#P3D7YHl0*V19LPY$f#Fg=DlJHd=_vaaiyED!@vd&e!r+)h~RB4+4+=KjQCLrm@F zFei-!3Rihs9^P&_HJXj*+Fzk!gJjGgpx7rWUjFprc+8YJ!9b4cPPvzxi5OqhR3`Y& znj@+NOa)4iECdj_E%HGPq*%mCa$&fh!jyWhc{$){pSTdI=z^`O zV#Z%YWo?~5RDKEQ6da+PU6nr0XmgsXn>{ z1yN1kX6OrR~FAB%t`JY}WHvWFT zgwAGM&#~_`*4Pa_QvaT3)r6Lkk0er(k9oZM7w-lb=gyNF!nqhtyqM}YLOwKeS$E$Y8d_0w zySxKE=sAm-IiHZ!5h;@^MKA8REW^it5l!>`;JKXpB2LTw;khVW)!NkcvIv^*8HT^b z+|EnC88Ep)I|Snz`(t}Q@-vFma80PEhcH<91_6ze;r8Sv2HOlM(V9=wc4CFyi{HoU zxZm*bCsR3Hz6d$-8p5wpqwXJHl_%cVmoX4DQxvQ zaNS})O*zne%7vNfRNxdD=}ql^3$N0ECm{o4D>uP&JvMiHdx(WNGh0Oej6k#9^W8CB zhILj>_Fx27xM;#o;mY!xcP>rl=yN-vem^anUE>=n zW|7-dCduzSyKDy0EHvjGrpJPqm7ykcaZMCKZh;<89_wn>09;2K#vfzj&59bwr_OBv z-L{_UEHv7jJ~n5h;40061$pmc253oTMe%{Cm4}w59f5eoe86LHgCZgvxUDe*Nuz*E zFMz&jcFV!!Tjcxycw9dU?Ydo;XI1CyG~-_!*G5553~@&F_FU$k14b?_g@78;jZA8EE-Qs9_|J8xG$O^Py$~) zn6M}{k}YuV(TBtocj%TMA_r(jIbpt$^)rpFE4g(b=F?O7P0>!=+)@?6yQti^WJdhU z?;L}z{~0asG;BpX7i8sPCKZji5dF(J#i&%B&lF{_xBuFcxD?D$gMI_2nW2qg>9vZ4 z=RU`$S9{p!^BH0oH(0|f$9WKB2X;_7AvXL0SmCv$I5ARn5N-(P=Yj)y?!RLm-{GDf zSBNya2Y8?y(Rk<*{0nsrH5_U(z;MxZ-#n6SjqY<~)DhJlA6pUSJmGsS;e5m%!U8hu z;5${=lF2EIVX9{6sSL-2o-NFzMzdckt1y>=#HJzBwf49M3Oqh5oGuC-G5D1DeOz&(UP{JNCe)V$o=r1j`+c8=hjZaQak>#0Hfzc4ZCc{_i1<$ z0rYyd6dvD59<^qlvC#GZY!BT^(o`dU)!dJBe_iW+!u2GnEA1c(ylyvvi{K2sJ{H{z zi!KxAn3NsFB+RS^AHy>_&JV(Y@cT5_ef|-ovBs&E-T-yYOXAWuf%EqlLQ}b~1%L_j z!6-F>pBf=jA!!;XyHG0Bkh=|baw{3*j8-wM-A{lTfd3Tn(6=uMYE*d7-Z#wQtVsPx ziY2G_C_4DroJt{TYLxi1B<1_egVl>GWZdYa;_=>AB<<$8IlIiptb;YaSZDo?|1g>x zv?9lS2N$eLuF`1%S;ay=nBnx}3Z zYvE(Ri12}YyzgYL4IX~Gk58qIdR73S%0qx_p>uiD~I60U!!dP7q5%^dQV0vG$ zV;d5w8@(egpzHU+p!E-LgH>z`@W*34$OC&}F60m1xC`5<2HH)D4Fo1~hu2!1J3^<* zj#E#I9v4iKE(56}Yyr!Aml*|@dm|v#f~>G!;KmJ;MUBbt&1sXYw-FVfM_^q(O5v>& ziffALvVBj`(tMM3_;{D(8DNE%7< z>ixET;cq1kdR=jq6T4X+=P7MpsTv(kV=03Yui2owcxZQkX}oVp5+xc{G!}-=y0V6= z(WC=_R0R`W&t;!gXT^ps@NINbpYPE0+}y~>i|wb#tGaW8VaS5!Wa41jk=*LH7{0d$ zGpoH1I>hTbkn5=%138!59?Cl5gFC(K8#P!4yucx9Hi ze1|x7&-_>h?;|+h1}V#b9Z?n!({4A}RP}&{L5btt=^}VDDj?~5JmBj&yfO57E+VWl zaDg6HMg6_c({}xD{!qX2_JZXB-(r4pSyr8d}SXAv{Bk0v5Qf1wwXENH_I_b)SUOeEU4Pb>*S_uX`Jt z69GyqD#8{@F3x0Qb69Ne71|WWw~)_Zxb<;bONo#Jriq#V0L|;7;E6!X3@a*GbJA-8 z;-F_T2GU=QgPnY|+b;O?KyQ(jrEFF1_#%1NxQOCiCY|9(jqN6YGszsbtXJ^d$v0NYoX;_$1cZP+oy zN-li1k>2F2{W(aJem#fAk4rGaq?8g@RabD;JVuw~39kEiQM%KvS*qCqms`vpiZcDh z1MVS_N&N!~@pcKU@ocW9qI^yG-&C`#RtKB$^bq$#crzEi(Rh?jV6%@JV$e!>gESP0 zy*?1Oxnq|j*Jn@@n+sKB_};9U{)@ft6wWKXVMF$Y05IEg6WBRS+X!WT{Tah2uqHQW zc%Jg4=eE6i8LyWtFD~9WPFwt``DWOfy7Qv)clLrQyYL+UtdSojXT}Br%6bCX;!{60 zHbX#k1;Vkhq(jBMIZk&4^kxJ2QtjaoNA!^>G)X427GU@bX26R>f0oS3ZFAj*n&@pI zOt%%pj>c|YG*w3)tDE_9M9TKBgTa8-l|Q=rJZ^zbw4H8Mcr7XBML=Cr+-{*HJ&vaHVHCMAQGd)|om5c_@56lFdj;chyW*6O)z}= z8?bt_Fpj4xnAMzG8)m&+#e*OH@w@PyKx)P##Wvdcj}RbYOpmUQEhgc*w0P>QAR=s8#VZBR;}7eXO@xszV+?=ukF6h+ft%rA}^ z;iRV4iRfHn8ONPI$D{GUX<=Gzpp8uH&G1;?FLxbb=LH7{Y(^3$OZ)~#7HfiOeZ7O7 zJC&)b!fP@qUWH0e)w_Nvo*Fs8KovP7e6c1VTz(KlNB;ay#RNF|$zwjlSlRL8`+B6l z%)uKzNzchu%1d&GnFBEyFQKS=oa>EvYA6bJFJd;nAb6)$2{=kEfbo2RoOvMS2G80F zmL%g1vv+wH+vostCd`gK*YZxblwVtvX>?_Js>U?Y(YN^b5*?eic&mf%i^F+_pE{lz z`9o@yje=><8F)QUc<6=@nyL+x0Xj#g5m#TXKXV3!n!n;;}l9=jgmXxjr&IW$3@ zj%UsVj9><{0boOu(XYT#Qwfmm!9q#W{tsXL@ygxtuZePqrjgwtykmztBo?M8?f;4m zxN-JV99meXU@@0DOkvt4jXLybG$Wt0r!Mq7k4rg9a|f~siuO$lAuY2Nd@}p;<>weT z@^sa+GZZ|V&*$2i+b#pXD9M)lYR(AdoQ)YOEsa&kIS4R!B~O)O&G2Aya6+Mo?GG?o zB;+hUw5s_IRnAKzKsKc3>Mt_@GsZ(v$5DSU9R?iTb%U1AxqmU|vf*=?E+(*x#m}z^ zmrbGA#-av(ql|i9${Bj4$1a~gc_zzu$w6p;fBNx(`e?7=+n~Glie2|EdWD#N8i}$! zz<6JvFYh^IvN3;Fg2RruZeeD2%DcuYS7+8iZ?Y(earFtN@0H=x(*-r{2 zG=~LR)e4-jts=8Vqr3pdc;)30xn^^30_uyiPH+id)Kt!IB0uEcY#`Ehc^hZ43@8+= zRlwPm?%7ph)gm*uf!IvmkXl#N;B(1DLFVIkuz+_nZBoDs5NUl11E(a$Hv>JzEC+!* z_v|qRegs1_W6?)xQE>4SAQuSm2eU&8=}dO2wWxJj?2Oy6HO`DloBz)mY*`~35B&+* z=I?Y~yRqSXxJKe}b4DD}s~mDCoCSWVommIe(rqZ{ccP?vk(J#TUC%^y6#dJFQQr`7Pzc`uu)Zg(Q7I zvNC4`EYO~h50=fakr%%+5O+VTyT0eBI)nGVXi$Is%*$GDBZ5@2nx+A5|1LZizgb+J z#ayAW`7#>o6F~!_seX!&QwIP4QZ*BK(V z$VqQzd6qwh{>-WGXRSrsgzKt1nuhfBh%UZ%YT_svbd6aK zcZ=LY@6uStMjPDb@3~%XMF8+9XWbWxvDUa~q3f7K`lwGR@Qi~yu+z=-?qRkY^vChJ z+|whjuKQZMb6T_;{bV&_@;KFc6?u}uG<=caH@3K%wqV$3wSHw`+sikD9nBnTEL7C*cw!{kv80mNGWM082o$zma<< z7-;9i(R0lX1$DQ_0pGR1lCQ@SrhVCa_Dt!c&UcI_^S#EY1c?Z@V zJAWU%4LK_B8G(W|C@J1V!UbV?s*|m?*QX@HSqSbqjn2uT?9R?&=C~$M2B)60qlMmn zL)ZW#ivP8@^Y}zW6vrzSoW@|hXV}3_6VgbypN%Ov3-V;esbk8B^00HA8mn^`v~^`= z6$KSMSEQNjAbYH{c4xTe?vA`0D0QoF$sA&4GdVFlAKilLL0eP|Pv7w=jRqc+nid6Z+B<%N;zqRZBe}Vl z%3< z)hjWb<9HGT6|gh`?-T?RaA4HM419XZ?j!YT z=5wdA8yFc&)@5tjw*6^~ySk|oCGX_oO)Hfeb=!gc>HIe0YZ2yyrmX~na~*=3dx|Ir z-Sd}3HI4$V&nF-HoDHOmQU4Jv$k&(z!WF03>AC}3x*BBtj=AJm!)=PzVIivWq?#Jcc6MXAT`FiQLkcrt&y&(S&W(;fpvfG#CSDj0$1S2_XKxkeapjwUiBf&$#1 zT0lGdtM_?kJ+!{yvcwqx?68mg3Zt`1{O)hmAe)E_^1BcC(^g8M^8+gLtUVT)Eqp^P zB+n?kX*SnYa9`&$i*q?BtZYsfuV-D*`?X45F{`gSu- z6O1Zp8<^1UoLy&IvsK|xL(t%J$&h?8?XUeI&Qy~-KURvZ;$Ic&b-5KgSS||r8uxxf zS7W3sQ}WSabP+t{Q16&9Gq}3=F*eO9&?Nf~q@Vg}$N|=P$CI6i%#PG432m4Pxx|4Y zUAYu|_bHq6%487pE*n*YJx_)DY;PCQfI&2FO}C2pFD0nhVWXC29adUK%2~7t=s74= zQu)|TS8H|Za((thtP|(>L^?sNK@MvCqQLPI87{M;ZHu{`J{~Z;SEPU zUIKP0ydGIl&capT0Y!oUMc(;INA>87cH4;=IzGYC^acSB(r4H@)|?dR#*j=wtAIJO zNPJYeyK0WS?wtq4M(OIp)O2EU+*nPl5GMnkFjuF!PY$(D;}+8!K733_?__&ZW$3cx zU6=jhTcp%7dT{7%CtBJpB{fMT+f%iug0$L@(_HdtP{y6jyTdi`J|Y17nI@9gEYq`U z@ao{Ad(lUO{T4Bh89xm5oun|h{X^)Xf@o&fb88_aSM?SgXp7IrG8mH2vyDx03CB8Zy} z1X5jSiOx*YgTJyVSV|02N4|Cq)gQG3E+Yv-;s-7xInRf5CmKqfH6SO60Dj&wzUjzE z)p>(=d7(V+dq&dmZnRq-2r8Az>amoAhQ7qA458Pcvp={V*E1Jyr}o3hY*S4kTrbha zC>8Ekh15J~YV`u%QCkY{9~BDQ>&5fYT`l#>K~|ylYgTBHVOYVDT)Dn2{+vID-LQtw zoO+$I)6NtA>oDXB2Iw`+>b=Ia?<&4of-hTK9i-#H2_;Xv=d%vEQ!CK!p}0hr0d z3qGrsGU_27Mgcvtv~35|wI#9p0xZ&RTO!#hl; z^{^GMOpA4^DGXoJ5!Wv1NJud7BrbWkXonS&P>9h9te%87*-*bYk`4;5#g?IQS6mWc zzDw5^R(vu&w^52avu{XI`YTaI5(kr3kY|nuBq;{~w%Q_?7j9(j#@KNsZe|`*WGbZN zg&JBQBbOGOpGrkgi#6F%kU!Pd2@V^r138lZ=07}_+V8%z1$b2f>k&B)$2V5mn% z=s3iHk@mE%pt0P^u7RlU-gYs52JUtnCIDa&F$~EEgr}ca8z(tcsx(AHS+>+l=T2vn`IT_VqN}Ut-OWj4dM`4qjPQ}#L%Zdz!`M&H^R`8>&E2x$E#iScTQw;)b_U{ISWpiw?w?P3OJIkAYu0Kha^0OQnS z>$xrmO?2X?-sGX!s;Pliai#Tis^&B8VVbM1xyREaLV&)s7oa+u5a93i0fQfj)xP=2 z9Zi+SO_}dc)}S*8a%RoR=tKf(JE-YPo|*p%!@1Vk;pn_{ueGC0tGDsEUHHr3YJzJE zF5R5vd&xjgVH&_eC?f~cZPfUz5g?4VJ^*YKG|q`z3tq^FYYgOPsqg!X+n$wb30-HMmz^RcT!4_d9W`EsGMu?4f((f zj4PXkvoo)xrj1)U2?0*SyY?4og#BGGE_L&)lpel!1AC7fZa&|Uljh~!#I%AW51YxE zE>$^e7~)Cq9DE@z;5x#aFQAzMtVBODUvQ}gH4e8m5W%;ss3z|Q2#+D0_snHd zQhyOK5j(OHLki5S|4M7)Q3P7B_2P8xu3CCU%k6Q-;X$Teh7_BRxdMsyONTTVVIRzE zx@g1eL?kn*ryw1UWHc;OaH_h(i8HJZr5e>_Yb`jz@Q}4?H`Vr?)AaXUkoZm8M+-AW z2wFlYeT0OkfP0%vV|+2-$eSPE89(KPWPDs*sya9@^ru^&Z9 z2t|c}nwrPUgXKu4OxUrfBKnI~Z=CZwLB`YsAaDL{cgr4V@k3P0jSg6LiN0Nb@SoS3 z0z{Rteu~_}lSaKmIDTomU-Jpi|Baa22;`Ie_kyhts5}E1?ur>prCRf%$}yn=Mglbc zF}bhF2tgfNeZ|F;349dm;)++cX2UOxu<&@zDiKfcInZP`OpkVWN6LlQ>c56QWh6+W zNn=_BFnq16=+tP$5qG9YgBu%(G<~zKLv#^`{VhcJK5h{>;-NOrcBKxc2QcGdu`8k{ zb5FIRY1@f)8l+CG+j#l4dKdalc`Tv2B3)PG1FD&4o`aj(-oRVA*|F7Qa{srRGHXTR zPxEp73pPId)jY`fXG^N(^(bc=G;+A{tPT7E_NMt;Y(U<-|9SBbAN-0G@9$I{4wcA* zY>Wo~X;ZOd-(Ou`I}u$0Z8Fs~x=4o0i$OY!m*RIMP-av!uri8i>F*#mR<%^-2zz!N zyBluti6sL~Tq+%|c^UtV|G^2F7tx>MR6n3T$rIO`t3t81l*Qo**8P=8>~piwxO@lO zg)Z$kC*fpI=khx4 zheJCq;pwXf`z*&QWUj80qA8pKRu?nSLg2m@K8eLsNog}7rw+tDjpHgsvnY%OA_KYo z*<|J!{gsBuGM>brJ0E>H1VXo;zSpyfgXQ}+v&eL<<=(TvnMHeZmt`5WaWYS$$dmJj zpl-vA)NDAji+}?h;4t96=!+YTmpvw~d*pJ8RyABYfFh67#NA= zLS6j^eln$!dwL7AJL{XJ&w>{BN(oet_q(*N|G6~%zU1K>>fp-@nF19;0-_}>%BcE; z&YnhbF6ipt)(!(U*GM(ftOyJvid?;(XJVQ80!QpsxNhTh8|b*^e0%}yageLC;czeM zaNkxxNv;6T05uy6|AyCeI2%(X$$*5YU5X-CMTyo%E7ND4Xe?Pyq%LV z8GLFD$GPK+N2Zbsfi43C8XTQkxvR2)P(d%+6+c&b3t;rQ$8rvfojZsmdl#|1k67Xy zq0EiA&cLQ%ZBpZ~(57N@GE9X!blMQnrR76V@_bI4DpREYMD^a;IHE&F}t} zNQAEh_Vh}46NiV$)nqp?!3{pYV_#bjX>nHFje^gkLztrpedHRB5F1^CtI53cDD8C9<>l6y~(H0~+!%dyO#{#2q47F}ozy|0Z&BdU8m2KaSB zI|;#kI}gXh$9+VNBSc=R9QR42Ev_H6Kjk}Au$bD1s zA-hf2J<{##spV`K$QFDvJo`;_NTkLH0hMdv?|E_G0;zv}}uy?JD2L@q~D zge1m*kmL5d|7=Fwah2HsE$;$h!F>*>SgV~ejKqDm$saT&86$9#rPlr2hQ(B|d*i4a zm2U$^TnlD;MMWiqa!ej&RjRYw$lbojd!r>w*-rJ(E%7G4V1?q&#jX`3R9`&f zD`%)I`eWK||M=2^A>5uD$q0`cPID8Z(=%V~pxsgI*Q@sTjT^x8a0aO7G>S3xe0aH<@i29V~;5 z)*ot5cD0bjL!NjQpD5VDE3x|bsek5goB?PuUnx5E4D&e z@F9QzvWJ+=b?mcS6j#ZlG#vZCh~T`lBmj#!?if;UFsZESJ_RpxGGk`0?_*n#dW@VA z;T|RV`iwH%Og*2 z{Y+4Ru&xUM>eQN`o1Vc|Z-d2F{jmJR=%(uWW7Q%wRliLh_IhBh3pbS9BY$c*V?SNq z^Kg=A0P(m!sGxVsU=tDEWz0&xk+!6xA3bTL20=A=k+W!OR>31DhL1jL-Zet-K9ES6 z=)Rvyai<)PC~UdF|7Hz#xp<8gEg4bR=)GE0ABL5_ zAkG!_u*BB@w2R!ozw@)&jcL&~^-~OEnPFdIhmsedGfbX=66p*@LErFVS==qJBRE^O z7VbeZ0!Ji7v0zMt(TOJo&8l{0$&`cYLhg#9mRmkB6R^Vj!LqSh8PgVw3e8J4#4hPM z{Od5aPCKYN{lA6Jxj67QYm_dZMlyEuu$I5_rDRCWV}s9R@@WuGODLzI!l@)yAqY7| z*yv6Kx?ty7biAP6O7U>Gc2h0VNE#@(4R)=Z3%p`>U8tZ`6;L@gT87@no!3NJI$m>G zLKJ48EcGVgqhutoS?>R_t>OSYav%`YL-nz-p%yDJ=6EcOpDSFH5k^hPZgI0k{(BOJ&&8U$;LQ^ge?I=+PweW0pp15wmChWhnp5hOHf;&_9YyYrbo8h8S555T=pnJ>f+y1`1 z=VK1jH+2mURzwb#w=w0KLELC)BMrbvWx+)R>g*j)cun+(*%3a|<{>&97&jDv-9z9} z5XzlpUTgYVTpD!xL8I34iw^=%Y<_ProL7@bG_x=W`7CF>uutoFVb zGfySEuIQTwC@?F44%^~4LV*A6y;Uf!k)#xYcMJL#ZlX(^c=e9+*-PZ)qKg*d6pUJA z9# z)f4~l4sRcpUHlWtHVvz8(ADlktOwpZcX`*4C_1ZQC%KnRhzxqZ3i+=oC(n3`Tb{G- z4uX4h?bFK3?&TBOwyvinrv*esshh~#$S8S8MU&J*I|mpgCTPai0nMBW)^QQ+3V1kM z(7&Zb6@JzAPDD>(xCpm=oC>lUD0|Eb7;hH-?nTYYit;)qRYWY0zMt@5gmS`9oi+&q zxVP^Ymjq5~W7Kc0O{Ad1fIz843(q})g+Hdp6>$wo#?+7nuY9|ag{3C|l6xMVom1?R zL!yB0Nw)7K{iIc**%Xw?$Y?H&DDyikAS2L&4ZyiocqXgh^+@6FM1t#}eK9V~l44d% z9Cou8Rmiz(s<39sNlP_$b?DDD+D~q?a5M*H3PvlQTx{0L1+9bGL{n2OY!t|5#XrL7 z;>K%97yCXiHI!VOyxhbp+|_k~R+;ngY7Mng7H-5;lfNBbC{Sohk)ZR=>Ip)-u$(NA zc6)o5q~$#}%DK!H);oxfKuCOLf*i7Pg7m+9f0^*svOAcnzBe2@Ra*%Hr)UA(3HyGT zlFMV3m+9((6%Q2-D6x@@1Km@Lxw5CXoln) zhMu!(fA_vR4sj$hc`uaCEEr*?9r$Ov>y>wo}efj)^UiYiad`+Ik)pnK{1TUIi z@kb(wCkRCpgW3kP%l0W4ELba*FR<`uF6Zfyksif-PAg%w*L;(*MPU~t2`j95t{>9{ zY-kl(BrORWabG0e(AAD^k;D#VT}%KA<<|8=XuT!{NBI3UdOGxTReO)_R~m!@)jWL| zfu-pkG%X$b6gL$gM*4;ud`w>+OwL6wHm4_@O8aCkX$L4pKbJI1$>6rl;CozL>5CBn zqyY%~eWhZQvq!JsZT7xk#uO|*=0zZMr-@VMO%fTl;L0byoZ~5XTG$8^TET;*M zY;uwj5mSDaCz8z}s`l$%+W8o?QC75FnN$G~cHu%*B?&s+6FEyS4GvQwzq?cpD8bsq zXV)Nf%Fyg-nB%`*9U`%Q`)RdXXfZ^v$Zg&e%zj4pYg>O}r>DS zB;aFAo!{-JKTFZ;w~pg{8+#+>D~PWwSY8B!AK=01{c`j=a+K=u>_JOOe!K$M2tO4x zhHUreuy10(AL)SI(PS{!q5vn$E7vZEa@3 z-lc@T>in|OwH=i3XF%melhr~5x=Oq?D@?yPg&`)vOOaa&*e^5&wl>v&h*XdgE`3#* zdM|%}CiR%6g5M0HwhDBQx!5zyJi49V0o`_Wzt@DJXnjRXRwPm?akyn*0IH9TVPRS- zhb}}O>d=`y1dS`Gjv-YrHV-2na-8&Y(WwR)v0;sKKV$@!rm_1}bIUZ3wCi z5OwKKm1vpD9)13D5#kP5Xmg3``>VYy8Pu*IWUL)e=e>>H#I$yE^+Hq|v46hQqh@(= zYKvyV4T$PS{>Hdb^uxhjxTIkn3!{4CHMVDPkr1+NUi|`dph?531*lGvpkNArk zX9I8b9gWz!L$L~g8hcx-0t#gfvmo0x)m#cYw-Hr#c`RYhF}Sm{1$)P{OyJr#SP7-O3YHe?MG@gc;-Hv=ycrl01t4TShoIIPzc{5Pt?*Z11sgtsW z1$wD#d1cy$x^e*)!%V~)^cVvcEWwSD*C_*<2?g|D=T*7F4k0jI# zOxUhOn`8UKT^*pPz1kW``l(b$_3t5V6LFkL^KaCeeFsW~)U5LuL571;g(1G;d*?8i zb$+R)d!dPkn2o;9lrENl(=CmJ1*_n9m?JQ07tcDrHwoDA>5CxCTR*!8foR$)&(p}t z?~7WBrXn~=b0EsWnKFc=v`S5DsgL)2(%x=$Mx=tK=<)w8cxasX%G|{YMg()aK1~Fu z!ofWvtM(M4O4)Os-1iwi0i|3iR!l{k6^}hG&d>9cF?3GD<}ivm(*@l7vSs@~s)DI0 z8&=|&N^Rswk8!TRoe?60TceVggM>k4@C8C9Q4zj!a!-?myBGPWe3=Vcm*rz1HJFtA z%Xx1%1ez-OozF<=6Rqs`grF}HVs&J%G_}|!bStkP2C$bQuRcx+3eyoS+qTF>P9UPB zfpNZxJnt|UHF*wFdbZNBZs%=`HOmoPu0QvIBZk|b)DQSDiFd{ITFRy$FUT9F5UzB& zFAX<}Mx?h<^jNoSd*+A&AEkt1+|miXk@i47q5+4zETb&9IgQIO#GzVxxlEt+F~mrKjjt zkB*+?9+A9$h$Y~^sF=;4qdY}FbFe;XYJ;6PwD+f8;wVQ?+Vj~fq1q?7f?0=VU6VCG%&0fr2X zXBOx^z-()+_i|&<-UPGo{cLq>2qm9IJ~VY0EyyrrH+t8-<_6Q8-xPJ{1@kt1%fp=# zJ#e;7HeZyMFH=CnObEydg#C~nDX0#gGA8E*KRhuniY}AzkFh9m5AZ5ah&=XGUorjG zzcM!y{+Xb#K4Ruom2nyqB}h@@0Y4(T1BsXV$WWr!E|sYN1fqLIWV=O}FJ1ZpC<(U^ zkrb!iIjDu-(o1330UOnNYOXIzp8z3)cjvR{t?yGzYgv=g;gcqK{y@VlC?(S-hgO{S z(rPGZOC&&lk=~U^wVtc2=xKOBDi0Cw7jnz{;Dfx!As$bpxL6NR%4RA&M#<5TZ>uef z0n134%|>V`;k32E^_&KAFqV!4d}U#a`SE3&xN{3Qh+z4Nw9!3@VKSsf7W0rbm~a(P zKlxP7nKQZ0?#c#@xvX{bm}fBBhk_$O!UQnG7tnjZsDS2lJ8aLjyRTofy^_@Fipd@_ z2ssQ4`@KM*tOPR=$ndyIu>cx>@FE*;@{GsTIUf-5u`|gDNhyvHYMw zFzOh;NrUk_q29l}4{Vak&Bw15XdCE2sxMVzQ?Ap4)A}8eQ%ACj{nd z#7$5ab0EMC6u{69Q(91(A~*U&ysT6$^ZV724y8G_^?_(aa)E$00;H(5SGOnv_eFY{ zINi3=h8o&UW*TZBG0&5gp%=}taBYc8$if?cU)wO}m7_D#65Ed)P zEij|!`S9w~b|42W(WrY-hZJ3j9^MffmM9;6#_%{=3O1B5YgB>c;?{k0zb^hpDixbA z=O2$CvG6$^Ulc`j7=4|t1?S4*{tCZsI#KH&sz6D(iL_lzRYtHnlv7uW;l*MKkSnLN z()M9Sor3!*1rhX4mC9pww<*R3ckF?XrUWCx`k>!@AYV?OO`@y49o9;N8;K2!nZ@8F9Nm4hJ_n|AV|pc4Bj@m)_ao!tmt(-VEy|xV!kN-sWd9lP{gdtDP@9xmVKpXW7~+tikCu)@u=a#Po2jRM^!AnvU4m#P73uT-E8 zN*w}a1#jmO7nNVOb=5EvYe3Ms2j@o>%gNQ9uyRNp9(^SS6B6K6hRCKD>JHX?)q#EI>K zkyZj`V9^8zz_wTTK8O@H#?@+BuNAkObamDu$Qjpi1d~tBmi4P;_TZO=e>(cz7F_sG zQy_4EJDw$&@XZK!gaFw{t~r0iyx`J!mJMZo#P;Q#g=UXCkOqF%XD;zkZR%8Pv4!)2 z5ZY53miKj(V5IIM!B0_-kh}6fuES}M@S+}SLFxP^b7@t}?q&L|NF=!)R9vVIK4*<5 zz$@#85`n2SgVqzs>k!Jd6i%n+aS2JBwcP?Mme+%%x7-x1-N9{XmF4vVcnv(46JeYS z$sRcLg>aY3t3cj#e$71(?gOY+qCZBJo>>^H<{fR$H~}{ZW|NPEkpaG={2(1~u~!Eg znG&ih5KoJb{eZG1+m1rwFovoZZyibY4H2Rg-880Q>(z{I$>&0N`pnB2u!PEj)=L>2 z5ms!*(egX&`~}SNhi&c%2^cEN@7o@ho`2U3$f*{YMquyqiM%uP!^8lTF` z?z%1QQK;6F`~%d{gB56Xc_=fOYk)b9V-}4n5-LeNZ91UIXGn8{ms6dIXsmz7&qN27 zoQKq+fjudv+n%EVWPnj+0cikY%TEld24u8MmIg*|kqfz3h>c$|NpB-@t&crU+L@nc z1I)Y}0ysnLj*hsW z$HExPb2_QMr5I_0YCU+?yJ7rRIcC%(`BexKO$#oIFQUDPA9%s7qg-`c75om%DO)Sm zwEAqiqmDBJtSxlrQQYFN(ynglAMe8Zo~%TUna1j%+Wx!(H_V_pwK%P7X?9OcP-dhl zQ472+al_Km2+0AbpEu^&eiL?k51w&BW%5AA-~GzokKV79N294=rn%8bD=10J*3g*P z&IGZt3yFAQ0<`34Hez17YUz7;Kzjt%P8#-EcbIwJd_yV)t50vKH_Y2%l0X+(z&yUD z`^TBAf=x{<@dMzwJL4bHBey?hkHs|XTN-`*X!ln2NteO)Q#wEJ_mUCr9ntRSQL>2P-!Bo1y}6UYlG*W(<}^q>RcAD9}zh8gDKU zb6nO!&uc`-Nx00RXbKSG(g-;jj?_Kl&0MD;EmYKJsCXs>_K!z(z14S?9KVYl^PEy5 zYYz0n22AJ+k&up%CLu*zPXzSE86o$Or7!*57hf73dsg|L)L|Udm5Etv1ql9#I*D)` znoP(M6Bpqx)t=_Q)-~$d0~WeZnbTHci@fT159SSO=xNf)0TP=GHJjiUp0K+dkw*lZWoVSV}r% zp`Cu^I%ae%J$9gQQ^!zMZ$I1Zh|)#w<52i1x6$*5uR$;Q6hL7li~*Lxdsg6>ok zgSnDaul~iVx&6we&jD92>C5ANT0M{}!yrp8G4Djf>Wx~I|43#O{WwRRtdvPG%8Ng{ z?;FOdisRFaHYPH9m#%8T6X2uTwOxPBLBOUlO9e*tiej#6Gm6_h{_*i{Dr2Xd@(2FB zIsdAHd~y-!!0=fqWz>bkLDQ^26#`FyHRG~?Y1MuZPnko!v@zXoqh${FA9kRrUI@e< zj{x5T0icuTzEr}&!7Msh8}2KfL^7-2DZnU<`y z7fj1xeB>GxyokMn<5-F!QcSZ=1rl9d4mcYa13e^?ecfvDs0!k;1d@kKjg0V59luUf z-F*>{H+u0)SwS}d?z&3er`if60w~Q_u&c)70VTgFS{XPZ;cgUD3$V*H|1P+@s9C4e5|D*S5>AA|g9c4qPn9?a)Qn8I?e#7PZP;r9ko z^wKaA_)N>|-}W=jD`#$1rfrrMZq9)F+0D&Enc)(#H#ZeT+aaqhK*9({HqA2>Sp0g)Ke0*C zUjEEy8&=}fRsqGzH`Y?`slLP5c8_}DkqYFZF6 z96c)J=}#%|dDwfOLdf)OhcA2YF`W=3KG&~qrTMM$Ig>A5^KE>;&Ps(>s9`_UoRy676ssKZ^vu2J#5MU;p`G*8fMk4vWqACt@$|mv z0uoU4tLcuSoj&+F#lg`O`NQTF>EFe&R9bc4HBg90#ad2T{sm>gEO2nDv-XJk&}wyw?zxu4tYy)~U>ePqt$xIg?TI(~4_7u&Vw3b5hf3<6>E+pfLn&sLT36-x5*DcwoQ}!3#&!`?(|Vq= z!rf+6!8;@7mFy9o+HKve(b7p#=5{iCE5Q{gn?p}?;8vx9Ek{k!fJs9J@e(xGsiD52z}pL`dt&c{B&L z(4NjrE=&df6a;JL3>M{?Y(PXpqA$n1|FUbW=x;=+svCTqdUEZ~VvZlqFu9F?s@k7R z&o5x8P;J1#2Lu7b-f>y>>k68|ADcO<SMCV|bv{t;&qrlM6ABvJIoO`@|D}$*+*wrh$XiNI?)AIFuQctFeNs0u~5gEEE@FgZAsLRYscbr+?pPiydTWr**bpnJv~?x9R);R z-R#qwcHkH%2Vue}`8N0K>y=syLgo+-&w+AT%uDmHRTkmbpY#KD@sDEHBS)JP#~32_)!}t);ja&`*AC>!}z*Q?Dc3p}W|C1bGl-XMwd?!IT!N2~P(a z|244B%w<=ifech%h%8MDP4i?6z%qH5!9kXO+hFw%EekmRr1Mh{%@p9-V`xePRDb{YzGSOc?24 zQ+WGh;@dZVCz|F3jqg}_C3sfP6JjM$z-c-vAx&#}U)ZX0z&e^|{OPgA7-J?b0|nUj z^2r1eJ3*5t*Lu?(or8+&i(}O1r4aQ@TNhZ}Ie^L%nY9A}Wz}_8544m+WCp;D;5Z%` zUPN@Qg~Wk{!Hkodh?B#~7)HDc<4iVlO+7>D_qxML{ z^l_#Y1p6mNwrSI?cXOexRyKreE291oBQ_YK+Ns*j+x5q%`E zpvIH81>3gsbV01Us)G1d+ngiE8}l^y74ooU7O&maKEHQWKC`8t_i$s~0^&R84jN%f zv+G$aB>(Kmv0QH-)lF(xhu@(JRG&QBi-(n_(zz^%g_|}HZ%9}Bf7gHTr;Cb-5jO>! zlDBsK?nyGzo)dAyHqO@7DRhzNjgaj>5q*<> zM#gOcn9Cq_TVJ5*JHCT z%7hf(lLS5sv+US+_ zqzba#o&r+UO$WE)GMQ!YHj8g*bGZyhG(JxsPMmqC13FoKWI+#Xq*rls@wCGA89KID z)Hb%BiL}t425xie!e}5QZ^Wh0Ti>l{+Kgc> z?tBYcrYOlCkNa=l8tF;Tq{5aNspfN55+J&1goZ85%}v>>6%NiA)9WC@_6C0&zgEwF zhagu|95XMHh4uUN6h=_7{J+h{(X5*TDOuK%duECW$R$vZ^0NDdp*AfG%B=+OrO~TVFyhcDBFOQDGCqZ zkOdqy7JUT|Y?%pMy2MTM^F%c>aYX*}LDBouDgd`UTq#t0vyrIeWl;%4?_MI<6W@y| zx(?!@fj^(jwl>n^%zLUcFCAO>>dQn9eRTtvm5R43kYDX0VAj36-tCj5<7+AndA!yxx#e>BMqRCCn>i5U2ab)%gR{Q0 z(!@As#rT}O-mQ|(&3iqALvL6dC`SAn{lCFNt-em9D==8ZkuWc7-Fw}CI01;`Jja3z zww67AL*&dPMD+G(FhKr0_B|FHn%_2&OhtUFDb@QC%4gQ!fHTYW^{Wdb=kCk!6HXaa zAg%^(n>U*jMC^)^b92pZ`}Jh70Qf-SNWhmskprK$@#T1P4gT!?Ux6hxe_Y+T$y1N%U1jor^!pH|fFhDsT|MW=b zyTfG@tAwCRa9JA{ge+CrfBP7@wWFL>2@PFAR8DEnC8#}FU(8}V!4Q1sv|C8SUYR;Gzpy{AJ20^3a}otzKqI|{>IpyHQo-QF+MN*G3zDFqGh{d zLeR$JJfMfC$o+VTD%aJlJV^7Qs=q*(9{Wke$BUQ&32OVmOh;QMqzSkS%vSD@sOkx3jC%-BgsKm z;g4rPPy8Hl;(^ZwXQ?sFK71x%e2)K%uRF!*VwWhEYVRm^Eg=TZpfkA^27 zwxY(b1%E5 zEwbaWT%Ly4yp*5~$|)%c#o+l3Qpt_Y5=?Pe$jCkT6vLa$p(`7{G(D@O_Wip=xvuR& zzr>9`6z^SJ{$ia1ZonfqU_=#2<9Gs>q%OYhe6>9E4=lUOf=jHD!H@UtOXW8Dyd}gr zvOz*GjnsaFSGu@awP8F{t&~foaJp|Sak zv4=8WSb{3Cq~nETh(VAV``6+4RmWixKCT_xhg)3~eDI?TbC2atPv_pmxt3zcvq zUQ?R^gU)^EXoKhEE=I{H*jvyi2n&K1%$0~&iX6gab+m}gTE}ZZ$V%l|9FQ>mRxW*3 zAQnUfL~uPA2N?Rv)p+Z=pEp>U(S#aGzO2S%enQk zFu+WUmV)d=@YJ&q_mC8!94x*<`&G-c05w3$zuQ$C>aGR#ya{($@w@77mJH%i&e-Sy zhqlM@MEa+dmJsY*O;rWZqor!r#G+B`ynI~F5pMg**dq6l9N-b-p+_W$B|TX@OAspY zJ-Hy$gqyOlL1l*(v8v`_%2I1ivOln-PXVNkDJ*@c5zx%6PAO|wzkMdpdPO%q)yS8F z6%TxhQ$Hp-PJ~u;Q;Wd@aw*wC2xXG#0d2yzdtm1i6poD-GAAvEfXAg zG!Mu3r`{Q`Yt4fP=|bEo&A7-aS9uH7^}vFmZ$;%s!3COuG6# zF@LcQCr!iHJmvJBBThxjia5jFGGm(YX7oOh3%nErW0@^JMHWuezD)Nj(s00}E=uXa zhce}}Z$j0KRUb@BgkP^=h(gWtCP9Ko|DBo4cN|D)^pgVH;sESIBw_;s+1Pm%jL~?` znsc|LNXuTV^scc62f-_kf}%QzUlJ~;gY*k+tGTG9)kp1abZ%E8KbV zE=mb>?rK!?OrA31NSOU#ow5Z<1^YbXFjO2vNr|rP5MxNnd>j>78*_1)FyR0mIv%!; z!e^w5L#erUH|^utK}Tkek*1qLFUUOGBhDGkl`ohL+(dl$K51B7tt^tuwi;e!KMr~vOaZw%rEwCBhQM!I$u0h6AgTqiE3LoR052lk|@NDss)udf)ITmUNVBGfza$rzwJ z0cz1E;XH+7QqxA5b`-hsNNkW5PG$}w50I5zZ+af7`4PHY#XHm<4DAztl_bbaf+E7B zPLW>y5@qU78sv?QN|EUg;c&VFjGGWoXzO6$kW))@-rz>kR7W(xIV+=Cmb9}c3$Yw( zsj2{xBTC`8nX`!h=LRmu5vs2ES;ubun>_VRC@8IiHA^mK{PYY?5SzUNxUOo)FdiG? zcG|CyN{{wE2b0jMOGO%@ZVugMQaKn1H6rGRiJ?R9ZuJO6!ex8WG0czHe#-q0NtMak zlQb=3k;rd-DXm!%PEcsm;r#;bNuB_Q5#96B(*R3K3Rxq4rvdgDSR=8LqD^f--z8C|8ts^ioF!rJMHU ziD3F#e|MKgkUKLJ;*y@o0EmFa$1SJCd|C(7lfCMUgZl+FkQkxzwQGR2hJzlNdZI}2 zy27aqSg@T(rUkLz{Zf5cLb8R?1ZI18#M^dle;CRlZ;r;p!B^57!XdseSRui|$ht3Q z_f*v;gp0lJ{UVC4an6Hq%tj&aHo?A9hQ7>OF}FXlmeX%(hJ=BFq=U9D?JDkCz7kk1 z2s$SL2<)t`>m9TDoKY!qsxg;##~ha};8|5Q7S1Uh5AZssU!K-(Rvq2UlYsrOWcxIy z^G;Ah_&%IWvl}w#`_gtsqXEllkIw%cnKwa_jbBP846;3Hky`CmR}7ivk1@xzeKsnl zeRs{yE%>wPBSCP@LC+8Tvurk0@|!Hr*UN}OX% z%{D27?N0PF1qu0x(zXWs!P^35QI3ljFLMYs`32qGI0Q8IvCjnY7&^L03#r>M7#5%V zg{P;rSD96lv?j4&Vu5{BEqEW3jvfw)!pM{wLvo9(wllEz^QeoG?bYitYnR<3eilu; zkNooqvM;zmp>7J4g+QZ-!2zL4NnKLq2gY{$dn`^*SjkxW6?*L#&}}-e zMiOF*><=bWV727Z;^FlR{wwiOI?K<(eSjcr|fKEXS**&d&ny|1cBhsFE~Ti8Yia zz>Md}r)}|O;-7F0fle#s;EIb}0P(~|vdW?m+inyi?%$4P}|GG+N_4JZYm%6(p7Qa{birj3w`BtNv9vaXb%X>_{ z5R51@-kl`MxS57LWQgKw7G=lt8e!Dv`B7n9*3ks68`u8GDQ5t*p8{kzA@VC+jrDf@ zu`4qmiOmCp(dC;2hM>JkhAmzPDv-r>hpsmkeq8Ki8W#bWe5{lLoC7$_+g1b*D->iV zNO{Z^t5Sf!VewWV8dNx9OS6`7lR5fDpdSDVUQaLEsRdoy8=2#kn9pcGMOmo)H()xI z7MQC_dJ4JZ4I77Mx@fm{D}YiW$n5w&dWC%M3TI)uG=VsL2d-!}5rsW%1^VIB)T_#+ z6D`Ol9T?Nfn;4*C@$?kmG$^+H`9Y!aYwMyOPE5o&9)iHEteHb~ zg3j76%>x#77;DvM9l0<1Nxz7qkN8Py!LOT7JD`q`r`PhW(-BTMu>rhxr`eote5?H^ zbYlc$Cbz(t0Hd?IahQ$;2jrS}?3aifOk%!ix6YW^lT-sPO70A6RUPILxtRIHm}A5X zvDVohMJs^RJEUx9IGWkjoT+X@yqvUZmwjLjtlFKAeVO0Eac7(cbJ%nhJNi<|NolM|2E^J`^ z@QHpax$qy!Bp%%KDsp;ds5)XgLCfnqiXsx|VZ=z?{%68s;_@@k8ix$qeLle-og0zD zIsk10Ms2suZz{9^Bn__ zL#e8Sy0;za&IxPXe#KZ1C}}by-HC?A0)YD2B1|dJJ`RvCSWAx)>pUZ!=0cZ_H_>vM z3L(O!D6%LuE7KGEoO6tL-b}bNv__BbyxxDa?nrtzVWRj9E67^PwK#g~e?(q=Ds{x6 zY_S&3C87HPbF3ek$Ii+VU!GzL`FS3gNP+A%38{yS4bZ6Mv{zkyj#X+Z82}HcC@1lc z%^T|{s&Y|_lQQ|;B&#lPln$cyHd;_57hpF?HW$CuQ=J>0?$ zqzB+R@9nV?knYVOTB2LY>eG!EQ8>&wVV5Dp`I+Vv>GhXWs;^nIbrku{~K;<(b>(yq-hZ+vM8DRQg}Vbax6RX zi7qu}>!==rQOr^k!JWO@T6Kgp%aq8f`YbI&EjJx8668MPM;lx3g~PVwY-D&b%)*a+ zx^jFKxDO*by+0$;L|wlZso7o%QRKmfg`*^kfB(Lc&X0f2$|jO#=*Nj5=pudNh)GBnUt}?f7!1Uafhp*!mmHJ&&~eI;MV7Z0;(%0O<~M46B9p1!+fr)UU`Yc zg)xf713lpG6Yvb=%`!y}A{DnfjyASO;0?^*)=O0p*JC{B^e31grLki+CcT|DO`B0# zrlJUsM%6@X&T?LjGexPeO^#00(qm@pjqk}c9Q(0d_{{tAnSuc_;VpmhqxPCbqW?M)w9aaI+eYEWgdsZi17*9~GXS<(F01J;{(c3sF zMji~uj9%Aec!gH{l@RE3wZ;N%`8Exrgr?QftqTQ;7XT z*qEDJ(FxK*l!Sh7UE{2W6A+$&cx!wLd0^va!w`Hi_wd@y5CcqLl(Y1b3!>01Wf7kLb?2s z7e*E-%(!>X0HYK~%uo1^)61b}cRni-JUN&gs=ficuVI(Cxz3f`@7)tV{cGePiz(vC z8!x1WUEO?_?#Ue!UTH3sh^49hONj6S38?bnEH@i|gi45)_EVA?>&+tkcZJ4Cr0Qtf z*Z=$o9kYdMF+Fhy*jB`X@cEH2+syT&3R3K7c=^^!=5Rp@M)D_2p+2{y~CcG?$xS3Y^!w=HAtbUQ}qDY{w9yKb$kAnGPYngWg~eJ(AAyP}V$g1ADKSMO}sYm)xo(t$A6sUX% z`>!6zz@fAm5%MasHoDN9To~-pym1~x>JvKrs}B~6?fTT7N85m&UqqQE38+!9tnmt|5H0~7f;hEL&-sCrOOUaLiDXi&kB|a6OK_nWzpbr(*sH-x5`A=k zvSr_63Kbw=)!!A28m>Z*OL-(C*nfj*=mXy&LMX6g#21?9Z(DHp`M;SI&TPj9)AyTX zJmwMXAxDe9o$OT6Qy(wfGEz;?1<$?5Xoi5-uEBGEY!*9+hCkVlGqsQXl=>c@nGrrA z(j#F3J5%W%4vJ$@U%5khHa+UOuOgi>xZfqm=(87gUhJqty@`e=K&tHM>iG60wYnOa z{VHzX6GyETAZeRj1wR|;IFhr&Q7|;EroIltXfUsGRdpQ4@`~yYgXU~+Rax$!v)X?| zQZa~;FiZQ^Nr{_5X#HX}P$<>md<2UZjri+NGITDc=v|mUJKHi+#7E);c`apDgNde2 zrU^bq=sDFF=5<-mo8H*o`H9_;48^{C=1N~gWufsbfb|9sCX@SsDnVljEa=BbuL&f7qYZsl=E8YvA=DtJnsIti&yZBO@B zZC=B61tS=;t!1lQr%hwv=16s5mSK-EG5Aoh(p$PJim<4xsiK+Ist=mE_Xfz*$+bgz zVvG(aHbfngqSAesOaVO=+$YUFfx{19i*9i&9^h7q=Vp*F%>7RzrJP^C+v-OVAyw^u!YPXTu6pO~cDThLuK7jfB9SN}v zC23J)9Hj>i%i*p!Wir>vxD;8|(Xj-D3-py2Ai6bRvHh=HPwOnHJB|uvM_1hDa}2+m z!?5G9-@EvtYGHC4(+U|A4lBHDCjlK&$DprIou=w_V&@k#ss&f1C4? zq6TI?>~1B1Nk$^qtP;iuVXKXm^7z3)FW7}gF&n4IUeqFd+o5@B9t{K*EqR5pp)+`- z_~iK=fuM-`3Cug{g^ObOsIoF`r1Hh$$f6Owv+ur`Rd|`u7Ik%sXOh0POtsU$Fy+3$ zx9=P(q62{%=%U!1-3RBtG@9||NS?2K^-ht*m6ujn2+;7`x4aVXq%n=^o`_EjN!)!i zFh%Xb>^8iGTf^fn3Pdlwf^gVH{q&#s3OhokGhcwqYH`DfomB8CPK=lgUTOBvSpel~ zn%5PQZGqS_;nTjQ!q$CV7Z^u)oo|;iz5WP9r3#6xY2<_rk_{Zp%zaML8eTtyQ_@`2 z`ZsyuMXifH^a`{g#AXDcghE?6*=T;OUGmSjxY5w;`l*ktZqRTq5^cu7F~%$KfD%-s z$lPq84~z^=XB$H!<6Wu%zJO+4GP@Wg>q@6?MM7q@y1O+!qzvcOeTifZDqRIWFyNt2 zKPMvZ9#VE9rUv5dALwNhQ8-rHqG-L$(z>N|-ZnvTE)v z7dNsN#=#IY?F(l_`G%DEG2=5ALWM6w<+totz>_FliCV*8!=8hp@2H&w`04 zPT97I0puD^9lT`Kwg-@j)j4k~@5~8SdZ91?eK6#ZBunzZp(?q?I=+J+fx`ZPOg5PH z45uUBl?)c+$nWqktkm#G*ytM$OJtKNc8GUL5hBD^sadP6B*P$Wz3=;`gUPD_pHAjv zVM&Q(A5~(cGMzD)E8htz4|m0oY}ld+P9Qx`8JavE&_GOh(UyR1c`ELacif><0BB}) zD1T>2JDc)W-K9fNEHvn`0k4E0)=Z8bhD)@LC~L#cf14)ooZKAxgZgh)%n~$1qeM{q zXz=6Clv(engVJtgCbh6&L#R?ilL5Q)q1sk3W~tCROq7iRsnuJ#PBOk=rC-o&p(OL& zn%@sIA~QsqLo?7jb|#Vo*%)qWTNd(vPP^Wra3#*;PV8HrFV`+Y#^Wt9qv!-)@1+Ho zRoCR8`S#T9ip)%}BsC|Wlm0t)r$6Qs*-bnU#&LYcXEOw zJN6z&1|P?={eoPAksB-&>nk7?!-~1;x0_sf_RTzSdKTDi4a-XW;isd?~~v@vP6> zm-N9G$mbnsAcTq>`2)PR=L_;Ot3TkIUQl@&pk`c>PK3i(hsn1G;3X&r zkHI{s^nj*eo~-NVR&rX*YyGSu0}|VvKdUXXKFtRWhwSU=Bk)6aDGcGcQv-S2Yw|5* zx5vl|{Vj%G!wPy6fl6*%frnAY6T(|+)j{sI+4)coQ9z?IcyNcscHx@k9T>@)j%?uA zJDWW*v3rC`sNF|QXOD;CSop}DMfu0M$|RIWZ=wPdk~_@c4n%+pz|~g_YSJRwm2kn+ zx$gL{FM#bps7LiXZbv~vzqI(B{){Tg`K}$RY!ZJn0^N?S>%Sv?Q&SJ%^$ErNEtm*_RpmoiqvL@U5g$e(7NEW;M?^ zl<^v^;rWHNJt4Qp36cw39tvGk4lNX*`VcGw*QEl9u7vQM6w-%nIpE?8hZI|=k?~KbN zt~2s=EynHZ^adsqroCd7z-!=VoMJKu+omhv6jl`xCdBQ4=L_lL`&DT-mfg_T(1H4j4otmT=PFQfAz!AS4Q{3s5@fIhm|b*bqjP*C1uH*v=_h^Tn9Z5Hp>G+ zBmuvgq;y8E!(Ik%n(zp%nYeZ9F`ZTYO;T&>As0)!`xsd5S>z&S|JBeK*6%1DdwN3J zY{$rVxj0M)=+7U@tUWnom6HVDfi*%ey~l^&AbeDJYpf+DeIjy%12n2ibU(K?2%@s4 zbz&!fxkU}uWWr1d-Cpy?2}9RVy4Cg@=BH{QzkRs0;Z}%*(E{ zy4;7ruD7>#J5z8g5B*mxd6pWvv!p$9C{_B09MT$$Sq3GD6A#2h26|Q&^sQp5x5Idj z_VBDg?+hy1A1kxPyUm;#@_LQYR~^X<^aQ^a`76l60>1`MrAbcIN2!*R{|*(jG-ivJ z;@BiEKmi+U9E|YvZ~r|0F{vVpWj4hv7bXhqZOQAeCSfm_5+<;>moRpe!<}e~ZA+qI zaC9EvfQKC4f2*nZSQa=9fZ3R1Zu6AtFp?FP*>OsX{#O2q5rDxRn8O0Md;K;Tc}hUH*Qc+^WisXvdY_`Ov?V1HKzm2X0i2(P3 zM&ap=M+(Xui7gixPp+T$_ALs~4n1rMm^34`o*;gpG>Wal(1Rcy!ijsi2wFMZLjW#Q z{@xw4V}_@MM8M*ms!#kzjL)1gKkISO;sTxtp0Bst8d_qw-i}J9H2KESCti^AC@>!{x+D_hf8-}pa-T6_JY-MMB?U|%yj zn~vJ-VvQ(Qea2(|!od>Rrs=M(+88JaU>sT|_2I%6EDcdL92XUMrSv;wj}%Ny4vyd| z_}YAy>37X6=2XHRtitZev=8=QHY>fr@X?DMa7J+9)!e za1cZtfyw(3VAalMjIWOG7yHnC9mLDonRncq#eaVFu`Uc^PYvelye&+`M4rCR*o~{^ zN55S-Q`tNv`~=)Q9+2IMvy=GyVUKnGUl-uD2$lOCeXrzzmF1as^i?22TANxt{KDn{ zQ0F{%%Zu}%1P2?XBKI9cq2_i_6}j3{!kOpwI1F#sBlOz)c4S{YFUfR_N|Dn^yJfeM zJRm<`*;|}2!#PUIdcGm8pVMyZ^swO4iLJ1s;R9u_#m}+Y$IjXG01(3Sy875<5GB*> zhW#TTUOP?2peY1^Zk?DdiwdNRX$tBrLKU92@<_8WNuL!Va>-YuI8NlrwXv5aSN+{( z^NAd}ueSJLpmd<@>C_Z{3^#RTF^%gVbX*3a`tAbIzF7Ndglu$*4{c)FliGaxk#j3f z0t=48t#g91xwv~nNH+XBHi6!U$AEsP3bLyqY3ay%I3TxcD6u7l;H4alc0we6w&NH8 zTag~bwENUG{?-LPCfid2DWSdvXm#OV78KHjk8f%mX zApPWIn}fRgklT{}MeMGkV)cN>YzJE3?N8+YuN+?=C{Ma8E``X*yFLq6I#ZSb8rcb3 z&KqbWd6K5?uUv3ncJ?2i`uMqSts{``xF9-a-2#_EjL!hJ|F(jAWDvgfTw45rXgDO` z&);$89MZ1W=j}lJQO;nzKY(=VBRfsic}NMmBWCUh|;X! zM{2-8`5*ABK5YV`ac0Rqvhn<{XG8-P88G!u#M^pOF9x-aF-fDkpoJpH4?raJK>V`- zWj5;nlJ9;NFu=kA7Z(MeD1Iq{lsAr~xztHtCdKfC>6f%D4c zh-czM75ZqZ-aqr^p&9PyhXsSda>g2m&^<&3$ZR!t_?`SvQ6}!ZfFRXC;!O4x7)#o_ z{c?sXoY`05Z|YOe45+L6O`WRoe*NAyB(U5*SWJ%mV;HK<8M`Kkl-@*iJ#$GLAA*TU z56qn8BmeUpF~7@>^-!aBtY09Rt3{JpJ(JVVq#k#uS-)zqt#OWf+oYe(kk!}4aOlN2 z**n!51H=>(c4`>(W?`&S+KOPw>vHlX_PA?d5iH!yUi-$nX1R3Q|w5fLgv(8WVjq zuDIqp#)Rx;aXd@&_Uvm8PyYAZC6!2k*n&*k0Q#$bh070say2(_BW^!J*eR(j`m*(! z7A3QS?{z-s2wHzu8zVJDDO&z;t%uAhhX6y3U;z*?`SVT@Nbyp4gYZg~-YKje&WB=h zT@V#oa89gz>ys8ZIJv@-IpTW+g-%Ku?JTJjj_6)Kpe;1jt;gUtVp7E}bQFpUFz&cu zHQnN^*SEI8b-+2p*2i|`}djXU$@K0>8EuVBE+J} zlk-$jl)j&Zfa^D7C3HGJzxjn`>(oUQJ!F&Xsns*GODZnuMqWMS;Ls;9$$34O0Qo|h z?f#K#RVy1zWk(A+Nm#5CQv&fT+G8qZm@3VWye$=do10f47iF(t38Z(jHgmeC_J z8XEOK##ZUnTSuw4RCgKSZF}WoHI5~mHht-565>+Gu=s4SAHN9qdX^9S+>J3JcOU72 zrr=l+&+gG^89Yf2+;oXIQ^+IWcWCcI2>6a5hI>j&r*2=(r~KOA2!co92LQJxH%+!3 zMOcp>pugria4k4AGWHz-soXllJ>?wK{d3L^C=MC1RnN5yP+SLp&}rM!mCH;*ZR0t7 zasRbIgwRZ7Y*s1yNE#L%{+)QH*DrsmES~bO@|JIVn|KW4i}_Erqznl0;xjXj#A{@% zouDC|di%6IBE+K>SBDyK>BZZP6)t)J3EHy_j-HXu8n0d>u@xz3(u!iW;E+K+e=ce5 zbAR%_|3pXHB^s{sGM)=J;AH;7xXB?MYl+3cd_c&F4V1voXWuR;XDs-itoeBQN_r=F z(7xMd!CyZUn)Ufw$3E1ts+eTqD5sMTIi5u`bDQMo(|FF=CJ`OpA(wCz zM2+Z)?hrI*o43;>Bmy9A7Ao?clgouGOK(9S&`8IHgY=d{HQMKQs=K=cwxru)6OA|ZaFQrw|>=N5p}7`1<$tBppXSPSXrxj znuzSjF&(j(u{4QmnSuCcSh@?t;&~NIH4gS3JsyoYhEHPbn(}=vwKrb0&#U&kBp&^K ztY|b(n{;MbF2UY2yfGM_|p`q5R9?t z26-tOY%pYXyA^&~M0qp>m`D52&}m`aH2GXT^B zBv45%HKM^p^T<)a@+4$@`r1^~HC%_BHTG<~Rwn5Cm0C_WqUlL-n2sb@}WaF?>c9d3^^VNxN^5H6SS9|9$O`z{Q`_UCSfuc7- z+fi-_Dod$e+`-q>(n~@#`SGKba$zLE>D(9|g;FW8Oq)ee8kIi)bYw-lqJ($ryE3Q% zM;Aylw2DS&d)MD4dVtQjk0m@40ZHP)piYgz=c~roZbloYT1Kf9PLJJQ`SM;j?!G2 zBE>IF6hFU>BF{4TRkO0XfF22X7?+S%W>`~gK#1QOUzV40UO)GwgQ<4^evljW8G<;F zO8{y;O#CVa;ZlfY=)2IOtH~3->XNV%vKv^-PvRX$<>M-rBxvJvbi&{Bt!1al4VZ7b ztRL%ApH)?w&q3UUPsHGzg@UbNl+GicAN{cH zZ9aGb$&(<+qWaEo0T*mOu2r%};6+GS*5a_yWhnMi80Vt$WYn&0xhIIa4y9 z)yKxW{VBjkGX(t6@+cL#nS`kKpY>l7nfy_n4E!-jw|5B_PuC+{2ul?t+*y2MA^gye zIYH3NV;S~M`(!~JeS`?@Y9Ji|gj@rb*obyNfJTYF?Z(&olwJ%F7ewqL_01WA!ZVz^ z0A(ndthJUoq0HJOgDEqJBwxt!4w1$Yk@aAVi6iyBwqCkWyXrRS*kkaHQWjA_TnuKS;fG> znLKtk+pGd`P&i#O)mo#*Nwg`;>%m8yL5u@$lQS?VoC6JiTq!s=W!B@ z;?SO`X$0x*43!_6U#Fot%7N;|&ia#2>57BoX5PImaE%i9ZzfT))QgY@u3b^it^nh|Z!_<#2ie0ezvGuUPS-+=zlY~TyA z9`8x>0Sqv;6YsA1cp*lLVe)QK^|Z!IljQ-p)x}t9L=(A!qxI#$ijvCO5ixR;lOl8- zg2;|h7if8F4wlG9?;Emy)3ezR_p0Qyk>jW+e`x{{m{^t;OA;Gy{xl7Taw>H8&^7!S z(5&NI;qK^y1$va`cP8I3@#o&&B`(&}QUMU#X6C2`$Lke(0uDpy0h3F8czK84mRv&I ztwyh05o69h`WzEKI;l{2^4==(W9|s|OsU~CBm5iUJf^!4&B6NCfP7B!YtiA%h~s;b zWKq#E{=l+#NfG-&9acf?mKQ^>olpHryR(F}qkFGY6hgBGx0e2hKMCueiul$Y(?Ir- zz$d3hgsNitH=*a0=;}?NUr}h{$tdqU3>a2JXo7UwM7a;$^h7VMe^6(xJZqnqyQqiq zS$IF-gS_Lvty&m@4;-?kXscNq?(5r?^decpp_Uwd*lYCg18(?)lDNRD&dOKe9!{9I za)Awyhl4a`b6AzhvB7uoQ4RtkYf0e{^^3!}&ZRNew#Y>v7Q(7g(JR@sb z_*nB=8_$TMDKQB%1YIcMV>U@HtA?g{diQ$Wfi4Z^<*K--N-^QgX&6cJh!xZK2A+XFJ_^R zTb@+Gbo)Utm6FsuaLQ|%<^)ol^}y_XCv-$0N5HchK;Z|GoV(e%BjV#o;Km>99K5=P z%+Pz7zR{ZN=WSJHK`pxfa^^=oYo9?gEVUN%;bHt;=>?DmKVlfS4Yh(fi z|3cksanGt9=RHXyb~KGQp~7_r-_8Ou*a8&s=`-ahd*D@3*EW_t@f^KV5szEh8G$9N zDJmJu;5?n=+nY07*mVsE_rpa`f+Fb#8Jvg0KxxG>b7}u<&-2aeo91yBLZ_-|DgbM~ z52%+H(p0ShHC%Jr`g9uuFgAJqXKqUG4QC8$FB1t7( z%U}WQ1#zj-$4ZU^)%Vf@~NPS_fCaU+C?R;{^WV}<(7%)5s_mWcq`-*x~St?0aHR}JUH3n&l{I)5S zNfiVds!(K8q$K7N8lY=^fT=L(acsbv7Oetal|T%6urGMSei?{N2Pu$t(=9P(@V)AG z>*&jrvkBJ|giqIlC}(PdZ8KOCRs1N&g)O(PiRkdn!VB&U2%5qM#2)oUAsTHz_M?Um zoCX939LM+#V_RyI_}fqS7F5=syRE9IffH!ow|_nPKd|CLR3FLhG}oM?atHx>ul%gx zC9YowBq6@ImDiK6nLuc~^S59|*-1OP(5s2kVk&aEd2Jp?WD^8dgWec!aly!)UdKG; zzRq3HtBhD}z2Q?hxa>aOATbV8+Ig?i-b;mxVSNMXG}w{OJ~49G+G*-=zWhY#hH-UE zyfx9CCc=-?=?77)Ji90$N|>zAr0I=-1*W}!PG5N4a)h6rpW^l{FyA4HzuWH{JOxeN zx*7%!%7(=7WH^3UCXYuPhr9BsEZ;gz-QvLzblJK<^>zKGLEjqP8`A2vjm29s7~k6l z$MnRC@VUC~$`DX;mFl18Lb2cM>j3AhKwA!o_p3e8qlYU~d9jd^59VI(5WQit$70oa z)^^Qp=%kx?5kGtmv85VV z)S?Ao(S?DRNxhAgz1q?Pmizb-)&ArOKG*!|{W5awYTY8>C?LRwp7$WFbmh~9{E8Yu zsNh$w1OpCqv7XyIZJTtKFg9r~?m#L#mY`kY`~BeUF1&jA_`7FDh(vBLQD=v$`LW?5 z7mv?RU<-Y2x;_cVm7@06ksD6Rn{H$ybSOd zZC9nuhaM3rrFFkmEMw|W<_PItBo#u+*-?BGd6=cxF?){(gwH^>MAQH*_ie!$QF_Q% z(|00-Pkx({saB7$*KDj z%b9t{1Q{?6P_1aXkm69Lc?V5|edX%h@uV^+#~vb+($?|WO^aKciuTLrBqlAAlyMTD z6%m@zN2XIEJv3Rdom&HXt?9(r4f(*4;LltbzyaxuE7>%PxNwWi4HUHeQtW{5RXyzP zK1ud~{8?5>z)R0ta2YLyZf7{TZLG8tkhpUlF=gf`OV85izY90h#S zqwh9}t-*sxI{vHupl%gY5z84u@Ziv1tm2og4O7%S)e!%j|$fyq6a38tT}=VS+s+Ymh!li&tQ1>j9x#!q(7 zzfu1@*30_8%UXd6##ao}5)}rL=J=bc7(kXB)zSh&>Hl;iUR)5amBJ(@zL69^oONPX z{!&ddT>XCv3Z?V&H_yR(-Hf_Fo@xXOpEpGTzs_DV?r1YcIHQ{q;!bHc1%ybMm8-b+ z6Jb?$AZ^^v*4pVbNW4NNuujRP-~BL0bLjv&=q0L8y*wFoltBqY+^x8Bq-#71y?&z| z%M>zx;+>ep>zro#8lYX^{DmSL5+A<%lPEn zJ*&iX=i0PjT*(e;XKav6O#o0>XYSlk)tMONRCNMHlfzT@$`Nl1+rUg2FhPBS-BQq| z(qy_>)N+{K_Gpga*qHz8DYXJU_wr~C7}}9_!BX!sM+S;K;wO&|su;FFWh2|qJ$3Z ztL^ZJD;fM<-^}9Qn=2nH|EZgiy}d@+=agM8!v3vA)eFO>>s9tVbn$>g;Uah6H2%lV zp-i?nt%NmcfMm^4_&f6wHaaaiAQ~233wa9}DFb#&elAytU*lvoPQ^O^%t$P>!mMqm zvY7V&&4S5~Gw9})({{bwTq&lDC2_}7@anY$+{BOf5~J-B4`p{|+~jw>>pu}ua>Pw1GFi_n{tLp4=ffvs=%){-JbY`|ELS4@h*YERPKczJ8`MLm^9fl!}|gt5^Ef`63&+>N;Rn#k}EB{{ci zWpL9W3efqKm(8Sb_0$+`?5YFnTgTUV-@7&+HkL;S8pSDBbqv2OYk#=aDgdPj<#T7b zp16(orG_G>KE25*&YXL`CL`uvddAWoS31P`a zQ3;%Uj)X?QxLD$`-ego-Jolq$)4knpTlQXp*X$)2B{S^*cy|QkYIDWow?CmA;>j^G z{Ik1$JhEL%`^rcGBtgCh#0x7!?_u9knEhYq58FbbbZ8O@Ja(LO_D#6F)wmM7lWve{rAM zt8aAL#FG%Q>ZEL}+d9>Pp6^E2bBA2dwY5)1Egh+=OwnW3wiAl!?nc6#P76#hL2oFY zBK^Ry2*fU23&4G35)UazFuAT+N8vkapg z6c!HPvkrzQu)`9GR!9qOrnl*aPQr~?B;Ab{*EEzjcOxb|zL03VZI{MV@|Y*@btLU} z48=jx%+Ixhy4x%dv~gLz^*=TMJQVOwkZ^m+AzKgYDSbP}x7o+JWJk9qxMqxlcop}OU*obI0eqhwAJ>9>AubV zihX!A*n+>(1lZVe1`bx!Hnb&V&5k4J-om3ZaLq7LatkD9mX(-N0>CY{QG9>TR4;w>7RuLfHmDO^y> z|1n52dM1L~BKM^T51P+Z(jAvcY9exbv@eP#U=&hwV`s(v4CuL0>iIO+RWHB%e7t11 zNhf|yY6C|qVXc93c8tc*BPGa69y{yr$Wxk5ufel55uoLl`jWcY37U~ZQeUw#)jy1F ze1l?j?l817q+kk4I!(lBN3O6nj|gO>E()qhA^WlVP%NxlU~DDnPWcvkFzN#%7z(}; zrbfnb)xRxqzEAe^6&5gZ_<)cGwM$X_rh5*_vStoWOc~TKiys3~JvV4rF{SjJCcjTv8Ss7uj+7Emn^-%0PSvQ2G=Uv64>7N3ODioV5ML$q{(C!TL8i31mEp(E0dQD zW2jq>7v`iL`C$+jQNg}lwsSyjg-Wgg>M!=(N)rBVxl}d&vCRix!-onF$0xZt!owiE z6Zgyz=NP((NmeQgM4k)T`Xgw&5mB@ZAX;vV9;~^?_?3${)ag8xA)G_fe=B|1({^hJ z!P->HtR>(Nm+-yeJgx4mLITBUSI2@i)!25~P0Ehfg6FG079+%h(!t^G-V60uC$NmT8_lsWlU;{`L^hxNS+QiT^sv*(GR=-Y z9zcE&g)quAbo&FBwVhKmzZA^1WHxp9T2dd+H&7PdSplRn4NKhK%+Teqhh4BbEy= zi6XsdO`uUbycu?uw7|`-h=QK39QeN{&ByVN0Ce%An=1191tv|w9Qky8+M{sAKVzMD zCt!!-FH>k%0xY()@@$^0t;lkJ9M%-zhP^62+3#Hd2zaeD&A*Tvi>UssJ`>|3^>oHi zJK4DJ>D+aH5w{M(M(wbQe4nEw{P*V;Ye09hkZOz0Pp47qB-a{T8KE8@v%mG@+)O2r zT|fpuFO^Ow^iFqEkDHT|n?Y*q^QCh`BFqF|Uf|Kk!Wp|I*NwiL<70$sFbt}#oh10L z^vlb0g0Crmpcg$08frtnD+jEqOOk3}zJE=6#>O3DpSLMLNhM@7#V=er8;9vqek}1o zCUM*KSiu?_)c>DAk~0@&v`!NWf+pQrVOzQ?m>k1);R6ZpZV-GX8fYUI1R;puEXu_ z3rx4@AGmq|)#(vPO{p6RKNqb!n3%5sh0gV!yElSOjdjJ+(;Evzg20rQNs*hfmw*)0 z%bV6lcX1f0N1k;Z_qzCj*als9O}jq5stlFMJk)Mv9#dkh3hJ%!lJJjaoa|!??Kw6% zH@SAkFWjoruYLcCc}g%&A98jw4Dp>!#EfmOV2kC}(%x{A51L7gfYD(U^a;}b2;>7; zkxI+WU~Cb z{Nk*!2FO`2Om&s%lPMH}4Ru^0P5!p3Y0k!r{Hmj5+LI`g6xo*|Jddp?28rYMoIFdGfAeiOO*t5n*RCCmGtp`iVy$3+ zL`EOsXuNFJDa&O~BEA|w^C%T2kL)uw^A33dS5OsI5___doc)WY=04mThPj+kdrZK}bxT**lpqFUf7=l{ zGwBEGl-?0eSN}*QI6If0=S3IOhK3%}EwVO0;?TnGn%rwff2n5H^yMjo- z9nDx?SeP)<0lXbwjaqL-iO)hw#k@V80e)krLs0{m&FuWddsu~y4AN`$z6KOMQy@OZ zJKhn$p;|k>dZY8~iCKJK4aa#Q#|jF3nZ_{*#4Zi<45orxxz!i>jiuwxc~utR@N3@B zULCgLpu7_LF=)y4DIuzjg!&dj#TVv)>z`MC>@ZG)NSO-GU>>6v2`7FR&7^Qnq;_;6 z%(tToJ(Kx&RDb|;ajJ!Op_X?2Fy>B6#GLv$Lu_!Us|5?^@pF&zUHb4 zkR2J-M9n3i@j^ZGQs+nodkS$tBeKH5Lr(koKdkAUVVH10BbuNFnqCgLqz!V!H33gW z(YNCAnsc7|ZX;0KTWUCi%(W?z(8^{17Q|Q z*(8-_NfBv#7&o}XOlCnJm3K|gn*O}A(vx9^hIE4tF;QV=1Q3Ka60xqdwzzZQ@^To( zrvnzE4jaPW?6YG1mRFlCR^p^%?tGWVB;ruV#_?DgL_XT<@cM?{7RHOHp26$O^Ia1} zjD}Yk0lFm(?vcG<@|64}M1$T?m)wrsysyu_DJy)I(Of@*Bi>EirARGVi6Juc)QLgJ zYsC)2SnG8O9&y!ZUN88{?+d;GZkkDs%?wuw937eMSLg;n(WUK)GH1Yy>(QPQzRTq} zCJi!sgL%=u?w)3bgibQ?72*TVCmKPeLg948+~9zbbIK{86hLR~bUvV7quVT0vzp(I z1|$(#wIKY^GR=|Q27D?hPY2|Hb2F`o9L!2j#xEj^nslbyProc)wVim)0!&4B^XlDS z$kG2f5}Bn0d~?}SkELBW^W!CTrIudz`n_ z{ne@om$4WBbz|$mt5Bavgd^K}5c}r%Ov40L{&G*?2ZeIdPI;Sf##KZYqv?3{04eQ~ zJrS@gZw@K3XG&#p2PRtY$eaQb6IT<-(tBmK(il-D6q^8Vh3gZ+;90Ww@F`!v0F8xZaOp_$AV=V#=F-SfM7u-JX3=IzP^1R6|E5xDNk|F-Xkd zae3j`VHC|InWa8A<~3n()&@3Z`|t`B9|SiT<4yb#8(@IFz6Zn( zQ?OjxSk!D5V8HZ@jb}_qBvBIvQ+0MHoLMccQB-#ufv}K`{wfNnxb%kOGekYK+Q!I# z<57c~`DC`7`4w+63bP6kFrsY*P1ey$X^a!3MNMsOd-u43bq-x?A`Rx<1~ zS86CLQ_fY7a}>LDyeeuo)?DNKixFuH;d22>lO7eQS*Vrx7}(hFvflon{438$QSL^zsGn6NX*vOj7;redC&i|NbBI_KXAkqgFK;*M zSJMKsONy?%uNlvzWJh>gmllEd zg5=1_83-)0&6NEW_oq-~C~q)v+}LeI#N=Cd@aorzLow6?g9~gl;CMLd*H#uR+qNR| zrb^;%R^TW5Dh~a0D{pHWCf{Yz!Q0@k#a1rjBBXR?b?%t2+Y58UT6AYYR#qItK}*cO zlJp0_SpfF|MFgRM{2&%+-W|3ai-zx>UOPeXZ^*>y3p2e8`dAgckM3cGVs%DaC!=ZG z%frP5yqdHP#rdFT^*wcv9qSi>8!F!2)F$?ngyq{USx9*`6fC*LJ>flRx zM4QTkr7cEyPpj@k>M?v|tE1qE{H}HS9~gX_{UoKc$MgLS z@0m^~@vS4k$)m1#i`Dl*up!!0-RLx^h5@b^wy1^hTuL(|vtLUC`CWy?jj(I#{whTC zgbHwGH7-}&5IdaQUcBiKrBL~3d51dR8#-<-KoCPn9os$@a$bTOJ5R=6sS5pip{GW; zN;=GPYkiJ&r~5%IAjL!b$NA_fiF;8O$*eD6+jqkr(&IQ1hVpvPo4w{7+I8dcZ6C8= z&Y0R1vULq7?jRu8i*452H!OSt3GGR>TDnnz&itGFLSkW-U<&F$js@?cW>k54nO_9v zbMrL_!BY&~rsG03%$I&!rnXxuzJr`V|R@rNyCd&o9;G0c|Yy>P$im>zz?2l zrLE~1Ql{-J>|ran4ssA9@UzBS|2q+nxuQw6FjVHc?GYI8CC(byQFB6OJhBN`0^mKL zWdTW5ji|}ar_v*QXCvb@m1`)8B@Ue&Py3qo%)h{QK+==z$Q>C<>(^`Ek zJmv;mLtQay#Y9^j2QUj-kls zH9@9HVXvfA#J%m7S#FvmRee99r?T4sd69M-kQA0K%J{h_5p}MX+LC>6;IZzL8*j)^Ty4rhjssmSco+b)?dB z&T3_tyltS4Vh2A(2+JVYvtmE>=hsg-o&TjP*SecUu4!}8 z5(4=pvB`h{cx&K@J^wh+J}99BA?xf9tq9G-xcU_+l*qX$j!vI>)B?g4p7ZaLVvBDH03tQj}N za`l$^%Dh7#%vQ}6#0_ui7@y+bm9MpZb>kypfp>&bGR~Ohc8Qs$6%>srhC~{K{dzlN zNyc%pH?aao!?@CYp8B}zHhKkfz=GbO zjiaPq+`{y5`XN`ok2ylv-xZ8CA}VK5+DrpkJtMnLg8)qj#ZSMaTv1qQy^|hrhj{&AmXs@ppoj0{ z&AI)M+DYhxuOeTpQQ}QF@rkSfmeFj(jlFbQo3a$DuHNW(b6x3e3>=kQ-!hl{e-Aw+*)1K30~c!9@hWkXJ3HHD#CF?O8%;DrAq&T zpymX)%YjiFcl0aJ!h3FIh=?yb+a|Bl`4_~u{gqJBZ9gjQuuK{TDt_4bPyb%5|5=qh zS#NB1yJuAmN7i+t-e!~Pw$GFb!dma(e0>z=w9M{w$q25Bu$;MKQ&jruYx*~437+uw zg|{#4DV#ZWsFRMb}pO(ZF-Q`kpJH*MjF=4&@CQ=m;7asfA86|C{D5Pz@`BcJ84HH~V7+Ya0 zhmVwqFZJB;4Ddg~B}NBC1fqw4eQ;FD&5RTC%`It)_!U3J*I}nfh6vf)CC4( zT#ES3O_2AWU$?xHi$rJ0Lr|l;I_iP2O)hr16<>rh*g15|?uSk*1DvPM8nOUHx~yT# zQPldzotTCM{9Js5O*%=t7s7-NzcU)0JfUF+uOlqGU#?R);kBs6b>_AU^o9xbKYp_MAyv1!=G#G6}`rr0Cl@C1v z=I}9;n!ZQbXP7>!0-Xxc0bcaZ9kDL;i0S|1Zsp496ma`h@j9BcHc=!F^26Vv3kL~(-b=N3aP8s-M3&zehAU9 zu^EX=fw7#P58R@Rkm{Z^03H!2OJz({#%G-*@X-sfupZDSQ&iHh1<%cR4ij#&1n-y{ zNgZ{IO)Sq4+Mg1Eo|j$Y8$*Sur?IeB5kkDkEllmWoT4xFd1}rK3Z%jbkQv=o)U?E` zgf6kgRe2U@Hwz(Saz8+_q4(=Q%TPSmPk8%akFjchUaj>&m&y!_A)6yIxk(d%7z6Bz zB0ei-rcZz`{p}Sl5DF=-KlNU@F{Uk@{LQ-_Hr9S5-o*~jvyA4$t_OC|I~{=%qK z9fQ=5Hn;vb$?`6t-v`>it%IV~toraI+DHM^d+oFE@T#I;z*>B`c1%dt)X9lt#%1LWe>V61gU>_o%67JX9v% z2u~UFe+Ia(x;ZP*tS}kl)TMkSO7|usQZmK#&ibN2p#$Qe`(GA{c0_}s4fw?`H-6=O zR{Y$h`F|>zV`;6@NH54H@l-%m#QxI<79(Mn=UCaVBKX5_S!cj4VkugJMneFXdSYYC zD&Ys$ifa4wV?yTv$1ws#VK)EDwgy(Bat_9`jrxxT2i_8<7!w@|+VZYtnwhOq=t`LY zd9>UFEx6X@|HXG;!=xe-%sbCM)brS~j|f#J{xIK88UX1#rIp2vLvJ3uhJfC0K0`|n z*YR&VYf`-dp8hVZQjF0k$y^9|^x>$f;sE~{Jl;m?U9T)Q9A;mnT^B0zH7hou z#OTszaFSk~i_mV<-g$21A!63yo11t<`;lsTrljtD29pO6deZm|+#A*5pX%T324{QQ zA5=feZi36PpBn2|t`pSQ_v0wC8!AQ#O)FSSDmU_$_YfZMVJR-5)f<1)OirWAXsi1< z4hpMH-Y!t=bXyf`DqCADoxf8%P21fjOa*pUDTza;chqPa*r2Z!|cYKoGYmNH}g!8er8b!VtJxQqIfW!$rC3 zKykI1AT*R#F%7`KnoGbO;nvht_eWiYa4*$*baezb4%f`tOfJlsIS2$#z*B*B+4qH< zv`4ipkU=RAq({%hG}}30gwmX9f+cPG0P~5}p`t&%COX~VS4(@7I$6IZirt3eL?wz9 z9p?y>at@nrfv@WO@(BCHyuDbl^r3;oR6%vae*QL= zb2NW>OD#q8wH3)w_26M3K9OXX8}Gf@5_ZBXxBRaW6?Qm;DkU}80gs~PywMgNfkg$C znZ{GC!UC0xFZq6w=HlXvL)ZH1{h+#iE=!#w3I8x}DuOX3piv@8n7=*gLVK#&vEk}t`<6&+B;g6eD3g+j0;bz^{PxP6o& zYP`JoeNIzT;D$>M;*xN^oY$-9MukT*WW;Pdpk5`5g@-cpx$PMJThz+ zr1au>LTA)ZVMlUWN(8)k93fi>b_!|Jx~gnr7{JVOdrDXEg$kIFWbFfSkodXa6J-~_ zi_5oSWbt5v4w0sQ7J5)$F@+*V2n@Mm9jgGIPWHi&-x2di_!o+mT@UxFl@pw)3L7U@ zcP?5gfSa0T`hiy=K6Nd)_A!3S00xE6Q-p8CY(6mRD&~|M=&HzLTAyU4`Q|Jud`N2D zkBYqJ_V~71(fxQBlKGLH@E75v-`zmT!(YySHX-G8)3IGi{?f6I^r#^UT*M&8oIzMj zx`+A-D0>ldB7rneXR`A#yYL=JPtpob^sJ{JL$-Ee8ZwCOmU!o8XE9PP`-D>2e#Maj z%O#fer`E^J3Jrd0RmJG$UN_UB8bF^4+Wd(swUo!;C}A9+t-9_0)IrL-ja=h7K_SJ|VlqX1d&OEr!heOpC9;p(F-Y|E zC+gcqN!S5LVLqM!;rl31@&&P!KYF5r=Ly>P=WqhlN}fI_|+3v*Pcimif`Q+fg$oDtP?uD zOs~9HbfzEXYwtFqipL}-e&4~tMG18(+FcY^1kXH+G)bFQIQc{SKMx@c;mbV8oUMdR zk2hw4L9blaw1)$0Ifi95-T1nQ>PPlY3;hk|geLLk(|V5Uv*-O0I<{m>v2;sVZ9dLF zWog0%bDXQ6Ik{y-mjfzY7+ZjP4%#B^O58%DeC8s9Iwmx67@g<7#ATA8gnbF$2sabd?K$XRq87G)RmmJm+`)g-U;elrAVQA4K z4>F~*G7N|friLsylc0MaVw`GF+%Ts{u?71jVf0h*O^DD>dg_&gCL=`mRXW%hRgT)E z(bE~2JIlb}-997F#4$pSND)!B zbaXSCHd;=Xnv3!)%LfF$X==p46}EwFpHNy8q?dXlSTF2D_18>}N5SkP4Z?o_gQ_E$ zYH4uKU``(hDt4nY=-d%L%VQ=(rRhOKG*SCwGde8t5eE9nenTk$j|AekxFW!xwUPQU+8(tV$_k-SuC`U^=GMI>n>^Ju-#z zr>z-0AM9)tOEt3+q+7`5k~yRjl_kDOtBCRo8%Ck6#)7mNR`v8|@BV7?F|0B3xCN#J zRt^5bn*Q!#0^&KpVEUFJJX*#t)M$#AW3V02s^5Vo(o?4o0}BhHt_6=+TSD#(Iq2)P z4S_T{+#Y+w@ZTL}Dq_(&a|Bh7LR43gTLup9qrSp42f>yGOS^#{qkZpvD&jQvFKTID zLtE%^g6m|MSFexwQe0){gUL^M;%bp!keRzAcFfVzqG~Tsr26~K1rT#qLjt*g1lieb zr7+AlGlNy(NM|N%x%mVlXr^9i01tj`lMA>u7@h;CwhJOSuut@V@k}VLoOBrea^VG$ zYLf$5Nx}m1IPls8nRNhaz22&4()Xuz6ylgpsJAgC>l%9*E7CG^<31y+)hU=IerV=M z78;fl(fDpxdLQPfb!&GzAzC3PjW|LF(b{Z&z`C^sOr%p|}qfZ@E< zneL#1^A}%+Sz-jn#~dCX(%bCwJT3ZR?SJ}d8J?O6enK4BT9X^%PmD} zZrb>~@s4j%L~o~cC9D{0@vW*sYi6c7+mi`oDdT@`hLZ23sMcB6{s17jNS0dXB3)Jj zcUW7Ic#50N1AaOP)dlUDFOqOE=x7O96jRp^sp%l$xlgReMJnk+RR;3#K}<}fqsHXn z;6WOX;hKKC(b&t@PV_I!`ZHsF8=#mDtffTqtc#HzTX?E&3uV}NZUCE5y!vHb#*&`{ zRlZ@@rKca36&{I~!DYsH6lu@ygGCNfUJu{EXk&16V7`8mxc!Q%d0x1s64DBCB$(X< z$m6J%!G0)(FaL?NlY;i{ok9G5Z5w9I!Y+J$E3)qI(_Bvl{<}q?DZ_18!Ws%BL%es^oY3{yt$1~#f5!UZ zrNV3dG$Zj(vqp+b;}T3_u~t+5uBOOocpFZ*`xturLzuk(2{G%R$A=-4V!nIB zUkr?Rr!>#oo&fweWje%gy7bI>G@C8_-)>VRSzZ#GQ@fxXn-p%fDtcM^EVEozG*zuk zHzAhXx8ICZuwfj>(0D)--SbaQCDi|2q`r3I>|bD zdb9C|eJi6#aE91%Q>{x4CKNXG=;0h}RU^G&ID!8o^TX466=sDJeqHm+GBONjGx3ms zxiFqn7xC5c8LP8vs|~!~%&n`%ob#(eb_hNG&u=AUaulKcn-aAT9R27szxW{tBauM@ z4l(P7Z~VUdzii`5Lyd7=H7)7NTYej5qn1Xn6tS@&d;fh3F`A^em`#hp!*Owsiglts z5Xj=J(SwT=EKA(yw#RDm@y-%T@y_ye`H6XG;RwphK|jU(b8lzn*ih}ekwxoKkUa2Y z#|#iPCv~Tizo>Pl>NA?Y7-ToRbM(#l1rmc+^$UZGxY_*@_Z-oOPw1S>C-c07f&hos z@@Z!fae`1275sX8Gp*py zJLdyPR8MtpY@k*~%u4S2^7~}TX*WssLWOvE=W zEZys%7h2Oyk6xkcRq5nC{%}f- zFc0IGjp4ebdv3ZLzjT;g9gqKTt#DA~c>%|z^4%t7|A$sjgieK_Bi88|rrFV?@}B=h zhazZ#;}Tkbye<05+aJV^hrwaI!@6n=L0@1k&Iy7j3RY`yt`N-VkV;5_;hcTWkkJBB z(ne$SjfYWzYA}VDJm*9HF%txCSA9Z>c9SU135h_Xbdr8T#z?BxVNo@H{R~R_r@NYA3W% zA|!Wf--K;WAbO~muz6{?v68|?q#k3}H^t4gYI9vLN*mHha>;`zG=$vq4s8XtCQswK z5z{;AzDU2Y_><}#FoBL31z8mJLw;haT^Rc!&Nb{9Qx#JxyCES#HRHiDE}-kUkDwFI zkn8+`Mh-D5*M~hq)yP&4L6G^4(l%ui8&?cuQQPi8v5Z+*w7w=4Vr2eT z$nd6u`b=_=3^xp>(Ic?Pdj(FF_1?Q1{gpUXF*Gq|eT4>qgGzknI0iUHPyWQOp1}Ov z(&$3AC5(p(84bW`vu7?ppLJ-Sd(U3-Q-cJI6L-P|;6+6hHHH)x8e!MPCk^6O1B?be9_uJ?dXY$h=k z&%r38PuV0Et)t5uc|0~_UUJb+L&5KMipln^%X%9EP}H)nyY02Dd|6CvJ!1n4DQA4L zGFA1(I1tI9I?icbxg@Z^;hE|kw55z7cWm0_Vj-oe$nD-wEaD``q-}CEWLu&J-ZZZL z8DzSyc=@vMK~Gvhs?)hiU^|5{ci5@zVvQa!lSkSK1dT*-PCMeYmHeisbN>u1Mo$fXTWT5gY!Nj}n#;h;Nt13SKdS<^j7mA-yH zpB?ZmQQPrHWgJd%Qo2(3MgnpXbLi)$KtJ zWI(_`H5ZVO~$Ivz39^0*Tb&|_TeMIY6{q^ zW1&YEBeK0}JnTOqB091k@{ny;EEKGEMkfH72o~!UBxWTpb+Kc6Os4j=y4MYoO&o)= z`Y+_2eL^h3+iuBLY|2OX#7Q)6;ybqi=r=E3K~}l|2~8dKPGp_}cHaYJO*2XWrFu5+V2F}wE&&h=}+@(TyROnsx%RrK*ijtrxxK<9segxvbAb}w97IsYWceA zdas+iZ$ehQ7?%dGHx=@FeUsqqGQ_9yfmE=OAP?dL!hr z@4gYF?&#Q8c&$ed5(vlDC8V|OGqqB%>sJ2E_bO%F%DxH99@lrgKm?K(tm4Z~g_)f; zI^wd=!yf#iXy=TQwgPeO!S=v(<7WHiHLS(_yoaXsMIzVTa=b$RJx4_x*my&8z(s|4G>+x;u-VgpX>3glQ7LMSs>j-XM?`thxfhstkWYUwZE z82@ivL_O1OaH+U*9)GG~-)4B9L%;+CO^5t{ zvREXl4LKl$AD^wMMp%1kD+^aT3)TH$Go*aZg`U9yfnEbL<-> z=hh!-@N@H&CSUIhc}Wtl_op9zS*FrJ;PORK8`!G0CJ0CNgtA@ zd>8gu_K3jDS|b@~!xzd`gz5(^;ns&z5h%P>$G90y2(#XsNASglO?bOUW){Z@-{qkwapk(r_d|I? zCkQ9W^3M7lfg8D67y2R#*GR$keU%YFmSxhBt4O__KxjfxoM?RBgv4m~o*O272b5eY z7<7eYPap4&E^2?KAmHWGU*Bi~R2w~@0y{q9sQRM#S#GV`$g#HCn z-^VCLtEaQjz1z!#^M3dK6DN z6gBv=Kl1gdz*<}Rt{pRf*k!KKR=#+tq@WwVD%bkOn9;7-Xl-^^oLs1)ns$UyaTmSN z2rE~>t=L*BFFwhWV)sLne{Ecqxs!i~Gz8-Nj(U5VSz%~hdgsw4)wMz863tf$#GY^w zL2-e4IvB@qFfkS8q$B&fNVwquw^9}kw$0e(^zYT>ouJ>;%_f4*m?PXr(+?xP%L>MpA5 zp)xf=ZE_69qeaF|?sCjjt@Tl(#K7LP@xiSN%m6LD#09QUWS!#|tkASZN@)xbEhZ88 zf)~X!mE3)&W7WGzVZ}FuhFa>L_78~lQ~qh}R`Ml|u+{d_YlE&OUj8hpepIZM*7^=} zyyN*y;Q3y*2Qi7yH8HF-q?kFwc2UvTc8l!g)cOs1*^)XWW)%3G>*W=kK!vuPu*a5* z1&J^w89W-X+I3@lIVZn5@Pq#kZ;ftm4T zgJQ1u3#9kAv{Ja1$gr)M6?g6v?-Xw5u$ut}Pswb*DQ;gg9w0}vbs}yiA+f^m1KZ`? zZ-0sj{cM3*y+;qp)uC%WFFo+wSuPKyLcQM}o95_3@f4MP@fe~)3!3cz(mx;( z{DqO=K$d}6Y)$Fd#J-p@<7YkrxTxkW9IcHnl10kw-+HqIzLnxeWz z{f#aRwx_%Vg*r$^GCpu%g!<6|-(ohd9ZhcAzpNGC_W{+_lcK9;g(&V!@Ut9tiHv+% zI)8d&MorM%nle7T4y9j)k~01AVOsg+n|m_rsu_KOri2@UrjcHkCnVLk>b=*a&NW`c z@Sp^FBC=ENXx|DEF?M{VW$Sqw(I1-WvFDL>trluz!4Q=0bPR6(mWMGC{Cs(J;DR7D z&JXUA2=gSM-Ma$}Kx01#sZvb&lhw61i$IyxqkLiK9sv(|76tbtB$LdZi|@$ZnH&Y* z^xYA`oSR0T6GYM)HzQWxMZsr@Qgb)AEWq^=>$v;f1sqja#Gig(m>wP;rtD}WNrIJe zE)@+;b?k7nQ4lvB*4v9mJQ=1DGk_GA#&Mr*DtVFZV@z=xYM|Of{mC)D;d9m2S;&+k z?3C0;?^Ttxe*O=#H4qWtn<&C@@I5^yY3p$2g>Mav#3^O5AzxKwI$5LGHmS0Ol2b5A zR#?oVTrOIJ^At;r%7ZZ%Gk#@a)>sF*7Bn){&!cP-R$<$KM8k)ad2D0=@%>XU2HyF` zyJW?_@(RJ>E{kcqCB>+3Y_pd$cx29OqUPw`oiSyWq(Q)n9Z`fcnZ=+I+KnxBqnAw7 z=#)4QT4}7W`>pwA@J+Z_dG-->;Icr20~5~%b#?59BqwAv#nAfhCwlS!-#lf9;9;K_S{M5S$P+B=>x5(Rh zqfhqJ53ydrSaqsZ-Y;WOpO|aLwp|$wqq?*q;Qa%*wf6;GQd;Q_JPsbZ@@?M`CT!e_ z!e+CTSgXQi+Rmn6Qx;v)Po)&uL094eI#)wyZz0CB3I1Q{cTLD=z=CjqBIhQC{rX6C zeh5K#wuFH*JF6DBtpa>5d|VbBPS}`cCQcu2nqH%`j}F@}Wy=8}!{GGM8^2`oh$+Mc znW)3I(5W6oi|n1fsuE}+Z4Tl|H@){(TLL_l>WbxbDlG)vPhU)8?mXo^?;nh*U5bbw z99?@`(WbJ(XF_z=2r3A#92}s8I+y7LYoi-6%M(J!3srWq zA;;Ksg_zcg#xN$|Q8*Y(BF=Gb)X2o}O8ErLyfR?^Kg z(Vs!81X%U?b&`VPLqyri(`p*E$js6#MPb!Q@KO+?t+t}duRGq&D5B^wD*6s@uI)m} zG?*d(KoT9JkiiT10(BlagQkf*@{2JrE$1 z>9Q)jo-}}dY$zZjJapHLcE9*KJq?Yzq_*=rMWSD}@f+wS0kc$k7(IwidU=TO5pQ)O z+I!M(Iq)Z-@rYz(3ZSDT6QcY?8Ai_+r&Vv2WwK?rIR#yZ4dTnYL`gPrAj|_S%AXd$ zbnCi)_&Xf#g_wbUw_QTfYD^?Zhe%}qb*=5b{^{m#&UyRNTW^Jky39dWIbCrJU0b5o z5+BK)NDdgm@`^z0RzzIY{NVQ3Pt2Ea=Pe^GP6x(9hE703K%vyKRevrVjki@>Mg*{? zCr(C>%~1Rx>}ca)kvJV3-E7Hx_*P)%PIqEybvXigAZfDOUS#KTy1}&9PC7e=mM4rK z?_alQ+f^mgEG8KtvrA~K1Y3K+fnLLby0h+EH$WiWmTGyx2fcc#| z1)1CnholM=j5Y(l79QK9Cl#y@d_>6L3ig&_p_K2$&7EH_n_kL(N(3z2@#V%>`n+6pt_N>Lk!XdTSPt zVMW!GpPTP6O+os~G|?<3ujp#HdWL_p0X7xAoPBl^ zkK*tNj4#;ke)xz$Pw8FI%FMz_o@c{e%hN6Xb3TUaedmOMo+2s15>rV|I6C#d2Z7`> za1>ta#Epe!dl$2c|Bq9@=8cjo@K>vle@q%g(n)sFfev7j#qd)*Eqx0s6qL=>e}1Xu zPLO>7(w+DG@YSHzN<^qtYy>UR z{3!O#|BUK2epT+{cznU@$-qrh*euj(+lY1sB$FD^9*DjO(4?u~rFBuq2?{gNvg*&+ zTJY---fqAXtU>I-nCEqWdv1dGijZQwv5nRRe{k32yU4;XdY_>F(!&C&1paZfyc;Q5 z+)x(?L4hTk1l7Ua)M)iJCZ*9WS>cN`XWY5`bfeYIX^EJ1sfvak>F$xz_jx<&_9;0e zY>kYqJ~qz?Dhv2mX~Qs*3MUgv@8$y*Za;5xE)6p_aB;Ph;-s8+G#u?DB-$4DdV5;~ zM@*KSg-_(z1JGA3HUvDgTXvU_6gcHNoVmYi7p%W`x|emw$e(P+;*7nMn+JcFM&Fd% z!uRzgn_F3ezNV6>45V%;sp6f2RdY_TRJ}r3szTs(@lhVfjG*sX;U*My6ylqhXcToc zsv!r!5y?WF5Bdl-XJ{tmOwIt{b6CxyC)oczHd`=qAi zY;Li#;a(GML!5ont7^Ir^8nj6ZAp$<(b8=V=vElN@YMlw(&*HRo-5mbOu+!+<*j8BG9^Exla9cv ztbe&=A_ieFK*S9RMr6 ztHDsUIYDU%(Xv^X8zGagxtgxviT2Nccx^VMy%~>>1ab0+`d0xCCJ{ES&&xWk_6w4U ztYO@er_GAWkN=-`EU^P6f8zBz)Ibu2*Z(~}$@}cm4sr!9e{*Zvjn+g1JC(=s2}fD0l;(J8<82S9H-m$tF%yEK`pv`ernpd6sK& zoQ)k(`y_95p3wmXQxlN$rVgSfK0fZQWtQI$h@buni zbjf1SEz1fME&(+0GGVOY1SRs!krW_wLO~4}YyHEfD*^75XC1q=f`#8(J4@l6SI!|& zGFO&L%t_Lgv-OdM@rfE&Yiyv$UGPHOiGTu=%*J558&S`hxSeO@e`8cU4Q+PBy#uIyip67HX?W}&<1%K zsXc3P(3!`!=(t|_LbA+T^i;bpO8Xv+GC;}eA6hRX63SYRxaRbE9lkh@i0Gn$>6}i4 zYhn~j{VXi03$qS|gIHd)+zyPw>8LrCfbcH&=mP-H3F9sP5_CT7r>gB}=_ zLm%1i!j#3W>)7P1e!}knXAhgQ$B1Q==p`RTa%b7;3_L_Z1*|2MQ*4Zv%fr)OG(sZlzDch(~h zI&%M|PS1p1G5E4FBLxTXW8UO-nq( zwBm4ET_m``85aKEyU;nARoH`T1tZo*=ug+b{8v?vdox2xEYP)k8~U%L!SUV;nnxJKNH^jV$z}~j zww*d9eC?r*nM&>`ELQ>h7bgNTa3KT~e9;7W3x|eUMp@cLtkyZ?(AW#QX>UzFT=x(jZLUyxFFHvCxZbLLkl-PCFfMm=9 zPaM#CNdp#DQCm@ZhGY`ykk5}&2|4hAQt@^4^VzDe5)V-f)b-C>8YBh<_U^oiL!^hwQi;cKLDCm?`kcH4({rhQK-2E zdr8p@HlgsC4cemRb#m}$A99Ad*KGsucs1)>CuoKsQk|jRa89HcT$V^C3jjgX6W+9e z_0)#z!BAlII2*Z&eFK-&t>wYHqnRbe=*?W#(FB#kpM4$V%SY>9E4jvy+mFYatW^i{ z^KUQJ^hJ{$4ql-7`Bd#=$yFRWDh_SJYFGUyV>5GIS(TY~k z!m4EqoZmJ{lQJUZ1fYufmQ+7umWR##6Y2fXt$+70&z`>*RRT+oACNjFOq#4LzC3{*mXu*BJ85zw8D<*Vc^~ErX6#K}) zu)IKIXlI*5fE6yPWn3|EUQGF5IHWh`?j*P`e>H%(!Dq2ym!CB3*J143EWklMxy-O?TE7$ z;R&B65Ra;)W z*9A;T4C;f)l=~1U5E1R=ps7+NQK9WsDljzhVy;Y+`C56dR2}s*kplG{CKHYP#91-} zB5CY7ifY^HS#5|5!;Lt+d`%JWMQoHYbhPc@^{E1IR?Et=5MO5yb%9e%^F*q4HNQ0P zH4(GdDGZU=1m#??m4X)1hHNd_UgJ0x22E&LGNZzpkk*C%>Wj`l( z1nSB5y+0#50WwsY$n1=|3lXh|!K*)Rny|D{aK>@`=(XMj!?wFNucA36=Ub$nDmB@J zpjsIOtTnNOHus1}YxOn?M%iN+wJRuN4}zN$6_uGFQq3x`7<&VM0zScBmBlK6bc}c} z9@CQod7dk{qkNbMSV(=IQ#{GRYE!CK5|xUa$IJij$`?eQOBI2BybT;dA!Z+UX|HT~ z`@THQKtjDEJzxpBM~Xu#wOv;hmq`kgCNKS78PqJP{xN$@q7g_lc&~a@J83-%=#8DS z%vD$o-pBXhM78RPUzB~eruRqiQ!85)^p$=pq++_&MmZ1iy%}qi2%t5V`^SUquikZ& zYW%TZIqLQd4u#ej` zyyk_h?Q6Q_m(vvWd;Qc0B^_F=v|J^-WZYmVZL&xA6t3vKF?O3)|CF$QEktEw-^H#p zz|i5v`kad9HNpPzPl(m3stV;XGqA+d4%Lx)PnM z(FF?wEa{b*e(h{h&gg@#2fR6{Z{muSaEX4>dAet4%KNDQQ`mTrQUC8xzUbHH5cVot zFKxP|u`J((WJU&QG^E5Ip^&j(8cco?CIOi?C6}DZd(OMpEMk#Pi+o1LI)HAkkpQUx=IxT=JvXdpdkO)Z z@M%wboBTx4_u1{;t#X}QFk`>}vwfs1Y`gSI(W)QMft%^$Bs*X3wF2-|$W5_;pC zr^WJb%_Nvk4m}=*^%V#^2nSA9=6*TLH9{~EYJ)A#697B}aOUT`{CyK3fBUEi0?T{x zV6^UI!la9u(W!sDtX-K`VFwajc>-b#)Zvdbv!~Rh3L!IVL8l6Pncpt z$V~wk#A%Squ?5#q9rV`Y$p0gZ^-MJk>#CP!*xsd*jG;Hr{LwkUueea~nkO>ca_)^% z4i;H^#WF8d0r6Bl^;K zkG{SXv80|MTdgy6@R{`R1fZ3(s-gp-6vvWE4%vOMX%o(XY>z1~Z zj#%1^@vZ6rRgnbl1Y6Svt34LFdyldWV{C=mxLX8ut5~!8T1AVi%}44{;6Wj=-5vj$ z7Le^EiSHe0YMR-J3R5P6*_nqw8ez@{oOgELLYq}uBpxdVlTa)k4Qf-%Gmt#X;Zy|= zj|un@M8<^g`%rBM_v}D`Av9H+m2K-Tl!ru9;EUXgC#E`$=jg(0>M)44UPObd9(SFuYR^k;pp7jATDRL z7w#GdH9PkPmS+K$bAVQ-Xa3TZH2M zkoG)Wf;q?W1%EVp?nmcE&dU1&Q%)k=cKm#ta-%2;7Kkq!66V16YX-(WT^u#V|1*6t zbF-{;;OM^~K}Qb9yqZ#?%|qMO0$`Z3fuMNBRJ?+}jXXHmasYfJofOiA1#|Cz@haak z3<_OYyz{mcKkVcdTr?gw!_-2yu6G|72SaZo(=}=9@@{_;Rp80&# z?{X8GC+I>c8HgiIZsP`grHy@Q&ov7V02vQ>wdiouYCPaP1{`CNub1nyMH9f6?rPZ7 z(5@H-s{kVk6o2h}9~vtS`;xK(9sG0E4*>sV-q|k#T$4XnKmc*jo``ZA4$m2?TX$YO zc5MPSz`Nskv~!NLamG7`*9zygX`;xnWAU~w%IhBKg&wS)pmjvk5>cG4lR?+&NH#y5 z(0}WbUdhRiIZZdXt8A1hOM@pgO-HFdgxL69Z7KeW?+xCqHG`Oq;&94Isy zo~#!}#AS4rJ;}DiB2fda<*@3~8MTx(*^Wm219fB_7-d=sMvsKA*c5Yv`oozFfralPz2ou6K^g$&g3+|Vj<&YgYpxBaFCt}m z^aNpn{q%)7t`P1IMWz5TRpt4iy{&wZF%Hg0YjBl{Rx~Mr_Q*J~3mjNMXf%NvRw$}1 zhd52KvrLBE4}3QVm4QJuzQJ_s^!~A7{j7TlPy93RCY)3;>Lk<@1Uc~-FNQaQNoCJi zr%HNBa2XGm;KqN&$gtcn_XX1pEqx%tJ3+rKmv zziti-XRIqkM4%oaV3i@Uw6;Y1hoQMwWh%`IG*wb0mDKV|L2c)6x{BNYFl~Rwgdm~5 zs<(J>XJ0X+q!Vhl-qwD?JY1lJD}P|$!dh`+?CmFE(d_tA0JNxabu{XecNM!H4M{2L z)6X?T5)xZ$nKS)kx2(G%kE_M0Z0B2*4*5aAr=RTHAWH080cq9Pg)%mP@z{ARZU>S3 z6Bic}k zy~WJsm-y_85rlAS1*VX{n*R2WP$6=WJry)gaWbdGCi}6c)kdt%SViQ%pD8!u}mtlt_ZnwP(az$e4%jqKR z+D0@#`$Ut^(Ni)7on&(>XCFr?u(sOlJo119Uo?ffbN z5DX4je1~mSk*%?%J<{pmX)b8}+*LR*q$B2Y*3+M5A`HnbN_l>zQ@5l|&bhTw2?|ie z_8{GAN&MpMF2g1Xqt!B}>X5G7qssB32t_Y5Bchc{RFg%_QXm5PXQ zZHV479|VlwMNlo>+g`j0;S$5Haaz(-Cla2cw%&#B9WXq0^nDK|PTh)W4!N-2aO2Xs z#(7-fm*)9^P>@|Kv66ilco!N@X@nawfocnInxt@_k_^}69~K4y4cYNf+E2mixpzMo zUAOvE*FqRfmV9msX1@np!B5e}&~srCBSbJ%0J}Vev^N|S$4dUA@wcSPMk`J_n6-Ph z+r&403x%GCSpjo-FTQdUsdM|ylJMM?>zguvvRi71e#a>O{gFAocH60Cq2~vZavS>F zqdt``4&28#0t8fp<)(jxwCn62?Bh5%nyjXw^I9p{?E&&SG`a<6E}|5kBm1JrQZsm^ z`tQ_^?+{=IUmIV57{aA{+}b415s#@x6~8(3Zd2=MpGiO6b?E*FSc@8a=QME&IC*jE=>wnv{s-;Emy*%Wk-vc=tN%gI|) zwJqsi*41{9_@~?aVfj^=GIQiKXvciJRqq0TzGUtcYn1C7u?ef1gB9{)-epusLOHbru782an_ep0`= z4Qc@{g94%N*$V3l0?J`W3)}HjoqqAL(02ZQX-EWQ{A;u(Opo3g}$MSP!WFO;T zcb!0NZJ@D5^7AgjkA z066X{yN#)7xnAz$vro1w|I}a@2vn>k0jcn^>A_YecJkGgz9P~@e^~8=V1Kw#zdHf} z&Bu4#K=7RWnYAbS#g*an$Pv?J)z-U^pYmuX85l{$*8tK<7^r~pLM&rY0RbNsEx7`m zCg6QO>t-0w&*h<44B(i-vuMTm_o}(=SvFjFWBKyBYN@^1OzwaNN798yW62x9ofVfq zkx^5OC@7KNB{lQOy9zEvoqSL^9a{Tjt-?^ z!UWEEM7(;(o34U8rH7P^!mX^iOqGvTve+5K3+db0W+sA0J<&$P zQlK{DU3!h(c#zYmxbAT#ly4G#-;)nR>N3N(JtsEX&s2){@r}VD1~{n5NYg5Gl?K8I z!6-!zM#+gIVJ+11XslH(or7KvI-Xdv72Z>`*l-@AJ(E6~$N3WtMcHDDXs0TSZ($if zHC3;^Q=0c}f1X)@e94s3Q11&e@%BDirD(EXt{%0-YKiN}1<2Z3*$*aINCKdn*2hCp zy{InWsw=g8NQ(Mw=ts(bsLVftvoO{G+FXt-O=QuH6soT&}R1yYjb3L@wK{HVHZ+ z;zb`x5La8WGHQR7!Ov{ZRkaB(X}fP&W?6ec`<$IiAZ<|Sbu{>(c7O#$8pI~3uf+TJ zIXp}Imi6McdD5v|Q_f*Kq~7M<8nM)h;U_dH6t@Lx5L&kz;v7?BsFk7t*$YnFsV15wnpBcR0tQ79g~5$)RcpYQ6;Y>m9IsCI zs${sZ18Y|mv5{#DWf1fvUSO(p4KBd>ff>{kCjq4>spJYdH!ZPAQfnKOX%kDjM#Nw2 z0=7o~`hahCb}LUf?>ey~l>anREu_4|41I_KkJIJPnXy^iFjzvtpfMUkIIV(2(pO@A zZOGdXVQV2(Z*t>#@}X2SU1IJlLkME2e`q&8kwhw3W|U1-!8A>}P4mrM`DmPj%d23o zrx2aD{S}dNQHj5Te@Qei%>D%@e%wAlD5qe^%SCMV2DxGvTKg_6UOZudA>1w_{Gj|N zw1`=Mo5RpZ6!!NEFQX!O?Tr)icwk<&;pgsMV4}5+kP7BV%(44HnW9#Q0TzPI?H%MF ztBz;$hgAz2i1&VbpE~^s#2?0d4GAAMj7J`tSuF>4c3f|>bxyR;{HuDueP+%rdd6jD z!o3*UID_aywqLfl>b7_feix3h7AjGd!vj-~QW(a&3pDfJYyt1EwFOcDB@>z4}0cU)jtIV!CjRGj3uYOZ{xk&Q4La)5Z}i{ zSAGMObe(hFD107O&xMdsfuA8pI7PE+j!!IamvdPUdg>QvqksX;U&^vmgyl0oUzWU} zDSmsgNd-Wz8_!u6DRL*(!~gV7z|?qz)24%LTaD)`p5bu~=0iRh{Gf@qGH&`5XXSzB zR1@P5%4g*rS$EA*@oRxu(Z5hmfff|P2eCat4 z2I>LNqdeRp(3zH>xwHrWwGjJ4oif$k2*KnOCeA{8g7Vy25d$?0nBM#tk@$_qqGm+P zRa?UJxiDFR!nf&q1|;KklbLx*pJ{^I9aCV577ddwrrkiQE0bU@k_NF0g3A@mE56tG zw;l31I|DSA^&b4%=YqJe=c6^D?}n}VcR-dS74*fXS}>O+ylM9H)P~UzQSkvT>Dm16 z#i#bi1OmBHJLx7_oaxS1WC+HS?WWQH$$Aaj?+PHuc<_|~_A}ctPQg5NSEgYY zET>F8Q^7Uy#iV;L2$o9RS+A(3(AbrgCLYc8UnK!hj^@){{4m?p@ZE`4KulLAk&m=5A9BfZMkbnVZfj`W#*K3llpyx95Rk;Z8wK~kh3inpoDF(aAdqaU(}dRE$V{qEffB8<3LA0mytZKBuGfs^uLvGiM6aE z{kC1()c`FsRLjEH)IlS_W3lC1P#XcJi)6CaJGk_Y%UrO+C6bO?rhyn&@kDPM$(YC? z#hwMoZVRl|3^wGyy|1XZ)rlAdq0wwdL(e-51#JzBShvd;tGNBZvkj9l2#V|v^y{Xczwd&uc)=l@9$!^1Rcj6}Xe2m{wu-!y4a zlIc2@ZD?k;0)Tzy1D0+RipJz@L__%%Z6A{hdCOJzYXWaT@%mv8dx4>z7zEFjiBF+c zQrU`V^CQRrs3p>?7RYM(H?~1I@wWIGZ?*Upa53OO3Ae9%z`r(H(>yFAiQq33%mnZ8)5)6ar5VJY&bsRd9{_uHxk1t(vb z{kqoSvR7mh%IP9EfVK-Y^<6QPFKE`!SeIQaKS{cFw{RT72w7!N~&i>o(T0O0Xo*z#{x|3!TJMC7o=l9M&6n&8TX6 z1IqCB)Tk<;<+6)%ISja`drnnKpHUvTZdQix?(|X}qW^jK<e#d?Vr7ZL{{_jrC$2XpRiFuGvA;nY$ZdpbqD#c#1mL~bkTXbrEk@O zT8wb7C7#qBT9UiHE%;Ggk5&}lN8}=RIqh`gYB<%0v>|yqPda-6q-5@k}j_Qz@ zWDw3?0psuYrdMdBjZ)D!9Nigvi!Q_IewdC&5zPh4A~52kfzJ35lQc-5k;c`rbgA=< zKk?c27v**q$qiuqTRh?n1vyCn`lMI{OYxv9F>lfHLLg`kO+;&pbvV}iTkWv?8A zZwi^ep3KvDG>4XKGdnxtd>y-OBJ_fB?jg%o6c&*|Z?c4=0m=)F29c3bSF1L9sZx@& z8K+rjVn83zvDV@E@^vl=PqXE~6qLyw4Bals4hKK*x^e)EU{QZa>^N zAPHoXIVE@+(oRMv=60bd1QgC6Te*t(>kDt#hv0RSigbAQc5m-kyWz;ayP}5>ckzzK zY-0^6!gA+*YUpPuYd>+Ow^t3uuj)5i%iuOzMvDh4|A>+33{ZRFdDm1h&VpT7No2DHQ&z z@uVz9KhncQ6+#rM7A4mPnd;ihjf9%e&We2@0*DDI2ADCP$pj9_yyZKk&a0h{xD~XU@NR?nQU~bUwd9yB` z$5;ghTc>`zLYp%)XZ|*@G07qEfuDj=*cQQ)wEGf97|Lpy2z39)=BGhGnla+UUjU{| zCyf;KSWfL+Oi>kotUA%M|65xyt9Um9X8)#pZxG`RoFTldUG8m`V&`_kUnUo-z4KNa zSlIFAUvI@Hy_T~^Ia|UuMFqvC*uvM#Y71IW72NmcPA#3 zon-Ja6Y}=HOrKrx3=;&2cgsa#X8Oc5*VzAM*B2%!p*Jm&zl^@%;qiV+;TU1J`xkou z_^a1IAbY*y{s#B_ra``a}dQSb2N( z&t0_u4pZC{ox|Fd*ie2a)~}+uLJ?LgY!B!9HkyxZ1ab?{wd|;kz=lMot)YuLa|s3k z#^pJc`lbzigUonxneZustPU+@0XpVT)j4-~P{+gGA$`fErv9h)*#)G9sMO|L zLDkB8dq|I|CkG#@BILfIiP|BAhuuB|8pOn@!xHRL8jAkk03JT<4$k675>MQ&Vv5D+ zt8~LITG86#-z6uuQnp48V0q%y%rB!ERWw>lbYp0_v5P~%Lzu}Rh&fUADsldJkN-Nh?d@35sAlBemzk3l!6vgIa_Js%R(`NZ z`{nkE(*h%PqhAP&r_5u*HQ#%zY=d`b!Nx!}ku1i`D4;_< zWFBH0pUZt*FqitOfywzjV2E)%CD$aR`s&)pmjx(wM1jTAElw#c-Db_#9B5aMip z|Ac6AiVwOow+Nn!!Z>5We;CWPII=8^AA_^b{h5ga)_kGuGs<}agm|Y9YLp@E`0cCA z3B5v~Dn*?>**4dYbUi&+f)gGW5DRk4Z>BU5{n3If73tVA>o@ohp<_Tsv+* zg|2K?ec|?S{@TL04dy}TLPW@?o(vpvDb0EKK>jBSDyyd`Ikgod{gG>;2jY3H(*|4d z8DJ;snkwJt1GhS@LSXvAy2W^-y1L4YgarU&b)bjIMhN|lVenjx&Qwd-A5j$?AJ??L z{1L@w7FTn&-?fWs58K?->lXcj1(uic{9aHq{xEOf`VnDeF=S^MIhRH-!(}H5>{;xd zWv(s2JSt0#f77;4FE*==3cS+<`!1fuiP`pCC)WdYK#ntD+^V;{-X7<`UjH%-oR8;l|f{?;6lS9Y#a!Ry1 z&Hd{r+tDC;7jCV=0$-%He(^(|_zyo@@vQJ=MMrUPA9W0l&jE&$jnXK35UKZf)X{;8V5~Z+D9}RhqmPP9()vw`$ed*am26C? z5kmW0qk#$g8(Bj!nyI20TKlZg&7s#q(UT8esQi}8;TYYtNDhm5UM4x=_FJjx!0+l| z+^Q~@On@v?5pMP$-Y7OkF~sjwZ{^-c;!2A>9)897ZEO5;5IdGKBuc28$EmX@UijHQ zwV9nGn9DA&g6z%;a;s-F$NGH#WZyZcig^b`D&&lf_$3&+(gM{zm zBQxugnSRTg_dbJH%umHRG0Z*_TC44==PNYmpj|rKi9+>s*!H;~iliwuHLimJRRGA& z1C@YKOi3QG^4$4Q&V+Idd)do=#EE6V)1HdnAZd(iLn6zA$H+LPbfVZKdh;XN@dWRV z0Nr*`59x%|H3gw>_N#l?Pbnhh4-~^YZntkKSv3W7>E?f!_L)S+JW^tg(iwzOy8eNM z=rYOW9}2lPz1sJnYu2G zkd&qPJSJR|hK*T;Rd;ACeH_QBYz~xHhjSk@phi!%^rL#R{Rfk=KDFHSi->FnG=)2- zFZbR}AHWfI5MOO7xQd3H1`KL`1XWXWwBifdCAS~xF)p1}>Mb35yKDt2R|@sV>Mv<- zk62?SYDSm*Y-yJp4?QEz<+On~1v7MfXsnkOPRN3Lv2Z)!%*xrAqo7$jZ;1EMvJJ>0 z*z<(|fN#PN9UR6qmJJ2)P8~A^{2GNR>p{$}$^iM`vnIsYw4*_Clo;n68#c4KQej z5odjP$>c#Z6x+em&l9MgQc3Vt**6Xg3mP&p9U6vT&-Xney|0^XYN~}(Z{+?ZE8RFG z{s%ZT8&>~r#z6v8$(@h6#$ZD?_jjvBXWiDke`$G;PgGf+Vxc-j{&wy5kc!$ zq(&`sM|r)!Ffhp}@^n7az;^r{rW_udbe1^TeZ&6l>+u3;xGq8*j_^y?HPu{3s_>N8 zi zz!&0gND-z-OFn&1qYoJpvkuUNXIx)VwA(_}5lp+4ifj*gWY8HkgvHbt#h)Un-Dnva z9H7kjVgQQC@PWlLqdv3I>+XC`cxn4m|5tZKfmJ&CK{6cBBf~oig-ad$jl3jNaoIQzt-Qic2c=M2vu!V_B1=6~_=|1=@3@=mZE1%0^fP$Q4N{r zOtLROMa7hkjnK>l-(b(D4MK_tb_KVxA~~Gk7UP~;d%cOtoh|6t zus*`K^nfFsBN!rO`BF%-!i}LJEJ9VYFDjaGrmpPgGW-IZQg;%JkA?HbyQrS31~D0a zM+~u_1F?B^0_k7*kV!SET12l!E;-ZM&P?He{lgAuCQY^ykvcYW+@|3GF#5zMeH~_6 zN|0unCRFxRw>TsRLu)ALX3wi7T{L8Gi6BbBkwihlvzyr%+1ff@I~_x_haf$u9s4t8 zq8QzUMUzp~#`ASn5&(V%NVUZsE)cxll34^5ffK!}*Vr-zPpH>`HWDUDU>Mt{cS2ni z8y@8!72J_$;yvna9J=mWR_T+G!?%S*oz=l8?07Oje;ukjFiv*!ugFB-eiLRz_rzZ| zKKC6%KwJ=2#0v*c99;sraD{pkQbs6}^lce@l}G?vZ<} zxcj#+Jh_s%Cw$5(hx+tGuQ)IMud=8TWKF6u%0g=X`$p_pOM+Nz*6(M2{L$HVl47Gb zs?`}bK+|63Ni-Kt!F!Yj^Z}snlE^F8LI3Co5j*02mKsL@%`N?5xD!wYL3y)thQkse zf7?6gk#|C%2)%doSPn4`hIM~wr2n+~)r)RT8-G&pA?lKS}`{ZKV7hb&Nq3& zDG?bi?o?C%fTyVi)oKS!V)~VFykqOPt;Rz!e`lDvJI(YKEYXa$*R)o{@Sftx+M7@ya~7i3a=a zB_AII7VWq>--ZiD_Sq*Hu?{J0q7K*a4-@W_#5m8L4Au|B<}yTaU*c4iU>%E7Gj$4q zY!5Z@p!kl+Ds<8>FClJPq^%mKEM0l1bZT3+<*p?j50Igbj7%*4*^n9Sg>)i#?!IZ| zS&BYm2Fh-Ewm%}W%z0Tg+oDJqvEpYU9LTp!^)=!dAfF5Wj|GK{h`MRtQ#1!X#0rMX zn%wy4sxCGMqB#R#oD>G{XnK>w*53IiHXRbD;7JQfD^V{DAk&7+w{Km}|* zLbF(3FaY+)TM7;IUOUu1)jxVKL9`}5C%_D(Q)&Qd zte#vBU@1^#o*7B!kBIWP2c5dQ;0gSWyz+i;5Ofyk2+IO52=(~NO)7%z$t`dD&etzc zgsQ;Xou9AlwNrHrd1f3cnli_Vg}5K~doV2?+?2Ml+-E8i|jui3!r&M_J)3;chhRLXyC zlDWg1b#EzE99>toK7|6tI* z4^AFu^_;wKh_eP2*atVpJ}nw}RB3IjpR)8!*8RtlsVCC`aH7T#u@WO9#w^zgf$a@u z`czDwnm2#~P_12htC1OP;l4Ielg{1<_lGlDmYE8mAtm6nhoV5`0;q^B(;{h0XWn`L ze|b&M{Jiua1XzbhU#tVi|8iv{mp;uc1m-{Mnb;!VvZminCAkTqjWso_)Gkc?Fkr4M zB6=Zmy-UJKX|w@j<|v)WAkW(Yz)&w27O`bM$if08!*W7)#TG{ZWwfH zAe-Bub+Sgr@70=1eo;ffI4{o7lPBh{H3D%`m>hp4T-ti?D*_N2*~F(>wAbQv4$*uw zILK0z!i*mc+&rM})C)!HLEa%xG736(MCduj)btGzoo#>Ok-2BAog%|+bKMT*1KbKU zmB6>NRDgkQ-QIAMfH3sMpq|kJN@_R@gMm|N*#InF)2K<}|hI^>RfNIA? z%GxFK`*+;GnLe~jB7&O=BE4Y%?Vsmu5j}}(V-#ICY$OT*(44x3gZ}s+?Lc1;t^Bh2 zM+ZK`SOb?;(p?5Ig2R~knzhtG#4>|)`_1z~cYrNYkOis9+ycaWw#MuRfD9%99N*R=ZW*-Q})0yXNoa z{xgJD6%3yX>Y{V+!%L9?(0iL`=mDU``DA83ABZ$?b)$c=2)g1BywlDi5 zsufJod&d`|Pc;fQkdU9{>DvRc2WSS}zE75KV;bSs63?eR%*@6R@tB}5pgiV6jt$^r z5_E={!}@S}oHUed?1QEVt~HU|QalQ-7RFvRfOPymWaoDN%|K41TbD%0%OuM^Lb2i< zWgV6sW4<>}E4fwuInx3Y>hZWlB~X8kw{EgsUwR5U^v8V=?UbI{oh zb#G&<^o8kJ{ddu~ zPAV!5%>0kTqpoC)ZthS1u~a^ENHTbU_lpi!Z16`Tmc1R@l)6({Iq7($?;j({Oq4|S z%_X;B(>>0Px3|lvz(+2=mGaNYF(qhfTUZ^1`Ty2*GtcLxDP@aLhJ~ zDI`qUh8yM_K!ugTbAW1psjy9QzH}IMUCh##gz&?8pW!JQztgQ2u_rJR!3DUH!j6tY zAhz7}Zd2yb*}ttEl^&;Q_80dsGc|c0a*|3hcrGYfIWC*e`e0WGjzjOWyh}Iai0xAi zJcu@pahWK*n;0eD>>5;=5;Z!wrWVkIqQ@^ZfH4J7bE> zBbH~Jkm?xW9<8S=gla`!U=pv+AO`!t7%_XcA?8D!)2%+_p}M~UkxMvcXajaZwi)Li zK+;2A99E7j@aZVvGokS|XrPc7lP1HMj#hht;uJeT*KdN$o0!rkDLr%}25z7PC@LBc z-E*M#-ZtpoO9_ZA`Zo@;ke2or?)C{|ugrrMYl|WWfw8=5_;vi35z#0XY_~X^9wr3) zHsgj2hWoRQo*jc}XT{r{rB#A!kAvW>OX#IXAqGI|_z_fZyy&>J-G^0(26f zy6?hSo?pa`uf7Sj!Xx3!$%~e*UL_E)Y>hc-_qN~&QrR9lUbuaYmM(N@1wkY zE#uR6hIi=7s(F;T@yLOLz^G&8#mCg@m7nW6u8A`mVKwS{=q5|rDcMAx7gqvwGj2ea zfpx9xrzz+i#Uf^Vkm*D9TzuxtWV1r9dGfRNTp%$DVrbLYry*i+V)}|kfI@ENG}IoI zY>UTkF`X+5T}%?y#!=GdVWg#Pkh6Y;9xfZx*=rjO0A8lSAtV-Ti8s~i{GtMSh`yPoiCzfj&N z32cEQ$|17g<*I}QwvAGo@`+x0waT+#6_nKZsY9lMO{dR^f^ux9+vw~bB);0Tj=Q9L zsHSxhpVRA|%1fcQS`h#l~x-+CO zuk<@#r*@7@P363kEsr>po|RV0q=TB{z|zXV<_nRmvxfNk{JuHXpDW24?1bRLV@ts1 zVB5LK1pg`^;!uZ@a#g@pAd9o74vL_CbQVj|ef&`blnE$8XA~IALU)XZ!BWh6Gnwkc z#`Ujm7wTAa9)P#iVar?%tWo=(ZSLF|6AXb(0JqQ}UC#fO%lHws+a=2{S0{Gdd>~PL zqwun&XP&W|EFZ2uD@Ehn1Lx7uVj|f2t{8aA+!QNu!O@Vz-lVMwDN#|B%i~p%38oqe z4lJKANpDLgwp)6WFd%=V(I?ok<#o*^?5NNqMt<4l$FHAgyozF_um+ZnO`pcfC@N2X zdw?9Z%U5N$T4cFn~pxd9282^xcH@6$oPMoTJHoL%YKzSMp%V~W3BQmyBq z*?fS#&AC#T&nN%UZudDH^~(x`VS`(s-Uu|=sXr_60`xBZscG15{k%u}5N4u;=UAt6 zgquT}Bwkdi45N*s64{H3oI0K~J!++!@Qh669Xw`oOQnnze&h$UON#b5UT^PM>JH2FB|iWBxj!ZJ#9J-|8`#g1ZF%g4i62@aQH=u4 z@*L=Zjl@qUM@spGMg%6$5hRjEOc`@npjtMMdP;%#P+uH;;0pgm+qfITVCSuj)o_zV zf)BeD%*@>!8+xRVgea>QGySP`TY&?MOFHfyOyJsX@6GEeGmJGnvcL%yU5 ztEGZg8E%I{_0NsaHocXE2!Se^*s4R}Emn7!MbXb3j2^G_6K-s~#HTU*mI!}%@Gv)G zBaZV%QjE*x zP{fw~1A zzZg+*V`rH-*ODew)(2cun-BdPM74dp2y|D~RVMiO^ZKY5dU8yQr)N?4;phcR?WCE1 zqIsQ$y{(LZ-HSYN)M9gHN=Ftj6p%O2lt3_!LPoN*U%LPzyU3DlFhyZMh4tw8ncpYE z&SlopW@0h}a@BiWuhB6Z7ztL-sVg*)R*mUU2B1MOMGlc>xq7Nj{(pw&)$ZwN7?YOh ze`e^-3$h3Qld?K?F(Tln)u>acQ&C@^b`$|-SHkP40@hm?5W_+8`x5tU8 zHIgin6{f)Q%bou9kpG zb4=)^>tl(JjoEIoRvH97;01IHuxdqkt6)u>uxtdE?iMl?>SMi zaXy&no**`G@+OL6%R$^Gc}_xD8c&a!cUCTyM{ODhHH~rXERv0oNSN)=YJQ~qrEeZE ztGooO#2-Nuc--DZMkbb~9-M(nV1n|CGF#*o_2*Kgeh1Y+PT-{Mv9uAjuJLa$7Hv_( zu$ zDHL&n_31C`QD7=pP^%#GKlgjvB;_g@#0yLMaK@&#mS5yj5@p&gBV{v1ykHgPa@ylw z-+F;QNsf~Q9Wj!bJFp$^f&(4qZVe(tvoa2T0_@>=2}_V!GBOo7J3)sEUI^#*TX?0y zV2|=bdv`a@8Z%^aWy4EYS*=ok`xJ-3$Y`(?F!CQ{f(dVl_~NIdzc;n23oKLbY2^a7 zDSg16Gq1*cO%ZF1+|>>IVYmx1#yS;RP0St zdacd(WuljxPUSdXAy-^=pW5q?MU}^A%Ur4(8Io4yA8YmKB|6~0Uh~8b@4`qJUwIXa z|B8{jxzm{DR0!Ntn`-w#VY=l!Q95)v5uK1Ssy)FHM3;J7+d;#GEq25`odk@3EvoFt z%v`N~u&5toa{BTJ=5wM}%-@A@SJI_{3$wtN)$*G+mDR`L6$nHKKH6*exf}LTUf5UN zV}2rt-c-x_=i;08zUC^gT6oSfzV-wEf!=a|`v!#dtyL8C{~Lf8G88niD%@ieV|G}Zbond4{hrdug*KsL7DstrSmdgX^%W7X6o*3B!|gPOPkBzVss1T zkOtI6NQPnVYu_c|Ie)yL38=EAqdao8jT3sc{dg2_kf@fUR4D=#of~_Npoj}nXF!qO zcLJw9q)LYrGRu#+{y}waG7FDL7KW3qUp})rk95JSkgP<=|)hq>VphOztz>!P;#Fa4D5JCxiD*LxA))EdRzks>yLnh1DBx|S*UHL#&}@@ zs8;1tdJNB}Qh_ge^lvDk2Je)Wns0SP!J*OC@xLz^zB>zbH5E&5laFfZ}fl`8A_x*#SSpAptULH;!92W01o4?}6 zxs48G`?xn%c753&K&%@V>e3RvX#)cQ53mvOq%DO((~L#@c5qpPA~fW_ocRnLV}1 zS%cs^l4{nnuFlj7pXI{#pECdfsVS2vw;oUD=g)}+(n%4uO1IxtYzIK?dRTVN;%riC zY*9JO2R#6!509J4x51AetJhK9V6|V%AyP?0v1xlN<=m%B;GM`Hc+4Hz3{5Z{V3C}` zBd*XOh}@{*!fUX&copn)P_yeHZ$K1BF_k{5es);tE7H7}*!i#H$zt%y@=8%}ZKW$W zi9@Pjli!kShQ2{&{fSz8R%bQt4Uc=^yDA|6T?PM3etyfnDPdKzQfw+%fz8(0HI z7)>0cWV3>(R-Zf54OC2v!CZ1*;_rmH%UM62>{1gV7@-|~LsU|?W$}Ue--ogY1)7mC z(WYK|xGWot_ZC0(Cn&vc_-4tw-<_8`QWI(|doripf`)QXL`5O*uCXcMO?S6)NVB8@ z-g;LKzOjrH{84I?boLGi_Gn2woilU&F#sST!NVUZDLAS6ldI}R(3c!~6kD-$*BF-luI=>!P;-%^^PelmpF3N7JBosrHkx~=FjNkx;RI6a=D*vESiwE6 zzbl5re!`)CC#DwzI@G_X*qYyw3A@WP6XCmEW3GXi(G*#0&DcX!VK}VN9|K;L6sb!cNC|U6W|GAR7_z)qBbS0a$zBP9+C$y{XOHEKl z-vj+0S5-vE^N#REUvbw8?yCOTN&3@)!!UMy8P*>}nB?&$p*E5r(sXExAHxzk*~fQ#LJTLHi{hvnU?hQ=DUVwusHW2aH@^@#83MC>w>tCcDgQ?8whF!HE0kCH zPkPtz)E};=d`7*eHBI<6JQF&hd7!1E>--_tM2LU&@Dqmw6$aJO(;+Nw33Im;9Eo%H zcJ81bdI5{=l2c{wvGHU4yiwe&}+&xRm2QTNg7mZoE627r!A}kv+xXo4=5gCj~AQjYkmT%Jr zsha)prnhC|e+{-gw4v;5E=8vj55ys2{XusIra|~*unk&4C?gb6;P29rFN7zx;CdTx z%Svsa!abg_yJS{-YOj)RaYXE8;3MMvn8&u;!m=+8$&JoXhI5g8Y=rJ7!76=QmtG7U zZyDe+izS1PmPQK;oP3MCpS1-vU0{faPtqBg8y_}@Duu8DySVSP1)`U;A&YGJO%u+V zGAu@6NBI^&W0TT2nzoSa^>#TH47RD%gb!-&UDA{8=kU;3$){_Q_{{xe18Nfz!OfY- zxXA;Tmrucsy5n2W*2>qH-IzDj=j4T0`j9w|B3mqQqFIH?$1zrVJHwSGixe=o9BIl2 zG;*zt#{w_(h4@r)mNSP&IPo2h&%VDBASqM+$Sm>=j?*)#a<{Nl_RwNsqoCLQEMpiq zT95eut6tqDealwA?fJxBI*2<*{TpDLF|Uji2Fa`z zcKhX~&qL~pGZn>Qf2|n&22l(S`bibUE5l-4ypDoE3F-T;~r2hBLg#j&&L?iYJ@G#4bwl`At<$FT>NTso61yt+pa@#k}XyvCx)f ze@iy>8d4>HKFk;PokNg=0Qoyh6)9b%zI zaAG!t{xWLam<0hpq3psrk8=AJ<>o|(U5j{IJB&0%?Wd2mj7HO?V~9h&U=7^!64l2M zfHl2F>YZ6*iUGUg>m~LgJW$Q!o5Fu6i;F{l+K4i@fS3E4ez#7|6~e1yIfZQic{HWy z@T>p*DXU3Ol!Cd^F9$Nuk|BLPUwGs@L(Dhb(_vOG`3F0%0F38j!=)KQrx33eo1c{@ zqYP3>(Z}Vb5YBPXtUP%>2_@{x?DS5sVk|6fZsuvLVd+dT|zqZ>WaE4qa zixfT*)0A(tbNkKR+L$mhk9-z|dj)qe29AmR;0gnWa5eL>#gV5X;v2}*w5-)mWAwEc z7az0Hv?VeRo4a44MR*)(;;w(wrF9fD9H-mrM`LaArF&TFx_OLe_h)EejYw<4r{nL_ zX$gw&o=v_szX`XB!Qb}TvwTk*u~yV|1(U(AAl`Zz73qZ=_CgkBwXkHp=%{L=lYZ6| za|s`@w@s@(ZWmVivM-y3rJ-~Q^Kx-kgfiH6kY8`GrW1M;8`rv^>t^N_GZU@GvFWRQ zp-2+@LLqL6*2}+i(S)aarOjWo1jZU~n0%M*4|CwTN(0k~a+I5H2kG!{#12DKCItTA zA?-1@+O=lV&`H@cai>H?T4@He6O0ZvaX_*{5a;D#E6ue$C2U$b2asQg(fC&LB5h9t zb?(9MSH39hm1%5|>)?i-<8?jZP|jqBrUinrCNsM#j+hF5{493(9A7C>Va{hk@b$ z{^%;PML!Z>K{Yq8obo!O67Zwnwt*D|^7%4_2Z?1AdwYPplrPd(pY^3s+c=!#y$YZw zOQcQi7nti4`c}EV7Xa#4BQk-u=tA|Q011HF?LIv~!tE_a0#-wZ__jn5i>#hx7KJ=Q zB>gRd3l-4rt#Lfu<4&WDn@-OOE&X_Tz`(Qc4a20oOc3;sr*LaIbPWy)tMcWQ+TzV$ zZrI(s(|x+WGD_09?m;5qJ*%ux0?}lExp={0w;M--=V@xJ9e0=?L3OCbfZLs(%|Ts` zN6nL#1xcn8#X+MDPIXlvffu)-)!WLs9|X*kdB;28eIwfXwu_Q*;}D3a)SrW0YOx+u z2%%vBSqg`@&aIRCIQw^Vb~{bb@d-&mb))=I!Bj?!d9Qz?;y7dDMs2dJ0Gohr?!;k_ zHiPT|upa-nr9Qwo3rx-xOZew{W>wyVg08lpJu?(+x+j;bBa@rzjvz;WLwXm@w(T*W zxPBd@z4y@gBUarmU&S8eJzyGi{04|a`MMKHbb)~pQ{S<_>PqaC`AA>;N~cw53--Q< z8~zX*n%IsML=Xqbo}PUd)3%I}%YC($D$G$L6&tvVC@yqI@k*bmG-NdCky7PdianZ@ zTzsS+qdiKKp<}}0zQTXA#_wg#yEdWIH*ZLRULWybTUL#UO8N2ZkJ?VzeZ9=_-ceAu zv#z%hv+YJ$jK;2xlMLfY6h81`P+ZzVVqC*6=ObRaC1<$p}=ATKl7`wQOtfXr5L{C)q1PCO^b$_Nkg3eD40dk zE~K<8<;mK79bJ~rZ^{Nmy+G|f@{Em$*Lcrw=(TzMlL_FFKX70pFXfw~XWF0AEG99>A%5@EY5C2#g< zP+DBla+d(8E?|MsIr!fw)antmV*(lE9B4{2Ut>A+`6=Mt__IX<&s5mx#| zjcQrQ0~<-uP#o!ELK@M_9C24Q0WTf2-N7dad)Cz1G(=JuO=&rN(Rh5g z1GKXtR*Fx{MseIRq|;)xkWz-;VEqF$Kz%_ObD6mA!AJ$Ev?C2D2p8*-N47Tz(qZ3s zi5|h<)K5GyJ>^A5^$$=`mZpmU;O8<8QwqzB7ASJtUcb^GpA~N}-8XuL2bx^<@$|}8 zEzcO70Kfm@AH#!5;6xIhm@;^1bnV_se>pPb1#?0z<^S1i8P^0~gj_v*N`;nj zS(@z7<$H<&jN!#IS!a*@0{zXl&A=QF4?{=l$fQULISsTs+2yf1+oHkF*htLbB^DI{5|C zzT9fq+Nx`U?4cJ<*^}J8*7D4J7=P8juqkH^`3ROo*#!Yq(jGz^;C^!38^0-=zs7_4 z;(UD@T67#r_UC*;pw@>F46P)r?rsKsZ(Ek1UR4e%crSPyUO8+HD>4gyI^Ik|F31eP#~b5Cs!V8@9n^J zv&7#O2PeFJoq(Jr6@~bv5(j(IYa|0B((|~F(TR?08kO(D40ndnI%6aVf?kwsJC3@ZYr+==#7*~OmECrH*$n9TB zt6oF-TnNPZY#81wCh)CRJqe3ax6ov(_;I8p%a-~+S9SBD=k^ER$UapDTXRLwI+L+J z5gEz$q_tAm!H$Z=Ttf9}25Gj4aLy0IG67XHe;a*ZYla^r<^>UmLOTqfontn&eWICh zZ{P!t*{M~*lk?Q8uvfBPgLt%58S-^NR%DK9+&?&|1yXC|Nm?QQ#M8OhXC*Tjsi%1B zHN71vS>Xcj_DkpsR@t><%(taPGu?`VA3Xv$^9!^Q^Ucy2@aZNhkrAER6%4@;2XWzB zZfJP|kz;UUi6K@7|F4@9M?~7USmU?;VlGzFl7(7(r99?rAM0UO2B`vxce5tQt+?=g zR%S+rI#_S61foUYud}UBZY{}QZ*qJRq<{q(c*2$y0WrUPfLM_5%?!(01O3;eJ*5k4 zU^Qx|s$@Eh?uO!s3fMh2UTtXSyE_uB-y?2pa-BOne}<%`zVi3i4dz#DsvKUIW3$cM z(&<&%{$_CXGIBu@6d=seIjLfZz~g-Y?B~i?G)x&Dm@`HHky2azm0lO=5G(G>O2f89 zuNORh^d_JgbuZibM2i5XlUPkmjg?rr1V+OsG@r=YA(8bHQ$5gi4V)V(e5fzcHv`b| zR;?Um&|+jeeM@8Mwo=)qNe=h|d`i)sS_15}ZPkKxjnsW@FPTtR#e!bk1eFEzBS4M9 zBy5Z@sTVQ~=-T1A@O%RZas4sDB>&7mb)66gNTR6hr}86)H3I~pHn(2=LOedjUG5C} zpC+{cvn2qrr{~>4>`>9ETIrlLf}DKC15YjeQ8r$&6H1$+V8p?Tuy~nTZ$4w7a*CnB zK~4zKwkPtnnttxBF`at((E8k>nmyPsI&#{12RKxH4Atl<0*~maaqdM}gpXemgTH#j zbf*$l?Voe)#NVX%=})8z%3@>!U1!#{<3e^*ZA@cZ$_qJoL&2Sr6(q~>-F?d0?ECNF&!bK+M_j|P5hsRd z3hyq)tH@62H~Ml0a~-*4C;#7RZlc#w- z0gVC*FVCJZl_Fi}VPJK9;9omFO?+M|J;{H3T$Rk}3o8W1Z5jbZ8eJ(lqu+5t{<0qm zQ`tjRCtoU)bmgLX(AiM#a!s>~AdyxbTGs!7$ruZ1d>V-2qXAd;fOf4zu$0EdfwXTB z(wg2@Yym_KZQr((7}mo5JuRDA!c3JDgxLS|)U$Ci)roTl0PS8=HLbPSWqcdwWa+cp z6bWM(E{842-Q!Ajl%XTq?WC*A-2fw6szWx&Asz=Eu@~Uvuofi=g;pT3?0{h|&m8BC zpw*owO{W!M^x&Ag9t&pB{=R7uoo1^e9yh+> z3LGS8heMz;wXs1Y|G&^Q`QAgR)jc6S7XoI%Djlx6p)Adx8CH$J7D;6ZP{nXC=crCS zANJ5DQ;5oZi*evLF74ryak(MRyYiB&ylLoI(WAiBAxmL>RDz_e0`lK+LHlasRn52W z3h+sJ2w?By2LY8wCv1laN&)gTMk?R)1OV)>hWZH%taB32G@Hfc4ntJmiiNbLb-l17 zOi5?8?Ox91=F#F0>b=ayiQ{lzaQ<2_TdK!D15VGyju|}-+cy8*{=zMO;O)J`_h}UEDRTUS8~R;qM(uxha=k*( zPl`;djdVp`FZE8!BHUZ2C@H`R`R`< zyN9pJBUT>4hrjKSe$`Pu6$Fzu^~|LUuDSRq6NEN=8fy8dS%zbFOOjl$n$4 zE5g2-4b_#Oc=6H5Zer^Tt*UVS+6Ji6WX`vPI&D4_abD!?5kdEAfJBM5`jryvD14cj z`Y18u+?GpQy2%kmFsXWD!Fk47nUaJ6l#W??}hQ`F-9HWzicT9ydS zZ*&a4!dwM>c-`-RDO^f_t-P=6YImmR?4ys^3V4wa-l=jeU=pbc$G?WJYW(8Eg8 z^1Y}f#xowv3`t1)$UFi1aU~xx>$nFhE`x8^*$)fc*`yvXHl^62sb~WI0gfOyfxf(X zXdV1-PnT$FBbw|i{zTO~y!;BIM-W31J~o*6vytUMeh-Mn{tZ*@?n@rGsmUez*WBZM#outt z?8C1>v8x_5-LF42!w$*zn5IM%0>LVZgTIZ_C6d&6>qE6_B9^g#l(0Os=)q2pD?waj)v)*InAy)!QmR>x;zxXpCy4 zYKCmeqk)hV0A_1VNIkj<2D3FbZi5T^E%5@!vT_C#O|6Ne&_~ghFbq+?h}(n5^tNc9 zqE@Dw$c&?XA2x}4w^5DaCPr~pji|?Q5TFPS&7$ersqJdKNTzLMmLiWW9i1o2qxz@nItE9&gD^;bvd@xA^Rn z@esu%&Qg<&46jK;fVBgJu4h_AQ_NNB!*#MGwM8odHYc3d--@{2Z(TQeHBX#ZzAtlV z)MxuWX<5qNsA_`VObn2zeKO6EbaOgqt2yqr{{49uKv4cYE(tP$cLw*UTTe@XW(7TV!%&C$iqs(OeyTi6G{8H3}Ug&7Co$Oh8% zkVuZv&}++g$BH%I^O~JAIDD(u-XC0Go}Jy8d!V2?ZfOv)Iww^UY;SkYbbhvdENA>z z=E6MXZksd0hW9_rix#T=3Kje=#mnLPn36p0c0(8y8MbUF^p=8BlMo_2T$opZ*S9mh z5H+-h1ILh*_{GB=@fz?^)YX{BJ>1kgE|{hpH907D%}>syL5+qAg~*I-RnA0)|Myb* zlNefxQNWd>gXMn_p&(ajJ@Qj=bJ4+{qJ2Y`La~u-9V!aSUJ(vritB25o&X!SqKX$> zI^!MRX+kyR#?dO$iOaQ&SF-=hJd+(7lyXxLg@{eQ5!PC1)j*uiRmA7dbJu6QSPz_*M)B^_T3{d8 z7g+|X$~hfH2%s(18KrQz=F*rGdk+AwCMzv)0@hoJha30daA0=+gF_%N;= zRP4%YWiWarx4c0Y;qzLK#k4sY(Jy`5J>I|*8A{hnE-l@2YE5g=qmKSaM%mp?+kk7z zJ1@STJu$C#u0?s}eZ_31;`k*N{%>FlOTs&yBBB?wwhT9*W4?MT1XGxyG#j|3=cBRE z8>Lc+6}?UbI>Uw~J-4$I)CD;DU}HLg@;q%VqoFav!rI2IYB;l>i{yLO*$gKwT3j%I zXJZxO=%+DgAPcGTi_Z(M0t3WKYBGo7f?RICe1xiYLQEmI-XfyANG@@W}Nn1|y#KA;ZA&Wq| z$(C^6rjEXF&81k|625Byi2N=F4;VY=uk6cd7?-^WNmZs;94YR2b)-F=AN0nojrmNT z=d+TB920-~d9r~tClw?&E%f)^?-CjYj?0fTh1WdL19J3lXnfw0#xHBRXe3=h!1o~= z#ghq++-W!ITXeHJfz~3L$YbL>ZV#2$lI3i~)C^Z#$h%frI0kQzAth8bu;d`w;^5wC zS7#OqvafL3PhW0cPJ!S|PxLR3vE*tGwqweE0Xckdp}s*=O&2`GcSM4eJ)!EIHGwQQoa&!-zes{?Z)|z z6ytVqVDYlRnsl?qt(U^qHy{V-u!3{q@cky*XQftr?9)@3(oN@r0nXnx2yEuF=jAGa zF^Qb`m7IyVVv!Q62*bm&=hjiinUb~!-#;8G8%8zf9ar(deq}|%q(F#LQ+x5a`*0XE z!&n&9YqQvrB|n%Z6gvpySq!v&-O#Hy68m7yAp@44*Q_@!!DX$=2|4wL1vS9OfsQw; zoYr6kT&*hYDP0Q!W$CeSZj`7Ql)3cPZcl@SWi$5|!7hy(;pK8k*6ThNzD+0$^LM2< zm{;T_g2aZhKjlP_T&rV`lj`UK_GDgTlDo!^zAielAUsE~!2n3$^XZ_3?~xyFgwPcx zumDp%{z8;Z`Mll@hvNn<@ZAjo@;@)7I_GV2N_f~OKX?rP+Q0*Oe(PmtVW3j99Nmj6 zva?35)v>*w935JT;;iiTFPkH|+N|V0TXqASR@~cVcEtB7e38f89qwehAy{>!tFHPN zPkX3Na1LMx_r2{f+Fl+4&90R8IqE2I+-jW$gFP|c3@A=HT*8c;(LR1mNu@tFsSw7B ztOx)wqnl&V!1dskZ@I*YOAOBdHcv022%~$P-OKR$*an|Jo5k}He6PTXN}92yxF)fs zL45zDL>*V;maJ*}6VV4uA-1IcO>Jz5HNN_1=5#s_u`GA_Yljib1;nMKx47mbmLF1Z zgp?*^77v}6vVzD*YX|9C0)@$<%r6qW*2l4$jaXuo|iwH<8GH!|_t z=Ds0A#)bnWj8+_j@nkR@u4I1*L0@RC$0!3g8P|2dIFR z+djDJ(cc5st@GcP-O-e%gk$(g=U4O1w_}|2K|rT>mn;U>A2!zmJ>r~F)wmban@N6m zBG8|-%fx&EwbM2?cc)+t1v=CS#oyuiOICZQw}E+MF+&SDvzL!6XZO=|XDJJQvo)RAgCXfyuJnI1ITFq`)=g=bN8DM0;2(=tKTO;uOl+Z2vNEGjM zGTS+zPSF!yAe*($9wXk#h&~XM(fuy_YbJA^=#jF{Gb|Eu6=<6PvT6wN5;ZK!>m8)=Np-d3BSS0+<+vXT< zu@RPl1rdcY!q&o7JFWmv%FXBJ*#mZeGv31O?K`0a^Hd7DQ5pTW(#H1K&SqoqAR^;$ z%1f>E4VxK`1p~e*0N=3zoC#xgu2#qKzhcxfxOARmVPuA7^m_&YJAi4YsA&FbLB8@C zEEZ%r3t2wNXNXSqv*=oh=QK+HY&*690GtEtMLuh@F4TPUWCyXw(C)`WgLKN73+yC4 zUh^$2bj0CJVdE@ezB#L2$g+?A#UJ$j-tB=?vm%NY#ZF9X!WgT+?M?S<5;HYn9Dyy` z)D1gwU}jUnjaRn*AmCoG+`O87YSwgy^Pc(r*63q|MVlwnsD)Mqr=|o561*Y@lU>$g z4dm`ig`x5mHkI9-BN|<~F11F{N^GY9xEflipj_yDV2aAp0b&OwlH|eO)R)B-b4m0e z!oU!NNCLb~$B&v?3_cXPTS^1=BaQU`*uG|Ow$FMDmhbLJmjcb*5PJ9 z781Gf%5jlUl^|X+l;Dk~>)e9Ln{8p2E1$f^B?m$~P|{q(JvsU8R3<^!mhBOb;qZJ98w2eQQ10zrcjf1 zJRZZ8Y7tN$aquCoT>a|3#MuuMW9BoNJUe=4{_lugX9ox%da0b_6}K~Gu8uz%st$8C zmt-g#WgZ1pfU29v7DP^cWbC1#xin0%4NThN!c#F4KLa;$hnMISBCpan`UKYeW@E?K z^hCM`V~zCWR4LeAK_7xaF$@QI?|@IIByD}ac+b59zGJGP11$WR@44vsNObRae5taq zhG;*YC^n)4kmt&hNerGbzjlw7_PD1njZ((Xn9Tz1Ue^mA-@LG;FZt@t)8QG;8ox+! z31V5j&nwM?=b46^^i=ss+vehg5te_BQ^b;Z184xZAM+Rs`aVyy3L1y~#9_dS2>5j# zo9%+8<|$o$Hy>;Z2f1>}BiH7?$n;Sl90GLff6t)jL#i6rL- z-}bZC8U`+xFiQCP+eFApXxX`n;qp|E94YkbeV++lIiLu^=PFGp$9eyTpKI2h4sl-y zZy(BACiQfyN(jkP3Fz(mL?-M2Fhw<(y_DKB(LCcW;sv|+A^Iw@dS>LxNS;_VxUIYi z_k&b=-Wa2)#VH}j?P39&084H%ApuBZNVjtNQ1YYFj&V;(Mr`j`W$x>LRMUAQswC)q znG$PB;rXu&3=qZeoQpyprUwNrEhGqFrC{~ zu#9?u-i?VF9`6}07@$VsTQ%&?ek}Tqeh?aGBH1hW-COki!w?H3&ZdVcaTsaX^<|(B z8JWl$GG>so6|>vjCb{w+Uss@S&cr`x$CFrRD(<*MZrs^%neEVc4-J~xx;~4sCX*}8MO?37!OGwG)4mN z!<&*$lHkR%js%j4D^hs;gu+-F`Os2q>%GEWg{?l^Qh{p1kb=md)wj$AWF9Qae^_^V ztM*-R)7XbAO^>`_SUx9U=bz+)Wej?2yAhU47!7z)75nGbe^Nd9W0LwdIz+IOfm?%? zHBnORaH5M3Cram2@|xsK+XXv{)M03ellKhg7zYJN(Kz-P{?g(~OCL>tODT)d|EJiF z-xC?Tn`A5CHrQ&(rP|ARAqb7sV32FF;1f>fh8EcEk1_tMWHlLF2lcpaP}pf*&3>R! zB7x?IP86b!)uJ^uH?t7zK<({8aErE(m4#?=Ot6hDA^wGGBVLA0j5RrrYU+Vm2#IT1 zO7945K@@tFb!prYG0;il{M$t`g4;M7Nno8c=Q~~Pp##m49o6H)hdXS}hixEktERIn zL)C3qZFl-mRhX&HEz7Me#TnZjK%H(42)Zd9BJViLTqq5AOgRfXhMt&pynE(xYVpP&aFb)iwBN@)Ocm| z5e8p0sUFDx-TzfT*CD4BG)F*De^O_85yBPu6>l}jK9pj+5bR+tXC z8f#j(6_yalqJRFsa{3Vt`*=Mk<+OVp*3DSwiU;s~o!qMB8^c{e(xd+wbnZ}(<)d11 zjhQ8Nu`jR8Z+j-5=7$n+_H!eMV`L)_C;Dz)scw-bi+V8z-d+FthvQWUp165EfmoK? zufi$nt!lp{XSgaB^3X#a@?t#T{PE}e->WaP?4=o=yDLYi&0c=n42qeGUjeG3O8UzQ zE^`EissyJ=)T$@N%|WsnI3wD|ulG4SDVsWkih1aoph`K`DOb*dLf(3tufnphB$7AV z5%1QjTcbW$k7J3~hh>NatkU^$U}E-6CuxW8{F+YnGCtx3PVyh)UmXLUSjObBBN=^r zd5^W?T}UArh(w6=y^|u%eTj#M$yJY>Mvob<6U(>gsyL5klm5O|cWf@$wDp}d13+Kd^1rP9r2i2J`M{DBiE&8;I`M@12 zoMVyO#`y;rE`zeF?LVI(Z#F==w{b!0+bK@~*)1`OZz`$ki9>l}7RE1RrVibjebRgC zb^l}Kcwcuc=iLTikY;P`>IRa8iVx;haQ*Q7-k)DrxP%0s&%cn1@&Npmzq|+Dk`b5Z zxM|RdC9G;wHZx5&7EGLKm4;VIY6;(r{#)?Yq&hXRZzbKrNqspV99OA zq!e5CI+{ihCC-uKQ^Nv~xK89p5}%#O0{OwNLCe-M6|WVEWMGc^sRuj5;CeJIK_c+h zB_{TD_^XHS-+50ez`w9MWS+ohMPjklFIs0w=S_9Pwlq;JXR(x_Ak zw$Hn+C^juO53BN!*;hLE!U2&IVncI$T6KGyn}`#AhMveR{BAYotQ3W*kg{CkL7l*ONw0+^!g%*&mgz}W_yGe zOd>46bx4dSNISZLghEKAH6}{$+#@wk+~K7YDFHEM10cH`QBxnB7x3Ftcpq4c4Qy~l z&pW-km8wF^D`-)ctrr_E!vT`Y<%2maAEgnFnvUJEwIS-fS#}5g!2a;)!sPvu_sPciSJ<=2;(AKxDgFs``DJ5R{XZtC0Zi+ob9^NN_czq$> z2bqt|6Z9w&Xyp@p=b-|ft?$HPEd}Mi=5;YD-G0WF%wQU8@F*&`c(clPA7+2yUYi8L zHj0q9nHorJu25pIXEL!~w-rqX2_U`HY#Z*YoHr*b*ixeSvkr`I7kMAX9d||DnFC(P zKY7q#MEy~3KzNj?4t&PoGCOvpLSJ4uV8U~R#TQ!k;9uXlplv%!VGj}*r#n|WP5E&z zD#^d3wkWl1fcc4uk<(YvkbN;{ORGP?_oB=1uFa{rcs%_&&iDhx9eq6^S=gQJcMo=eFSg$@++p_{GF>BU4x*i^Ad;_ zp8`)nhq4kzYnc;seFJC-C%jZdZi4-tc=BWr-gpfjf@TBGjhV9SLyHFr^OqGrVS1@? zQU_PK-IbV7d46f){1{b+0b-TSUxL;Y`^oL(PhR7O>i z{`T#;tSSQdhWrnoeW2*izvbaC#NLe3AUq?*+OypI_zN0n2UGD#-=~ClSK!mm7T*P>OjNU2T7C`2sf=RqaAvolK%)M4HpAr-_!<~xgK$YnA{5;T+NXMMQ z9xe-~0OD2+aSo3eZH>5=Tt&`T*mb>8@MdI;R`VtFj{)U>Lc$5`kzN4L)sDp6xuX+q zTK99ImC(b6k`YRiKpy**X{s`o@l&P@znv*^sqavy&uhqJpaU!D&%}fG?jU`)$vsJj zS{&rvZ*1eFVHSs7$GwduM*}<6+!z|dk!+6RLz-eE>KI!M6r#LQ^p2F3*T^-Xs`i*3 zw>ersjO|nN4!mi18pTrc-_6rq8zuY4!0Q)kjhNg#DjgFqT!GF*2L)W?#awsoC*hy) zR8p@06IRr_^pR+ba-h3#q4!ipaG0e=DUz_qgjz=&af0moTM3`t@hKa$sSI-TA^K>; zeZ+vIO0DUdRhbq(1kaPT=8TBL-t*A?w=2du_xZ`93c1}{Mo~jV`BICbOc~friS$86 zG=DRFu-R#v-*BNev!Gk&#C*c-pJ9*4F{;O!pS=B)D2AOEzv(u<3Cn>ZD|riOmC}$= z95wbIKs^g*_d!qvGi4C&Lk}uHaL;Y7Jd_7?X9q}nPl(yB|7p}XlX_ag*30sZ!%ry% zHhgQby*EWg@0SIQ{ZWM*N!}A<*hgpYH(!dBYx@%WNke$QQA1AL>}7)EN4Bkr#tbBB;<) zT~}IwCxq$Q8bH2(ja~?fhVkPOmt?DXn!sR!b$nPo%eG4E~JceA|so}Ezc+cv%QH&`AkRXfwof9vw zgyYr}c?DQ~Lsh#RZ|)AVzEYdmaBgIVV{RKo?G6Qw++mVv5b=1Uy4n5_P<}dUt!cn; z)y+gM`n%E{^*Iqza>2j~O4`E+hW*$MXzU5JIv{ek6H+-tPKW#a^I~g}sEAK~&(+*3Dl=*HDo^JtyP}|bQ=P@bJ10L$)E1H- zO;x#PidZib;tInezHzC5#*H$|S&yh!cnrlI`uIC`s+nk#|E7tqS>3n;V0#%kuLU04 z8m8vZ%HFWgX2m5k1-tSET&Db$Ss~kfnN}~sj)CQIWp$Hc$=O_UsV&Mccr<`&ADop7 zKjChwExEb@y6VuR`Oeni$XFKDzeToq)Y!5!@dFv*G)_3CqVH9X?rk&pg>c&At;#4n zGa`(Vru+QnJ$9_ov>4F1k)ZNE3u^>$fShr#A}cNBxM@gQyWlC z3Y*7%>&Undp)ez4QM^*?VQI}RyK6gD0DrmfG`oCp&IQzr#Uq*KhaGgh$PD%bOP`(Bu=ic( zZgz9KMZIQF4{?Lx%Df>q91O(Zr(gnEXHimi0)#$rbJC>|r7i)BNmXMa>q{E;yYpMoYM zSv|rlbBNDm!V2tYg=)ACi!+lLa#+B4jEO@1h)iUF`_Cvg{t)MM^{ix%$IJm1C)rqX(u%$nfqrq8=#4@Yg0t8uvo8~tTHfpUT$b-MkQ!TsMn@BKBp}O z42u5%N0@tZ9{Yq8jvV%Z3LnmcvS_N=E@nXG#sj}XJa$%uWrXX;J55t`Rmaz91FToy zcLGb4k9}TP*y@o{QTPxX_f%P;7ad(kl@sA+vp^5q9R;@v5QXg@1F4Verk^-!Y07!o z+$lko*Zft&DH2p?2I9*K{iCvem^@Xar=x!d{q*0N&bSNFMM+bG(yezOC$B*=mlT70 z(7;%uw`{O8g6TlWBFY2d8IgRPxj<%a}PeT!3kimPL8uo4{{Q@+CuDyWvnVLsuMEX+7_ z3!`}j9O7;UM!j0d?)xwpvuy|%qP>YELrbJ27z;^eV^sL9E9bG6R;+#x(y#tC!5R=K z$DYwdR6BThQwL#)DH+y1ED^(z(RVHPP%gDoe4oC83+;bB^k4P3a)67*=383p055 zNZ;Q{$!&xpe=QREaue4Tmrp`Q&zD)i)`=Zs-^jw6S9-2Z@3Ib$=U1Y8FY1A$Hvj=B z11mY8UEo-ncY^T)@q-vIe78nC%*ZsvZ*RZE)G371H%-#*7ZMvP z>H*jO2%!=AGl|Jn)$*2B#8nwocGL$HW~OFwFqmkp@`%V1(U+dNeSDL#0+vTrs70jm z9AVi;TkwICzn)j;dgDWr?s!&+tadIrpp$0UllpIm_x!-OMPF)NYT^i=2^sis$V`VP?Ozd5J}St| z0i&;W@ED#31ozjMJz&pfZHyvA?H2_j-2ahd^DAD8B35}yzd4H?r^j%Jot0fU)1NAX z3&FwkZq4FMpiA(xBa1HFJFfBbe$aQqR+(lPN}X!|eTAS9J>RFsvV^q)UKb_80bpkq z<3qPd4@dhoxk5F4zAp6tzmii?{pClOE>n$Il1oX2ikb*1jJ0%eCH7Jey_uEFAvL3g z)^Tb0T8_B&C?KDPY`**#o9_tllVcP-e^%yZ1hVaIluv=YzNmhlF==52s7)nbQ=IP) zLy>NXSc$1a!rTiX1*mHT?5~QwZ@WZgE&V`hy`1X9xsCjqu^T2iXsbDVnN${9OL2HS zvE5kuTJI6Iqu8!#jpf>UglBtksP695bLU*y+>QiWn5kXxd7M?C5$!B}3N{+rb%yGs zD-C16bm{u~<3VX6v6^K1G|4jF4(}DO$Ig@Q@Z$)vaXplUZyWKam394K~k)&d2*gCM#-r?PBj!a%6( zXxy$*iA0IoNa#T_ng}p4a=yQ2(t0j&MgNGa+XjnMAgAB=fiV>p>@zJUWiEo`hTP;J zw<#s86G!$O-Z_K)iQUz|V^kJUwKJLalexDhUiNSl<+619oR$^P4TBfb_!ROo79lq~ zWI+PJDBP#t0pIRiYzR0Q&c5kwBTQ1m{R^&RE_yrmlHE|^x#Z4L>p z$KCj_g1+Y22fT3*o^Z2t5n9}#c{Cg90ytk53)u6MLkc4C|AOb)M)2Jw|M~8FW**R) z^Ix8FN#718d@W?|689?oZ1|!zMo`x}@~KEqie=41LxQJA?Ly)x$>=t28-tkj>kYko7pvtym`sD7!Pw zzT3C327e;a2IS+83R!E+gV>wl!2mo%{f8Uc%S({xd){-1yFkseYLW4wl!~c#)r{8) z@To@F@6%W+L+wHkllH@2fzjX)hi1Tj!z>`5F|Fhb>fh+dT=rqNga>H+sztU2qAj09 z6_tHNl{>=Pu212r2km0U9K77N3x*T%RV^+afD`+MI65(n7zYX0-}=p466pQA_Lm$^ zl*S#KNs?9rC{(uHa8m;q95n)N-Plf@w+v{clS$g?+{LcHRb-+>xA2!nGsuJA0!Q-c z9*wj0dyAw@ICIcxD?wmYJuNe}ZlkOBN|02>7GiU8yQdy_`*-U?w8k=pfnEBe+rtc0 z6(Zf$xs%!_cW<7HENcPj?@+hS00XOS910ni(qEB#l4o&4twCTcN)YI4yf_$G82@&6 zYK7!MrGS~XWAroo=hG^5x~EF+_p})@hIzYus5|KzW$LgJ6_jvIIcLj3UOfboL4(4NDjy1w<|c@xxuV)BBTf&Ui5kV4^aWbn~i+9f{s| zJ>3Oa^Eo%Y>eqn?2`onPQb7d3HL?CMBovBQ{G6g zVDm2@O)I_c9dhz|&51%gUOrbuFYiZg{_{RVP}EcKL-1GyWpQeD4NH0h{WgnwIE~Zx z14R9oGA_j4D7F?tKk+VOsN)z)yF;&*viRjaf<#*)2+ zTAiBf`U)Na@fJ!emc2DeKTR!v!}A@-oK0mc$E#q?(|xX3#EMUc*7wHFjPm24#aeaG zcJsm3Fj>iSm?C{{P_}0O=8-_eY5iLU9UCq6H76(G+yk_NaId8okPF;XuTs(faolN; zO~~H0Oq^Fu5R>S@?%c7qHIsdj!j^3EpC7#tD0|xf!3KIs>oR7ZZZq!rxW7?PQY3GwxZV{r7T{Z+V=p~cIUNk%jKmS zb>pNyC{dlMR_8x8N{Ry7d$Q1jTw#$@09Qq|iVaF zJJg5s$%RsNQxG__Dk1{eT;UZm*bFI04U}24>SWX8`oZbW zb&m}5cxkts)~2~pRUcZq2YDFU4!8a>=pbAoJGv4B}l&ke;f*5jehOVRt4rQt7HjYMGLha zbYpEz9e2JwDO!!O3S~?>zu}59=KI>f|hjY&`@@o+kn2z3}{{UnR+UnZp z`a(rX*r|5{ZxJGPz`Ob*5Ynpad}^dGZlvhGT)-# z*Q;arnEbjF>y{hjGu0K7s+y1m=V6ZqiM{b8fRM#_!^!x8sDeU3iX}iKu;5IID?4U#+GzEsJTq{lMPjQGVs5?&^wJ=*mNiP1f;s{jSM#)$;dQ3V~kyZon~F;+*(t;v~uYhGBT~UJJgBA zFv*|0jD*I1{lvq72!FY#Wnvuvg=6qs^KU3S-t08&y?Pa2GwkxIrNh!4doa0eysH?C z_IM0|3fxE5B}gw6g<5J??Z3VuZ3I^@_O+ly^v63zo&pijXmBd%A0%5z8Olx0GNL|PRumPRiJIlcIpbd0QpIC zU@HP!QrG}z)#a}R6GispKYe%VCIut?NEGKgr=DU{u6_YrYau{lx zY52BUXa>GUoOkTUUL>R>Ha``%V@e!CV58c5W0U65VFVZy}(11TPJ-$tVzS z=M0M29nnZIk!THDeZlXDKTV_CRtp<=_gq5AY#vy@Wr53T-$TH?&SXNr6Gu}6q4)iS zhZmwAWIa)Y2*em5^|ULM?1xLZsVF*Gh+lA<5oyvXAC@Gca(Ea6wkn|Ca$odP+6cSl zIOKRKA9I65d-SS0B}ZzC9Q<&9w(-Gk*gb29;nbQ^UFLn%v3OX?#iX}J2oq-+f`&n_ z4&n`G8{mS708w*vv-OCLmW*_mE%pSB06YbC{E(=~kY4lk+QJBjzZ2Rm%3b7VrjT`r z#IT>BXp@sWCE*Tm)?ZUTv0ik8?BfWIW!-W?l+5<}H1NOx_K~b|+hdsv&A<<19e{hD z41L9-ZU6oZvRa#>&;BJ{>!>X1&~-=4~zbR98Wkbz?Gt*v1wO6dZtjX;R|&fa%SrJNY{vTNB=1Q`cL$X z&SFGlw{Q7EDRs?%c7Y13NB52gG+OEbs?3n!+>&L%-7%}aT})k6d(TGrl2%!=MAI{q z4BOEf{`Q?*&@n*j|YWb@;9=BRt-1mT7HvoMPg zQ#KL2ftYHMCwR2WwlK)$qy^<}_ zt#mRBMVe#~X43M;HFH-WD#bFq$2n-K;s^uIJGQx0Eo)G;FIg!a?owWzIVtB%*WJ!N zO6NhE7LeC-JYB|UejZL$u!^-&4_BY-Ud}I{ieM^Q9h&QeDoz$R!|EudXAtGW_8AM; zohS>xSS0Z@(tb<1krooK`CF8iD=?Gr?&&XB->E?FfvOZx0v@=*;vEKK!okeJrJ&v#%wnawZ<1~|g{98y z=8J-Bw%>k?+(#~2kF}{cOCK0ds2J6u0RGiSj0PjMfg@re*hWXPh--iu#;o`YYfk(v z2%TAj(av`w( zz`UwCGxo19rNV0_e8n z?qjyg;NFXaSJ_8E=cin-l$3w80})=O0`@!80rsz$pB84SFdo_AJT1ls^Mn9}Y_&a5N;B`70F;7QaP7g%dcWqFAq+jAG8 zO4qcVZ3nygj+Gm47Y#A3N`Vm26y4wCWj8aXsoan@%X)6a!l98AD7TwBwL?|*F5Uwq z?%z^goGxZSmjauwIh0)+C*oqpq_u2_>*rJUbv|0J`PI9oQ0(#hf7Q$x-JFy zvDG`Zw1o!knHFC6S4au1=npkDKsG<#Vg^t??7kWt*xKw!|76HV@3FG#vc?+6w;mwn zr4kZvY=z ztEh&=1=79hG*7VI0z9l1{q zsZipi!opXUiEz1hC9y!OLpQ4OPqgp5M+41M%@X2^jFrR1$IzI4}~*LlwXJqj&B|a`#|M}l*L12 z_1gpO*_=U}c$`32={LEh)Dz3mNmPmJIC2!Vutn1hCc{`!S;GYE(ks=3}BB*vo?a9XOUO+cX(OyCf2{DHkag(5pGsKiuD0 z8+h&#EX=WOXOrk?af6*suXUkwo zqbREC+W%SS@o86bR-)R>o7uuNC)C3X)Q#<}B~c*OxKwi8=`a}6EFw!x^x^9r0SPOB zTL;Ys{V*=#P^WC(XB8qwH~t= zgBi^$C%vUOSK|C2I%hlEb2%GRL51?^2brgA^*3^%o8sx_?f+y&Fq*ZW7Cm3RVZ?N( z9hW(flfCPgvC>R6f%}n|O9OtDmX^m$Sz8<}erXJ+q3D+=gWw#1A50n;bZ$n$RLKWE zk`RfDa+2qgUy?trCJLBz#pnm1ouj~{ifOlwX_*8aFIzZ#88oAkhm}wI;XGA*PL^fT zEl+A(@k~!{tllfjKfQM7_^tpm^W9E-04Rc8xqtpHbbntF+y5a6(0U`0+N!I4mROkg zrijbjc$OIZ)yfzY-8H?J0?T}Iz0?Y=hmeCLaorj z0_)qvMctr+h`DXYf{Nu3y=Mg9a`YS{B1TYcD|mD+(v!WXY#QIGqNl8mLu?TdMsmK_ zgDc_fjP>qK``6BCB<#v`fGe>d`0wRrjvzU>|M+-7XauYb7$*oGk*C^5t?i|S85pI7!$kp@32~Qe66t|g$*6@FC`G& z)^Or+j?77DdVQ9)8-gT&i@Ews&UaGC8WJH~^N{~j8m8Z<)caIJfF|~$l_D5T8o;*GJ4s{)y;NH zh(UgTGohFg)TDqmFG!y2GK~2F#oH%r0@2%5kF70FGOZN7>phIRdt%iEv5nIx#Z0E7 zU^f#sx(_jigze@(fGQpusr8B+yYO>5=Nz%ei%SyG8-q#^iqkjz>==oI(%4D+#0LT_ z+jBsQQY;1$2>56N0cKLb#7>OD3R2qgWkNa2Pt0@ACj&ul>qqll{$YNf)`I8gEwVF~ zpl1Yqs+TXJ8rCh=rOgH$N~ky??)FdxM(Y|J2q}lpX|9#IFB5T#$QTb6N)KzsNHnO1 zT9fPq)^{KCtmeqhJSjo=g4463Zf$yWDh{6Y1C4B~72^Q$=uZpi8bMs5IbG(HBS^P1 z%?oQj?*|~X?jcbwx)A#d`)NjLq!`Q$*`h{Wi@9AZw>CC|FxD+NzzM7{rQ{Up7d{GE zBQ`*M=GvN*GI!+g*w9BAmy;lmcWdn_Y-|df#_1IpqajcrecX<#X~T97GF}D0Dcu>| zMVsZIMdy@yqXxKD>*q%3VZZ$E$k0JL5mt7}1^)#^gONqk9RD`Jd@EFGNL4OnM;K_X zNcvP~sfK5g&_ybNm8uG_`m0xuHS`LFp7H0pR%B~i^ts_mN+)G3@kyxf!=@M-(Nplx zu4HM)71UJdzpga~UGUedxP83|&9B7fVGki^bwP13&i^|Q1MxDBba=M}I%0(mQFkP0 z<00}pIf0OQ)AM*_UEH@nAMGE%hN4ez_Z}(yT|P!1U%F5X zuB-tAKoJAwkG;*9K+EH$8QwtB;7&oZCN}>+;fkdbe=3m19dK=vj2;1}L*V{xCh-RP zP~3YCb~EXM0hSx%!WpWe$i)HOMNtrD?X?Qh=7oR2mLK?0%Uw1^{z=SLl?LqXnROMgDgx znT5j3S_3$AceGMJR@$rGAl@M?pBmISjLaQ(q`L#gIoz&7m?V8RiB;N7%G-5r*imb| zC(c4^Z71a4BE$vX0Bc!a7Z5XCrpz!SKZ_>2j%2e$lf;axg#EHlElo4W$$5)F{|XLE zv{Hrz)S3Z@a@)fV1-6EqC77D;$;XqdJvl2vFo)AHT%zSBkaT*#yX4B`ZZ=UOG??Mm zy*ecXT)nZz1jPFe0$CV)&YV*7vkgH+MqWmxE18L5K2IC|0z%nr*;GdRFlMBRCS!zX zQ3HDJ>fsmfI7q~-Qw&<#lu*^M9am+YY6lJDs*0D&kqEa_-;Va!-Fp)K)=2!5Qb1qi z6B(UH$i5C9kenZ%pZ;ve6E_2>n0`4_V{a^`Ddj294JQhE5b;xCJ&KIv`B=&TUW{f= z6Re{pCWfLvER-y>FSEce$S8RcxhX<6Po7qF%;lm=et)+Q=1kpw;Xkp_F4!n2(P!rw zVw|BGI|D(g>5YZLf(Cevd zO1VQ!H6~}(8-ngKf))qX6Irv^Xgsi-G|kjH-*fMh^AwbSYYDp-i+=NfpPM zNaTO^dOG21@t_61LGe@kg)RsJB%h#WzF6a2xPgWqD;$=S98Y8U1R{8eQtvUOExv9r z*{X7EGS03SVCCKRC2Vwk|ZIv?gc8CVZ#$ z0+9Y}_I&QUlqNpKt?-AAyP45wZ_7gUMmEW*YFJB23iKiXdklQKK&V2LYnWp!7?=N4 z;9{w)QYtyev{=r><^mf@!y7akv?k3Ot}wm`Q810xB#ilb=V{Xm=@cv&zc`wb0j9{A3kA~ey`e-DF6lN!RQfB4j2=v#rdIszEO4xE64;K}b+ ze+g|ot7&|JR}`DC^vcV{_ci(8qWRxk8{lZQt$ts$h4+RNCE{PjleyOWfcHzrx^IBa zwkwsf&CC0=IkRn-lP$^_U%x3cCrqqeeaL-xv(6h*sCP*#;^5lEFN6rMV4IKs2WCx% zbbc$t`DxQlByS{2gS&{BW2YVeMW2dU^rRT*`TaucL%d&*%9yUTBv6k74r(xJ+n26c z_N_C27pftgN6?(0<7cyV>`#C7WO58kbH!4wYaQC{tdhtUKcgG3Zk7w6on2rZLQ&;m zWnT>Y&-t&s9&_iPLutZRZ(OUS9~(V{P`=zq@9z&6&aQn{ELhgJV~v+1oW;HObO8q~ zDYqK_9pr(v82ZI}MG6Sjc_XAuc6P`&Ys{^8T~~J*gbL1oSpvOmv_P@s<*@=giSnnE z?NgnQ_I&9!=DBl~=xYHeP6S%jHsg$=ali7vn(4 zDNr_QhaiQg1BTyFouJ=(m2^HR8 z>uq>Gw7EIajmyyuWQN`p=mOH;(HD)S?va~SbuPR=3;m`rN9d3jI(k{UIEop_>m4#H z-d`Sw@_VPov|wd=8jHTKKAC-Hg%?I3I5~rUA6z{syYZ3Ubpd6Vedx#ltQ6FFf1huMw)w&%Uizf@;DYF=|@Cpnz!!mY$TTu4nM zP*9XqWqmd1IP#}{0Z+?PF`JYbcW55&w}j>K*MfLtghhaHz&|{UC@WLNwmkfr@;hJ- z_A3xI9Rq({#EWbDT%Dzaq5D}v$HhD7v?LKZ;rj4S^^WTTfUi}dpRJn9RzkV_lHI)P zjsNdaT028va%W5Xg+F}o>Tr@QRv;#+B!CuCm?k_=vw^3}9y>CnE$8;Y@IBZ;&RQ61 za8ry*gyX0Y)HI6ObK&VhjbYlBvH`avPVXf{S>MKdge=0v7al66TZM4pZd%j_`01ZU z%vrC&H8@EP!5Je|VgPxR1z^1LT+f#)9AD|ub6G&`f9({RDfEKrMfehSspP`^1@)Z) zQeo$N9FIFGKgSSha%(#N@0%j4$UQCyIOXI`J1!h1Pi+u<)2e^*Q$6=bZj54h42zw%eaBL54i4Xx%bDcsmuUxi;ZD-p^Kk$Pb}E^lz`nz}OV8o?-nHa>SU+ z^_W%I{!2H4xJdhciakghTMnnTa8KL|;SYwD>z7jD?Qsk!Zwg{Zdsd{Gj*HvC9^g)i zBjAVvPN7H|8nv8TQVv<;5|9&1I@}tGlAV%JZ)entT{xh;r1w<+aY0tH36W;DeTYw~ zM~+WYa)&j0R!B@+hr-oPEdDQWI>uQjbTbwQb>?fIe6eekkMZEE=`Jl7hZ+^|waY3% zMYPJf>p@j(vo)2V< zJu|4!N8XO%V&4My!lHsbJ}>TBUy4A+gT(K;E{ERlW`xeo#ti<^D|?-gNsmLne0It& z-Cu~Q%coI&pXSfyj`D_#uI2veHZ;$7 zp=&X?uiZhjJ7!4C&Jh3Pd<+0gj}^H%L&LyI@u%o=RedlQ#V}gr4JuG01ajd61~@q= z`jgH$cfE;(C;^EroVtL^K8^f&AK5x~!NJp#O@v(IQ|0S+Uk+#*Db+0lkF@DySTX6- zZ~T{4z|p)X7(Ewu%j@SqL8^#Dc|-3tD81G(XhF!hd}F{k<j-!4bS{mz>_gZTsyvXWXg_ZwE~~VEGY}C+En& z9dwvj4{skeiNLQL__4^GK|+jOQ$2Z|R=3SgmY?_aaA6(1Ice6#*n*g&-%+a7^OMWw z4&NNko{1_IaueElw^C61r((RRX6N3`T$)5c%A_o-)^|~M(_&!%8WI(*)N_rur9ehN zQ4t}5wKS`5Bh&L52c^rMG)H`Zg+@Gye610!*Qd0jvhHbq}TUO&<`~d z3W0m%*KZw)a!e*!Bd0VzMe0#q`2g+hR3cln3xP^&nNwVml`QKJyGcKzqEkYsg8#M@ z)Q}3vlL>%;Z_V@YAw1-F#5kPG-lI+FmtfDh_IoA>&hhdSCcdJ{MK?h~=E@D?J9}XB z7bo-?@_P;=nuN@;UW);`9~!Bf&;E{4eWK{|nQ%`Wv0k)-^^_@@JnO(Zw(pz}2%^LS zsb?V^{-%epRY1oj`s_}3R^cucYk|g#$96d$JkfhujpLwHFAZ8jc8%{x9z=a9|BM6w z$OTgMg_3x##j6d1&4^)Xhn;gVss6R97m|5sds+!iVL;n1AqT0mtU^7MdPTUSkDx- z+)XME`|+aaq9z7sko`Qoa#WE|_){?HE@bY|a=v4c=V2NCS4dU#)rF!G-@UPc<~NDq z0F<}G~iaFx#}Yb)v{+^DYed!Qim)iaIXVu=Uox+btAJ4$r{j~`!>xVL^H zCkM$e;Gau|2ggW`hEqx?!BG=j#F@kN!9yQ3UZuYSLS{)OAfy`|`mamCLEE-) zeB8$5*bA^xeFT*JozbEpUn-H1eAxBm>2M3ywJkAh-9V$9lh9AohNa}B7+nFQsFhFH zz@dMD)54{yh~oQ@7gY&mMa{%8ks(nH-YRw?*ob{ErME2}yOIh7UQ%BkP=ng@bmX~- zsnSAo``>e9)GL8t9GM7sgARE~U*0!mY`GI<;+1z0I@kSB#_mJbtFL$*El?66Ual!0 z08l|b0i|Z)#Zt*Q`v?&k%%$Pt&>G{p$rt|nR$7u+`W8OClB-n1W`Sp2iHMmTYlaD3 zEhkq*u^SvmhPG++12pj{6>^$4DHSoMdE&j+9Fwq;yKY;C`0$=#a&yh!ppMG3g5(YL z5F;a5YVh!0S0+yac6fu5*BzW~_;y!&QynWTS?TQ#1d*C6pNl@!`}3#@<0wcbP(`0w z1-mv(c{{&lJyarF$9~guCIJ-`jYhoM7&uklN^b$mvTTlQE0h3CVnjs?mwP99MRnIt zZ9tS8ptyfS$vJ;%FEz}5W$3D~X)u0oMd~t>-Ag9yd&GYB^NY`ki4A*yj;cWJ&bVV1^_B=4ix$cKzYrX_}X|64lqV zumo$rg>Fkzf~A+@dY~&gWq=?z5JQ@B=iZ@t z@iDm`A&>};6gjl@J(OSgj7qjZKQVpL@T!<#di;oTt_A5B zY_8k+z9WXf*>O^7fpaw`KiW1_?tgbTNgAT%xcg{#l5k)RmJ$>*^oH126(2tZ#wlOR z5j&&RA^b5}1#YU1gK1XJZ+ra@h9sc%ybaw^Q?|hinD9nc4lR7&*EmP!Daicw@wvAL z@wzxUz?gxhT!hnz$dz<%+E8p>#~Qkm}=A*XRRj1P9@HH z7(k;cTvRE@m7C`>9Xt2&uWmBzi8vr;uWm25C+j6GgV+tc@kvM(A2%k-N0J)P89WYs z|7#7-xQtwV4vccK22%{`KMjED1fXOo?{nNumc!%3zz1yFX#gXv`4}UMVi34gm>m@F zh=bP*7#EQkuI3uH2}pmLR~~jSEvG8I?K*Y-`iH&GQ*cTX#5zcKL@vGgs|B zChTNe=8cF#J|~0p1qGn^Ihs%JJ-akI#hsuuXDVrFrDK(4u|a2)N?{;A;jx> zHUYNAiqC(%Y51T8KWOBE%Q^ocn>1HJ1#u!ro0#c1$VRgsXHvFnb@uT@(_(xGI=HSG zYr^VR=>>)x#*a>kM-4^^m{lCCJ+lfRq6ZU+f_S#m98wD{C^b207#bDH>l=Rm7JxLr zBUM$fwBs^~d>LoImcekW2s6YLGy|j=VU1wKw+twL}9m+e95Q4_p5mQ%!|+Kp)}KbI802qyI&DxVS1Q{+B1n z>(cv-^}hejV&sQU$sqC(^x*!JO7YuULfVqjXyX%S0iIB5n);~K7H7`j$KL20trl~- zHCvE)D8|S@9No&9_>e=w-E^sHE|sSgoO+tMmveACIuRl1JfEQj)XOd-=kQTEUXiT# z7{16cnP=ww>1giy;SKjOUFp_he7fpuRPmTMn~IZ{^JO>*HtI7n-IQMdObGt$fjdcV zF9FDsC78Yu#g3CD=WcDK>r@lkKEcwFGJs>mT**L3hGT!}#h0&nn1@->_C-_Gb6x8S1`(Kc8ixi zKJ}K8o=DL=q!4G8dcEkEM6f5$i<8TX9WfcI)jwVeT(e~-kR%$S^Ai4q5wCE@j=6}qnBvM|RXVd=F%JSC545azi1TWfwIg&Ow0ry)b zSD|>%_81hI8tOgtLyaZdY)?fz$XFyj;4nLzfoCPzBdvgeRr!_r(+U7PK*YZclt2RH zGU~eY1)1PH;yd<=9?+1P*L>B9=h6(Tf#HnJ@(8Z9b^|ULdj_T+U!c!LD-;_#4Wklm z9NG8-+>#4?6#O0Inu)dIaw(T^A*Y)7siieD+f=%fv1hwO>PokB%xebT2O$U61dle0 zWm5A_yk$(mmDma70xD)TNpo=-et&ZwQmSq+og}CgpUJDa@I90zZmXt{=rY9-xaZV| zYp*G=I;aaG8jRRH@A4w1XxX7!zUHuCXu#0|4X0zOE>Ly~X$L}&Qy zaZ7R$j{CoaGLLQop$HM}4vy^J^F=djr+NNBJW+lK)4}v=a;D47tc&hcR<{vMqb1UR z{Pj2B{2e~GR1b|M*z>8r;O7X$UfCW2j&cXJ03kEPob-p)+s(q(lIEVTmC>x>5;yb) zNU4>AjjjR~Z!hjsRW)buBb4M_UmRAyh?ytXI!{k0RMW;aSM=io0F zPQnVP==3T zBA(vg95*n{5VHEeAbpwh1Ys%4Yvsj&8xuHZuo@~??-Ocskf0`>_LEP2_8iCsTB{(L zE_NG)VAMoMzo7Yi@D~V(5BLMLK<+%2ODLS81;ivSh@49YU(HD67R93YM@GH=g9x+s z)s6)#)mM?V;#ypG8`zkktPG9rl|h9g9SA1zy&K5m!lIn!71VUDp`amb@E@UT8B49X zpx^pH7zI!5zsfYV+IyzQf-RA-P{AB5a)tR<{Viyh zL|AEIzbQ=)o$L-MWWGO9?#q~?8x9Riur>fNt&^aey4afth=6Vq5A7&?NQd~%K+Jmz zEBd|%1#I%Feg;3hA=U(T7Lt{-QDNyEjBQjrbSGs;`)BiXx%DHP*^>O$OlPDzCya2r zfn+PciO8*1sDp2zrz~8!=(Y%LM1XW*`-gF(->=L;6t)b|*9CabGA)hD>A+Po$a$e* z(Ya6tBXol(=e~FDIIP^k_0K&BQGqXC^gbQ7KZ^{`!Ryvg_|OtUN$<&XO}gYQbB7`y z?k#izn8jUolxc26xq6Gv>Wl1YYoLI>+4B&tZoM86YsS^8_dUhtBUs8lme~^ahb#tK z@o>>p&|Go(4PbV4m~S-*dUu@j704A2%#HgBBD_?GaK9>Vn&V<& zH)8p$m4rGHN@=|Y5U4Pt%J1x1?Z z6}4=FY??AZ6di4jJGZw@EUN!lgQ5g_XnJbp(z#4H$FkcIA##yL$18;WpZ}~m{P5%Fi&tZB?)BY^j&d@ukZR~kCvIJ z4VSYCFMO=IT^#NSO#^Us3@K3vh2dL-LYGeyt>@ic^6~=F^uOX<4#>78GZuXwqwzOR z_YUuZl(5v6t?#bEr>8{49|_04GSS#j35~1EwK)RvBHzR@cH$&pNnt4TQ1Eg$7JAkj zt6DG!i4G>x%hw8JtRB<&B2n+?mXPFHh5X-DOSVxWdKY#y;iS1D9No~<9kDF zw=4y;H}q9>+WpeXE9*kwJY{*l8kkH`EeOm8g5BS<8abg@7+Mz{tH!mmlCpfqjcx- z{7aiulx^28L0)tCwmpsKE{{6n&szB#^2onN73~Vtt-st!F@5`%nplWA00F(7u`fyd z9#byks&Zi9tVqsz6xj0gy$Z%fd2hbJZgQmv3YcPD7kn+)~i9lPa)3E~Qw&1|W+n2-VV zEM$6zu-nHydaKm-l)21?;Mt(&*$NxJe24uTa4VXd=uG*|rDzAVv@8@_my`O{*JgB& z(a6mbj3yv9>nRtZBQ?w%&_7;h7%EF(5q7q`qneU61NvUy#Qa$hf?Q@L?e0|M)>;cB zY|3Ak?-h**xpgR)f7EZSD>GJoz<|D>2;mL@%ky<6SRlAt;g^;|v5fy}s?EJx*uZQh z{C~fjFOEcYfAA=Fqgb@zq(tBi>-^9Y^@j9Jv-iRPAcl$WMCnz>2S87}UsfZjvB@>O zk(KZTiG;oauxIS$($faX;$eS{sUPIK`5X1eF5WGH6+nz9t?JDTzclU-@k~=r?7ODp z>*EM^>2oWXOOg)P4e_!W49x9H4KV^Xg^IMH;cDqgtWf^LdBcuvQ^Fh*NRVRyFZ4!Y0e_7Emn2I0u{2it|6r>Oa#92#((GwHwp%1VunQxbM84q4I z7N3X4PpgF1&7knn6cxBO$X4;_FU1?K&a;_AKaUZrS;TrHZd)*q#+rQ}fjQm;Ev@qh zrp3gmhR1i4Jl8gxo_Ea-Z{px!9Twgf!#$l?W|b9Az@sO$nP+8Tf*(8E$b;6|;r z99hP`plsVqFcbr>#=%zgXhv3zR$N#K!VrRNWssR>ykr)r_tahoKF_R)fVce>wdvVMkzrD@=vfI=CK~Z$qBn?>PIOje%R^keGdZEPF<#OzM@1M<2dV0KX9tsi$~M&My5k8XLJ3@O(ZP6pG?iZcVn zhS63`zmTv2270sXT)MXL*9tht;NZUr+Ne+hf?}=bqXGPo#fMdi1`oI1+p!#-!lymk z?t%^}OgS90o(ezR3uBXNJDLvb<3F-FS7F_=o^_G+X4>d){JYz0_8<9o5i#%u!$ZOO zQgTWQJpnD07DE@dKxqNZ#TkTe!rQK}UUUK*jJB)FW!h^OAQji9`!BThfGL6ho4Oa9 zk}y0T^ME4kN2KNa=}{4?j|K(@13IE=Nx#gUTi@`dkIHdqhDomzcrHJy-+f>h5@eE~ zqC!p;@Wf6n>qgP|W0E6k13We4OFYtr8yN_mv|!pXVPv?~MsoPX(mAU8)BJu2+V_bg z{x>WALu;B|ml2m8^2F7D)f20ryLbKZm-W^0Mse=R^3tvLUL|GnaG(>{3H(}=4OSu? z<=Nsrp9i0{1HnMH>5o}b*=2zR1!iy_>E(Z6d8~xL-m$;@f7O$oD75LHd%gO6&VuDT z!8W70*f6M*oKf9ij+%zvu_KI+9QuoM3H${ zM#Di#JQ8npcDoQ!@Y#35Vef8#knFu0GlZT5)rf9{Vcl9~DBS&w!w_n*&@3r36F_a8HMQ-Y6??poGclg1lS|2Y&1zY_h_xz2%W&{BBSQnI8;=@MJr8;Hk%Q`pm zD`{_t0i(99D^ho0fc(m5xKg#7BP}Kn`tWeEjjuS{xwB@%FUIZcEeUv!Dy^)mP|y&8 zW00R;dUAh7Opf?-DZ2EQJP4;V@OLbvuqDM{OeIW-tKgoVyUAj#G~FBKB(eYf?H0K7qbp5&;jRBa`x8m5T(eqr!IK6dF#(Ix8J15QvCwn|?lH?9DJp3~Hjn z2QidHSO#$VSv(lDQ`HAu8j|0wqELg7zcy2sk=8grsuj3w5gAAY7d%^+L-6gDsu(hn z$b?|5_aOXNezwCqT>KX*&bl^>b{o&3dpF$1!L$Q7Sj$iyg@`NK^3^#`={K(b89icq z94Y##DdUm3q&gdn0VHp0B$$$U64kR^h8kw-5ks~tqtj1mn{fI9pZKMplyj9UFo~L$ zss4*fJDi_H5hi%wc0nJZLll-=ji1OC-WD)Q{nZCaXt=a~)SIyHe2b{CBLlQf8fLcA zLt9K!#5+TtJSvQ7H@NGX0oPYLig!H!s;QsKg#QEJM-VfLhF6;V#+i#DtG)W$yp9GlA= zM8g^SO+fh*3Hva|RSr{4dDWJ+g`FCg&&yfalI-oAKA?KO4&NsnHr-Wg-UeZF6mzXl z3X}ihGL5)D6v)c1tJ5ak%(PTBzm*-2K-3Wz0Ys=`ai_dube8nll_OFu%2PC_+cWBy z08rBMZb8>P-&&Ja34!9AMttB|DnJ{_f)3<#5C=6}OAUDav2VN#Y5y3SuqRN&YCJ$( zrWMMxyX8?5b|!1@iIOT|MEAuWyTZWbs$pkh*7OmhSzm(n%DV0R7Z!;JTU^%{N;v+0 z-!fh?(!W?`xO)gx@-&xetAKiOqD@z}MNNdS@RzpvTrcfIu+?q{xcnBj_EE(jXd;;% z$YA={7{psQ4U~DT75hKD2i$Q`-eSz4PlcU2b;Aww28p5M0I?E``)-TsX{T?mRsaCX zD}5s%VeIN9?UpQG8X-o%ecOK;O_^&3x1kxN-+0&lz%zbWMe2{~TxllgaSf8&^*)GM z22K8Gk3i>W7jvm*PO^j%rE<_kVi7z)5YW$TvmU)q z-(j1RQju;-Vdd%z+1YiNEOROAs^=p&ktEj#0ctZF6j@!Bbfph2b$qpShpqS9HwsCk zdvYg*n<)p4VZz(FUeuKCy*}Qzy2a1>bnEDa0ztCy4k6G3EnJX~lWMcuBHP2&J75Vr zo#4`MWxtJ{Z>1}?Y#?2RNv^qyN9pj;JnsO%v)&XFk3AZ(& z1H8x0DkCOFwoUBuDF3a<=x~%;mi`T!Hr~@g{CPPKv4Tn%@b2GwUd$Z{TLMdZ|hDpt`-AFIWS+YHEbM ze3Huuc{g+6+yux9-!2TFFYaz0uHr%I%2lfC%fn>~i%A&z)gO#;%KVpO++%P0|0Z(G4ev zkkQ%C6Eg8;$@y0PO;PA${tn=ysyZQfhjzsIO}+_R=>pQ}Z_GC>HWGJ8b(X2`9khQG zTuoeOe`;kpayr}W#S541iX&%46z|DlajFi1bUU&fy4OvsZ#yr$XkNXrL9$o9C4sb{ zPN9g;11I5>qhH_$WiWCU3E=sRYCd1$Ka!7zIGEfBg-2DPXK=U88Ja-R4V*;()M zZ@Maj%Cc-b>0>tVH>qJvt*Af@r9>1G^EEa0F6&Lo-M`p^qL>xNLh zSWUY^LEgF@wWRIoywDBI5wOl`hetNq+g9`nmCLfBHw(2Zq)3=p524is7&~DVeyvDy z`ioq7UGAM6g=f{Z^p;}Mbz9i&9;L`kqXP>3;{)Ryui|%qi?hyN+~>job`y-1-^nhz zr!y}tDi~+HKEZUCkxuAUL|a-z`EjaxRSufvcP$z8hmcW1A0H8!F2qik(Nr96XYpjm z#a?0HB8`BlojVgDQ1G20-gp9e*^4o9AA9`qgDYS()U}jDWRFI*ClkDpOMmZA0>7L@ z3Sr$vI;CQtp3Op5ybQ=i-UkS=>MvRY zC+)aJo@+g_AxekgEBm);0A6j?*V`Xd7-_OdpRHLTx?2-RY7+nEP(Nua8?i+Na;B>;}s=@CitZ4A1X${qj=IW1Dk6dY% z4y6E7@0bMpNY$&dT$0XunTYJu5$8S&$6BEVQH93Zwb!Y?zbbr2Ecm|nlxXiN4c)YG zT|MGu4?kNxEI^#Lw|+$_kY8Jp?CyIVdG)?UIwp39{h&eOP;9>J&CA|e*+1VkXfwf& z>`vSovoeO>Ij}UTrt+Ypi~bRt!E@iAVG_XBi))7m-!VA`SvR!ouxRIVz6<0Tu<(8c<032n zeQu$JQbt%UpOQ8hZ>&4du%`>ubDyT=`)Yb8Gimq5O-fK`w@!bmYCPJR_H(Ff?zl5J zXgmi@j7;pq#rshMIfF`WgS`rFYdu>tn)S1RV0Ha4{p`|)-tDZ_)1J!fNds=q$!W3O z(nwJ4TW95AGM|0(Zx$NjRkZ^<%2}hdKMhAGb0wZc_Ix>lKja+t1puQm(}i@)R!jWq z_YUM4z4HnGSM<`qTZ~`qR~Wj#To!}GU+NY81@6dSM-(uGY( z;dIt5j!`vuFS_R}!@O0Cs_LHp8+$^G82VvLspBZRl&&xOYyZjlk)3$tOE(Cb=@Clg zp2%41k8O`)0OL6_2MrZ~@?t_^xKy}W$CoWUSkPj(hZ63+M&yXi)=wCMWXCPZZEs>91K>r*pXj=#xP>qwN5T>i{wnmnrD^Porl#+-a|ZW^LiAM6%QSrTBr3JMCcBNikl zU?494MX<{`Qv|eQ`EdS4-%LIA78dbCi&T8PxB8cR8b8sQl%Oyja29*=c@%@?Cw(kB zZneP^=4NPZ6Y5(;r>`E`NOPy+e+t-~wK5zl(2Nh>rYd|mSoS{vy>thHF$Q=o90+^| z6#=YFIsnLCrF@CEdi1w>$3IYQR-&d+AIg;jaoKB| zYy4l_?*tq6-O7A5#@v-!a^i3YkfR-xywG)+`HfTMvUc<%-q<;$Dpvz1C3x!Rh;czh zF+X0CtbV}(=!GdR$qVr_H3Hz`_Vf}Mau5s? z`g10QmVe4sj#(QM0H#$@b*y+?Wg!?-RIys{TI2@+uu#$2__Q^?(!v^@~2Cfm5e`l1n##Q`3GBzaVQF)?kALkkwekBXvVerYD zwpPB=x~(R&Ch~rdHRhs650PobnH{HZqSL19EJdZ^Qq6uon99Vfu(fil z{=`73F)5@eu?8%FWVu!*MD3>k@nznMlPx@Mm+F=+DQ4qCQ=J@)-C7=~*?<$yt?nXs zq-sA^LQp#{8K@O0tAJu@d)bcpPRR94LWq zY#7Ou1nq>6*e7-mitC!pz^8zLA-JqSTG&GuV%9i0G~LbwBqeRxG@Gmy*x0UkqD)sU zYHbelIi^veur~5$K~4s%%cPZs;LC8Dxlnh1d^aS3_YfPp_Ho$fd~bLzhcz_^?QS*<@IelNa%p13wHr#&Na(%U1>Yn zjg3ZDDc=iwQBi64C^H9n*a0J>ZSAF+pIUYuHiI#lBO)?Dw6IJe@weLG4e+t6cmU`f z7M=P1mmIOPIdCoc;t_lNI($V~Z(q>-pkkW^QM`mrz>rTwhZp2S7RI?AoHXx^q3~%& z8o+Jz?w*}wWt45<1^TvMWOzKQ07dgu-y=@ZcyU_Sk`0i!{|uBP2$z1e8>D%}r0h zs8R`&aK+^m9N3iHzx$Ag;4@Yg=MdzbRF=8u`F*rPCjbWs3OTV2*=9AteDqV+gI+R% zj~tqhJ!#U%D`{+MwsBwnBI3)B3;9}eFQzIuD)%rej4taZ^qUZO zx%j10#rm#&gfq;N(9ge~Z*YdNA2K`lmGck(!QE;U)r$gs60nLoBElY=z@g0%=Q^7@ z=yo}8EyceOQr`0SM{4U(&>PHjkluiuzW5UqXwGtbeZ2DY)tIENhN-5OM~7Te|E;xQ zl&lb_$@!+&?DA;}2`(CsyQZ-G-PQOA+Fvk*e1LdMf9T%mMXA?n0M=wR!z#>jJ9z(q zb;`K$-0*3#zQ?OlKOl;6KxNnk;cPx_@Z;k$7XDFstTgg4?K4_A75bMvD(vq+;Eb5c zop<>!qoE19wD`fhc%|5sY7ikf+niQXw{VAjukfJxer3$ z@|jC|YhXM9PAp!WKgzIHL{-Da*#q-4dr4hz;rv`{^8T@1*8^Rr9%M8@H?=pN&%d&^ zD`)x!R5SlS`P@d$lO%PT3DArQI=24zd;Z)4y&u&f$dKGKDQ?uCKd)rm135xCInLp9 zuVDeW!uK4IU$Nyl^@H_>Elft+g_DNd7eVZ;^8Sr%P%hVPQa@Y{z5U4Psv0saOKc{W z)BIKTtKRCODEQ3QM&Ki(z$RT zF*JSx-aPjHZbLArP`iGXxcq~Y{r=;7P42OKWl8j1G#e&e*@EI4e%iH$`9^(ZlqP^A zkJEh_*@hI9SO4rz7waGvl`?92w_Z3?Cr3mCc#ZQ;`HDVQBO z3q8DuLq71$*&`jJ1k&+Lbc-70ApDnbiYlA$tORC(0~g5Y>$O?b zV`%htOt())V~?#w(GTvHUjI&3-J9yJb;>G`o!y!dI>mA9h8Fo)k=fwik`-LPHNX{r zB;4oi5=5?`m&}Iykg}xZWL)PhW*23mzX93UL^|&eNeXY`z60a!aiZ(3pa~Jq;FJm@-#Gv9~BS=Y# zIsz(5a)kXAe&a*pU{bP{k4mT7BERYF>x!0xbp^-u^+GShoy4<)73H)Ea}SD0D|XyX z$0Fpbr@Dylf(=ogypHa_2LK{-aE)+D4pF9dWNU4&X9_8L_Z~q5e#VZjKS9~f3Gh2C zn}?{$xxI{A^(GfXh4{9Lt2n~f04%rG!O^FU=Z|bW2+OUB>_U=XxmR1dpj`eo;()9z z*2a{y46vY$?h|~WY47{5hlgVTkb-oD7?ytbchBs=NFNWvU4Y${gG}<@qb-{Hq@1i& z!kC}IO)58D;A-X}2_FTd`XF1pGojwf=!Ca8s4u2K% z9y~aZX;v4?#P3K2eqY0i>aYNVulcsYw6(SBCZ0*&NoK=qBW-?@+<}lVT)Jy_mWbo& zrfnOsi^AaI-)3gl+%eXtsAE@;3lWQWe|htvS0l7K&qT$G&`}9aKotf`8hC02p%~z(OtjZyk4BXC|OED)F9lmG*JZXpl zw`>}vCA6oXMfxH=_G_+#QY$6qgeWBu5^g>6>|R--6C1)KCi&`ecN1b*TBFC%EN|Bs zi943yz<`b|se>w09!+py&}J>9xBQK6=6%k4AdUAyvT1%D3(zE^H-o5_NT5pU2$Mc@ zzlbz_*gu7lUZ(?tP2SO0g%Wbr?@lmwIu?xobY$t42~R6|^O?(S50(z}4y`W)HcivJ zQJZx(w8a!WWndY73iYzv+Q3ImATi6tTOd{T5u``p*nYQQm19VI+SYzWu3fxOOy4YJ z_Y;rrp$#pQoK3VgJq{^z#6H3l(0S=P_fAd~$42pcZl>!Avf{S_J+1z?4CJM90{T7Ul7D}wyYVYjz7MDl}3_WcGj>bL(-4w#h4`}DsuHM#;eXl|Qt z`s6{rhn$3Ih(WP>==%vs>_XcO@)^rcJ=4mm`r9B!ly(3)Q#~??Il>!^9nmac+?Kse zf6G~!=#&8nIhX~#XebGx>Ddt33txu$XngZQ57-6QgBGG+>wLD2Wi z>oS^@LW1|m%W!(~seV0I7B@n(Zvck4mx^xsxSiLy4d0fnzm8FjZs3$Q#b4j;$v!(t z?f1MBL`@d=@-AW)9L#?@)inhFbEX8VUZI%4;D~{%b{#!E?=%~uks*g}zFQSRcWj`+ zYK+G9S`YNGr>nvo4zSLni3$D#kAc`i=Md&(r1Mu1+@B2h8V>BVxNW_rGtgVk}^M6C0M) zSE|$o`yLO|+mZz{lDB$`TxGY@aJWjO+?e_gTga!|qe?T-_pj8tmZHES!2@M@gT0lD z@$zd?QRWXQZ0#q#k>rmpgjF1g-qJtc&6NyQwyuN%F3N_N1P10!UfFHOyTwmUfz*c; zay*$~9ip%)laNjn0Dg44ILjFinoY$R;=_WyjxQ!BKk|v1B=FSK6Bl6RIJXikdI+F2 zB7scEMjo)SASeeKvMNl3)$~X#q_lr@dz37#T`b8^+9*Y<(5b~9fvzV9iMujs{W!53 z0gl2*ZX%~1=Ugv01ulC&K7NUEVw@9B)2W`CHBa9il%}`UK|#FK*(>dft8Ze*SSf+`xvGc<9}Y1?8~R^t z3ai}?MP>X?A_E5qg+MXki6@y}IgD%Zr;OqRFqBKSuBq9bn56jkVM0#W0|m45>op1i zhxGebWCvj);J!4rL#^GsVhXhqaI}FqQbyj$-rjI4ve7EHiT4kH2(1ac_dvVJ{lOFk zcuK~EV_Cr8smun8>+&GpfO%J7;v{h`*~?jHheBLv$?M(|_c}7|%8uW4D3U-`7T)4{ zF8q@|p(@A5nJ*O>t`DSM`wjBcOi&8_}6kta#TNDD= zx8+2Z%6tKm(+@jI#OZk}z=1E4mGn0bjh&CkJ{2x!5L6AO&qD*1eHw1>qI-|O`BYG7 z^Go}_mbr9PS18(U9u!+aw9_VmG}UHJnWKw*)1s-XPM(gx(G0lbo@jHjM~KOnK^>Q- z#&!ZCLmtw+u^k6SR;p(xb|k9TyXlpKAQ1I>N+LmWbI`W92z4wv5mXX8$5Cqhvwz$s zfOWFusyL3a#N_pAUYxwt8|?2HI}ibRv$TKn!*My({xTFVJ@0scqskISL#FHzSX4f_ zmTbOrlSn005ZHpkmGtl~`?WT5`98Rj84LzNRy%F-zpFoPPE|V1NP_gbTwVr2F=Pr=j(wZwb3gcp=rTFQeD({A z<;UHI)yJl_(HzB^!g5F&v|2p%B$BC^R1CcG|6r}zI^Nuf$S)sQi6;b;C>yyzN*;%# z&L(S|`ilKWDtuJ?stw$-Gp;!wx5QKM?9iH0k-UgB`=EE5gOh4n{bGlIqbE~Zj16te zcWu2>EX=JuZLJZVTfCWI&H&%svVTU;>UlfOsOT6=VCc(M>AeJ4AuA#i70M0ykz!$x z!QwP3^%=uN5P~S=7PVVb<9VwSiQ0Dn>7}{15kdA3Yu?1~5iLZ}UUsPN@{7YkziWpe zId@QX1srtHHUqWUkC@WfP1s-xXP}rxM^YO0!`^10dFz70PuY8G+nG`@JGp5bV%#^2 zxH2*oU#M~Bma0UeOru+!a)smrV&u-?Ax_Xei!-(rfY%>((&Jxj{=eIz>>Qv_s#FKP zQsZN2q%4o_f7gfQ1R;T&OO`VzHUG8xK)5cDCw5MZI%3<2h9G z2GNk;j2?VR_V3L>>z)$K1(Sv6YIwWW4CIm;EP7)&hL#ZDcD4jU5Q^gy$u~~LGG8$O zJ*UI9RYnRdsR=Z1{J+YcEq{^&ME@?ZvYqZS`t+M;#4+SU_eMs9OmKsXn@z1SxsvIZ zoOOSm1$M)lhe8M|kpyQt#5Iq$%aO@gu5u+seeWG*QglQPpE8R<>r0JlaiXb1{yTA0J;j9PptGtm;)NHx-sPbiPL!H2;M2J4K2VR^TVfvM0&3 z+S~9t+}jsq{h)ahp!o*k*^20w>T8`ve6aiXf=?4h^F+oH(2Uj*avlAiqs7=9HyTK@ zeep+Toga3flp0fZem)hSiBuK;{N1zR^{1zshP8s803Q57oBXO&xLFmdT>{Qko4!wJO8#Pa^yBSo&QqYokLxFjz!0HM6zreyiX}eo_PBml z;fuq@q~Oz$E;*CqCOs2A!`L6+_u_SHowJ^9>jRXz7It-zL#>ZR13F;gJ42jz4~V`l z66icWSL-69_|kv?P5=ppbswdn*In`NSlO@?xCJ%H4}B7bi)??sgPIt0$BH$o7VSvR zz``+}9>y;O(o(YZZ3f+SEfRji<5CFBw=8(_z>+6{Id{bd*{3wm# zp}NY_H6a}k^oi#f!vSSP#g(^JzLPj*i*!o7wZ~-*eZ^0pj(G)}%iTkMTD7Fkd4mixO>T|B$H4oyY=_FncxDLfA z43ny4ZG)GS=rz-xd*ksfQ(s&y43(uc@esfFLMiYMu1M{5YfZ%tn}W60sOzWecb>|^ zi*IcJa6Ab9O{bxIF!&8yC}sHS-6%SPD;Di^EFw)enz$OXy753t_04Iz=0^G?vvChb|TdReyf=Ru53f+&eOeyjyZd~XPTWe z(b%qYI2~q6f4U1?HI{2cg?me1N8F>xIyv^>X32=A8kk8Q_YaqHw^eU^DU`jXJU;w+ zYf}T20IaL>?s!3Pdv})wy3c$YYB0PNg=N7n*q5z`LEfk-0JT(;rxB9^|#D8b)I;j0(^x#`s&FV}0 zo^}C2Nu<$z!3uZ{sadf%w0CngxIgX*og&RsYNXq?R7qwiEBF@-M$(c20_G`YV>CV+ zO6c`Q&BO%ojmG6M3SQCouDIqXb_vnQeakE^89~2{J2DmUMN*MciP4mcSD`y%!du%hDYGZBl*O()QevZ!Q zI9Z*CmPHpfMwm6>$XKwA3Q~~@&JZhon3@p2*`&r45*z`hVq!PJN*|9r5lf;yuloz) zcI@_~To~L9K0yV6ls5f=S|`}WAO^A)?L7Q<5ru3C)Vp!}2yry|Bt}^mr{L8JIo^jz zHrn^4i_^vOccvV)D5R#3MNk*Ri)HIxG6VA8?x;NE*LJ*h=Ca*5%4HYn=JwOj5L0!n zLU%eH(9_M={%~sdmDbFw0Fl;as12f5&S6gy1a?{Jx;TxOK4xDe0?BAuTNLwG!n0;| zrnJ3S+O$N7|6c%8$c!wl;9DWJF!akys*`A_F48>PZnvJxmEO|f%uWe9Fsm#q7;OxR z&61Vf=Pm=gBiH8uRTt6QU+3&T0d=O!F}k-TGv5izzJJ~4zh64Iz|Hf4Z+*JSB@cRb zCui%On1dgarP40{94x06uzCdXQn-Db8G*r_nTh<0*tZvBM;yBkPH-HO*u&iA~#NApF zYCl9UWt~>}Gx+0Z04<7sKbkrOJjuxyfzMr*#yhe7t}+1Q(L?pyDJBRaoA&jT)@)QR zul`q|DnVmhYzd))b!i3f&pX~8HGa1K8SSnUj)Jay#fnR(?4jcVMaW`%4JTdn7W{-5 zU%g3kwz2x#WFE?!$jqP{P$md^2H&+>S{wa8)8mXKwdbf;>TS|HUMetJr8?!MIeR0~R{g z$)#Q6#$7iK1)zGXNRRJj{EV<8l_97JO7(L8w@}A@7t9=u+}&pqLe9SH$St6{j*27@ zW{OZ{^vX`eOY@q;%MBsF7h&eAgc>2sKLuPBxjJcD6>s#%*WxZlCY6HNyC1sOR3ahU zRuZZ=(aJR){uKMbls$(%4bDM*K@n3T80@{>5Cd2d9@ONv1VH4?=E~0j+oH;!9Uu0~ zOhcCFm2|9`%a3INdrewVas{%o`6aW#d{P1L;{zySE4DsrmCxlQgc03KYW&rz0L^Wc zb-T?2fi#$hgHSwcZYO606Cz5H$Sll66(2Ni^@%9K5lsl3$%DWh5=O( zHPg6c)c@m!HJjE)rHG|(Q9y|f2IOjX>M?&1doE3{7LbukW=nH|*bM?jDqd3|GI0r5 z`~?Hxv*njga;jXRPfO-o_~?kTxZ(!3Mc{-~J|Gd`AYd>N_9{-eqSG%UjBefHP!;XZ zmO{)U`%<+OGa=?D8v$!u;6wH68%P3`c+5qL3?Wc(2tLr4*dTl#Au+O4prVnmK!sPc z>;!FCm&e7+St&;#^<9*lvO4x(UqQj}pSdozyu4Bo8PZzj%|PUa*8Lr1<1})^gzpPF zbmn&vL#q>3;?A!==lvMCQS?>EsoO_|2G)fUn~74Lb<4dRk2)bB7Jvh7ks?#M|UPyB`H;p?cSaQqh$5mqSP;oz@S-&j)Uhv#(+0SQ~ap19xzze<= z{uai{L<4=y(vE_LSA>VPmjTJu=_nO|{#p#7?y>Qm#ZrUO=tkIq(*r|(;6C5^C4e*j zN6=kfmLP(iuF&NyKe5@_hstbm6Hmr8+A@z8#~(gYqPk-Y2O9{%$yh-@!?KJnE{cCX zQIwa{_TpKDvrH!&O+NMl_^mp9hlx&NUC<=*ufjrJj|=?~r0Exx8gp>h{rZsW`7QPT z*~C5l5fv-3D#+k5tmt}>k>gbGhY4Xel{7|HDenhFKaI4H&dTu07L3m77u)@e1L!{v zBI))spe%ta3|6TAMro;<cEiW*yG!fuw}q{K^IaXgB}){=A(96u|1!mLg>We3R5pd z4nyV_zH`qKp)1!F0mFh|qm=Q(u+UTIp`CNtQf7H=%u7h4HQOoQw>H7g2~3^;I*}?dw=O^!BvyO!x0Ob zXFfGl7tr~uU-7j0n1;fs? zqyOtt?NJzO2wu19H#(y)7BR4jQ2iyVT_keAB{=|lB-5Wj@4xxuHeKbXs3dK?Sf+(< z?;n#Pi#qTD^1HW#TN782skT`9FS;>VeUd~cF5z%N(9UNbwMCF1N;~a6g*KgUEea^V zKC>u?8he0P!q;!k(nrF%sSN`5HYs4ji?SgZ+A{kgR6cr5{X7nW3;_Mlz?fO+Mi!buo}=BLMA`lDXDapeVZ(%={-kn%5~F!$af-_2 zveK+7Lw`WXc;A(H49LE*=Hb@438pOBOq)N!hteX42N{FtCBo0b5<&) z;J8LLvijqZ?3uY;Y`ebD1B4s?p;Iak&RgZEoB?`dg_Q&$iI?3*QKbC34%{$CCQ7Dt zp9FNOwa#me@Y$zXB6WNxP}28-3cEv{li`!YZbD+F&xn`pUaWU~T@QVlQ;qjN?q1kG z;HVe|KQIr)8G2ub6O0yN>txwbF1u~d3o@HkvP~an!cd?Rj~rr~w7z$AqIYTvdExVd zF8P4>E#*y34E}nCud2ld8CIxK2BX%7JEYab$tu}KoTpip6d0@r+AvO$AN7Fs-qImH z5@w7q#I`~t=+J=NmyoB_d(Z5kE@sQ@F;Hi^s#xRcn}YM|3SU)Wd@olFw11Zv=? zp&49}7tVppY&1HxI7MloN@%H;szD>ic5b-o+xsxz<<#+<6%wiUa#O4xagG4d{X>e? z(iC?k?wkNYK)%1gVhZgeWC7|<-5`$q;twgKn=`CQXk1r2qraGNr{)0_rIbORlBiu) z?BU;chGn?WWFdWD*~a4wE@NDwj8^K9nz)eUSJ4!9K}SVn{IL!J_`G}7aBw|*&f0I` zV7hu6K8PE`EiXV!V7ROzNPU&dezT_%*cCr7Y>F1RzC$N^)J(#e6SIMHj6FYp#yvCW zu>JmKVE7j&#QXJbl^>0K*|=KCok-X!a+!|{sWg|~>ejW-c=JG`u6l^gXnCm5@<^`q z>?TFM(7R^e;y}`B-!^M*TL61YTZVZ61Oq^cpAvMqukSPCQn}%GRz!z6`C0Zlyh_u* zt!{?2kj^MM5dm@XL2DiDRlEkI&0vav#GF13fk0U6+CQAoHmP~r%2^I z;{_#@$&P20PQ?xKpdjLv#zrqfd@-im*EJ-m*Rd0(c4ST76i9wrJCDF+Ya;K{6LZm4 z5iTWjbz6;{c$V1?2 zT&TH<+gL`)W~k@&0PNas_~DV@i0DFzd3c*uJ?3ZkmYq#P(v4&0Y%Mbn557!(UJHpz zkGHr$tjgyyhPO`M0a*ZfSI^-QZV`x_MQ+RCNR?fg;mbRe%a6hy_KC4r(C9$PME<}w zDTW86%CizU%{$VgcRdpJR=lI{%QmKEXn7|m^_*v9cZZFz{&{JC{o9P2s>6^(k9_%F z(_p2#yIa7$`e7$!Y`s$WIn_-+rU)JPS9{j0cVlDP=@V^t?)w0gLJr0v^85V(r6or+ z=?d`zM2k3emc@+?1O`I^B=XSuQxsd?61RznTXZ545ePvQe(X;jis#l_S8-IJj0&oc zH=Zny?_tHzAZ1yl)v{P#r#wVhV{@u9n z#JYJ4GJ~2bW+TH>L4kg^yY)UJZIOg?2)jV@G2&rcV5edTOovc2Rk{@0GIl#H#O$Q_(KHJJ5?NVcA+@%`GegBJ`8#!ff*KQZ%>!TpD$d7<`y;Wo?T}CI?vizKY8Zw?(w>XH zM5H~LQH|V%8~sYcR-wvxK~z!=ct1^{*+l3Ad7ft(&TGVNNJ7Uv&9p7u-7q?J-m?03 z6$H!nrKZ&tfO?b>d|21nEL0F60fUCJT9+@6JII<53FpLObQ#`9m+;fO^`_#h^FLC( zd1K(rN2|gNWO$w4w$4e6vU`;W9 zFZX()g0ggy8g?!c%bJKA*+nsMi+R`gsaUp1iNf8l0 zUiFJD8)w#wMJzEr4IMJ>$%B6vTC|T4^cPh;J}pHw4q5qOZhx+OXy*QJHCH5vXWJ%Nj0siSUCWG=k*`bgPP?X zS~m?@7>S|F)LuwiHIqi02BAcr=N-W__4w(#_W#f#g?n;Q+#`0s5Kx zi_u5NF1FHh-GOip69gfw0JoOn7ppFt9SJDA9ji&fK}t?Ld}zVU8Dl=HuH9ef{E*|2 z&ky>(eNT4RdJ^gWnj06^SvK%C8ha_uzDJgGpN{6;op;hgUr=3N3AgImMzz6w9smQ8 z397~DfneC6=3EvI4}l&>nLDoH>@S$#=ncjNMW*3E&|4?p7GfR9G(H`-Q8X2ao7hR z<(jfRoSZYz(b;lq0NbXj|CUOiGL%1lu{neom>(fG+_aT}p72T_QVs9_@ZXzfy=f+u`_s<$ceB?2K$>FN7W!k|{51~S zHk1<|4iTW+b0&{HgjwMPrZbmSR8s zT4v+=%XUh%1)4hA1|Q3H>lOd!X_>||2V`^D7=XO!kjZMQTe@-!IuN{ zvOp&F(t)fGl<_sFPCj-p3euBUi9~V1c*amobVlG7M_Ftj4GlQL(KWj(J$i;y%0Q@S z!Qsy1sp~dUj(k$5)FQ>rWLA1&h(pRu1I_sSJVGJV*nimh`Mhf1lFDG}DK1gU31U0b z?bu99z-PCF4baFdB%AbxVJFH=7(KzJB;%A1d)4atH3UsA(z1B|Eu1R)lSdKpHrN}E zQ8w&=6eSo?x;tGrjfo8kC%h)#p{B)JM`*wP3!47Y>ZubK0wV7cazI8-xd_yPpsJfi zAx-IFDL_&te^Yc#(9+|8%qZumIU#%9KT?s8d}*~Pm}F=q-zl7IB`$9hgC}@29u7Y= zv=AG&!SEDm3>s^#Kn4BXi4omX^868k<>n`BpOFLWM4LD*F8M|eO=Yqs*xPEo2m(Y@ zEO$pHmUt5XGN&rFdWl9|_Q1SE)*j`dG5%BN>gHvodWsc0jb^2B@!WDkEiZr$zi*l8 zy+k^#&y{syTU!Fk;zjO*Wuz|_fX!t#>Wc@dk)D1;hhbv{3MYc2=rbst>Q2Wp68A)7 zMBW&0yKlSX$rfw8y*;D2uOa=s>>-&NYOdLr2XY3(h zL3fZT-mcD%&IE097}~fgjYm(=!8|~Ed*4Gbq`k8)~Lc@QsnAy6jpt zN2hCZYbo`I*!_yplB8PVA+Gn>zF(%@l5rEGNGtM~cuUY98~oyOeEr$oLc>t)O?_iG z3meOR)F&v5t;GVMG8>tSxwSV2xXU$uiQq4@^f_s_zp$Adli6zAmg43dgfRwO@ zI`C|;Sf?q)MRGAj;g|#Nq-{=RhsD9~g^_y!{$zX&G?I-f4rJ>)Y3?Z_Qo6_i%H1*- zH~l7QtGye`0DDN@>iov;0~ZMig!N_<3a0pw|7D=rNqGwc>X||~Hkr=eck`No2Ij_$ z(cW?9(z;FrwvY^TsXBLx(&FP{sHD12aY{${6Fxf%cFWPT?aAIQRD&;R5Jx;B_#ISn7ob0egxMCj*}AxLt4l5s=sH68=w5xI+X8VDig{AWD7oB2JW`}**MMcY zPbbevjY_g*(;pJLBY*Z6^tgZOrIic>dQingMj9fgU}J=klB=K71YGCL%shJj7)JDk zH4mY_s&@$H4%Wx;ykZE468Ht88418*DcC!hblvUbmw`0nN?jx7roa~p5wS|-@pL;Q zcu~H3A6a{6-iTna1^su_vy?l&i!-Z|z;GWv3q1)viG2QALa#TV!Ep5~;Aj$9Llrx~e_OM!aHK zr{#upRGGuq1|(GB+g0cA$E|$HkVu@44jvu<;KG|Dc7kX4oH4ZSh`EDSsFHyDzu|7W zh1C1YZ`xeM+?DsPBp~|uuy6<;obP{}4x9$uk4H(h0*p$3Ryr`DxdV>u5%>7`S$4ZA z^=u@{OJn zAAL1so(*A<;lXue^Bh^oJ*72LZ&w7vPqcEDZe8R$3QGk5l$88<530&3nsoqa-O#EcW zt{QgLx?6)bTed*&MR?2A3gc~VmcL`eOHFv%#T^&(AO=vZ`A0UX-4xr%*B=H=K;ohY zOeHiT=1r7rXpVjz9c0Xe=%yN&~m)lVS+k*mlz#!%pWa`I!Sq+ zAmF*Phm-$6peYhG`sXj;PYX!I^wyFc7^Q#2Db8vdr;&&&I{`2RtZ)13Z_@g0^;0ACtKdsH8)R{D&5k`#p|)h zm7iP~KI+8L`AMlTDP1%-j`>=9>VHpI6~Ek06sY6Z{`O#jE1^N1~Rzk{wPn*F{I{ej|?zx8{> zwL3-Q+|4Wp0CSjSTdR1F#~Hz&9KejbMAqvBH6?Ezo zq$RB+rUmJh%M5+mi$PDL0hS1{oE>kjs!|lzgc#!O zrU`zi%mjc93kt#_O(G9r=U21gSs#Rrie1t!eg8CIa=6BfKY)H!9YXZYNcNro3;ib! zvCeWdio4ss-*H~J0Al)2R=3uxj*$<{Ln{2igH6_vyil&z|Fqs#ZexI@JkbZWQ1$M6 z4w&#aKL#k*^pcXZWSvxWP|G1SffY`UHC&`)1 zpVrNTJo_AUo84)rgD49bjtLRmLf7ggz=l+D9<|Sk9VV|t7dIgJ!h)Xf98fL&kBIO0 zz%Nz*IQtZ6NHlm5Y{U*T3%0!zY`=S8l+KtDQ0oB8cDvHB<6t+Y4jLQ?knm1^X2B9P?gM1H-$8c{@{5XoQd~yjy zG?|bM9@mgLJ_94`3(AafL<4rUXVnDoxc)##1&j{VRqYIab9VNlZNrP;-_H)1c2PAg z*2x-inyB9EFEGPsp+%gWYP{#d^(JciMp$v>S+D(8S^6?P`%+0?Oz9VPQH2%hR(z@x z^Y?G!Z+m_@#1$W_DN=aK9L_V7VJr_P_Da@g4s6OGCb?#$S^QM?r_Jbs)d}lHeMVm! zQQZLgA$*=a`zC3ewGIKlsmygr$vkxLIIF!x(6eNLh@ZDpMrL5byUM-CTEWdIa&Ah= z*^^iDu%0wOP^B%D4^xaZCb3@T8U*7emIDqqKJ|iWg%2HIIfHr{DQMeYHBB>T>&3dH}wkU8~Y~M}74K z#Zol8hr19cAS&^4pKE!_4Vg|4D1g$ka+nZChd7OcX|(BrAz~D~Jr$@8Un#<5QO&># zX~YNMhoKU)fB*+&n~56*0!j%=eL(o6<6a8=C#SZ^ow;udU^05yZ|A_EOO< ztezWhKy_MF1!sZ zuLDi##U2?g3o!sV3D38y)q#I>Y<|agyLGy?;4H=wO>6pYIk~w62F3};Kgi-3m-gmZ zRZJ!vG=Cwxk6Voz^B^C46g^ZH_M)#OI3_+pPyT))faJ9 z8*F8Bf7ImInh(UI620@lJCIK%m7vxu_2Y90_1qc9Xt&D5T4=v7phJEH?~Stxqaz90&N#tw5>>CzUWbFRDysp#v+s@=qtnuGTMviOrf zMmQF-qqp}QUaEUdw3WZOH0|aS{&+SluL5uoG22?@PlWSoBv*|b!IMZ(9yCOAwjVg* z^oSEM*oTv_e$(?QNtBDa0g^&}0h#$@T^K2oX5Z}rO(If_WXq>;dqmtUL5QszQx=Gf zZbk$bAAyHrCb52k{sO z+-KK1qe@a6e*>C61J(gjZI^2l=4jF5dsE+tFw8uA*eKU|a}fZB7g|lB3AmweXQ}`^ zGGH1_L_hjgxS==?cnmdUZCmEPXHBDF{rMlY-wsjDWP$rcsDI|W{lvN$qeOXwv(B57 zdtj#EXCt!;bMPSF0;xx`W=D)Jgttn1Py8*VqAcq=P*SfVGuIp>*u7e@n#9yrO+@Z? z`{E}c3Q+E61LaO$Qe0h0T*svCz^UxX$z|K*+DN!|Q|tx5p(!|ui7PWIGzP`HxP0+) zZ&Pt|tOOR=1%kdrR z@9#cbV3_%fyFRA zN9+ptlCmEcDF+9DCebA3$9#d5eZ}1iUSKG$!-|8KzdPQCD2%>HduGP_xSlPXswd(f;?K z&5E>BCyEw+DX5rQEve4UERA84u*)w8<*OdLyBfj**DuQvmK>Bh+-nUagbsL79MxKc zs~z*Ru5w)7d*HQp5gRmTA~AKu)B~MH{M^8Hs#|+y=}VxsCX?z00{?1GBQbCVBy=5H zGCTi>NSngthEO?|ZDHWGvtLwJ`aTk=|H zdX{zMtFCD;x+gu7`_gOahw%l*8kHk(pXLcR)Px2&;Nwv>%3HfsMWv~4B;+!RV6|`A zs}%^*9~OFvVt2eS3&CG!0!PV?p^`B@`vKo7ZfCJB#f5BC&|S5`YL>ge7EL(-SV2&J zgx=B7n}5#4E93*Y>z5dcb9cqJ&^Z<#W#e)u$gJG%-gE*nGs`sUfQIhn+VB;S1vUhS zAGbOnG_^Y|!MD$-v9wv=_B3KTaIB?IMX<}Kevp=5hxrzVLr6|l(+)p;0@-tf@9Q`I zF4k1xasqR!&ZM!TF8bReU$E;YrP4L=a$vR+^N2dU{4Ht$z49v-xc_!^X`a(SNIsq+ znkUqGxDvW;(JWGRp0q`{cg(Ai;xNKxq|%9Mgdecg1`S+K@urRKCml|p)5O5Dj{gX1!g0A+e>-@ z+K^mn?wDTA+Z{7ay`^R~2q!F*S<(;R^y9dN^VxG&9A{W{dIsqm)m&=zB3Xm19{ zi*8@C_>>(3s1PX;t~Mzqz0ihfej09_wJQ>vncM_(ejsplyt zRa=|mCeO6T57p$GMrtrZ4nZ+5>)^O~)2SQPSa1$Sc}WSjeXvmqN=4i;Y?IKL6GieG zm@5V6THe;wCndRl8~AyrDdO*u!|f(hS{xphHnc)W<~Id6VeA7w zSiLyV8!QP;ufd8PEutb>*KjiUq!ntv=eUOk@ks-EM>?=PWvycw4$jR-HI7bhj6skF z40DT$^xvOJ)KD=$F20{*hsMt37){)xg5EQn^tO~j8_e<1qQx@r4sDHaaOnM*|C}$A zrub=$T+`4jo(ou-!zk6Kip4@IoT-2kx35YxBerE4W6e3Ho**wV7l$*X>%RG=fZ(ji z=T2%#_=a6hLfAs@SI~7YPU0?3nq)p2qdbq?*I=K05 z2eS?y2#G=n2@_a~<)w$4b6%{YK^i0T+Wkx&r!BNTB1wCXG98%nox$v0<12{^*U6-N zDAg}PO`wb5sRAVuIIxa_x)|uDhKnZd^B`hEX{5Px`VZbi+KuulwRO}+UR1sEXB=3K z(S^OR(f+_sra~6GAT`DeJ$toWd|Vqz)3R-bBq_~^eV4fh_(6v-GeN|%^7$>`c(&Ps zAQIT5BYQ-d0%mxGEZrPF4dVNpHMOq9Fj@H&MPDEpoe&14SmR{L&Ln~s@(sIBuqK`6;g!xwtY*aILO zU^PFMW9>DNB>?2BGqUEdM@!nTv16P0Dq~uucwp)O&_eh;;4Mn)?=iM#e$J6(M{1RVS9Zh_s>SK!bKlWHDX;{Y;H1J6v3cIYwpBl(~ zvg~QKeczlojATdBLt@@yv~zD)b_i6Kb$X{QsH!3IsYqP~X|>>&wo;`ny_QY-9PL|`OV_U^(iqxT}k0%Rcg zxGDC;EmkKYppZtf*a4!_ypthpLx{%aopvTz{^?70ES4NZex5iGTX7!x=+Sjp=jsH? zOc1Yrz$*a!F`oVG$-xT>nUWH+lhQhS4pxiEY$jq`amYNM*^*-|k_F4J5hR#QUwy0w zSYoz5h*Uxe;ZoVV+aF6eVl2u+Gs>P*dy+!&Q2p8YS_1}PaaDY0mR^&i5TkU1A~UHP zeKFZ+13)-+BIgnIgZd5OgjXJbx23&ssqC9>i_M$$yQ7NEf7^XUsg_u2o5Th|9`*2p z8m$D|MzRSIH-ThyXsYeg@T$j~1H@A$WvOTTFzlmEtYQT@sN>O-5z8I$wl9LjwX2wM zo7rtV6o|oNBKYLB27-=Zr`7s4W`x8Vb~jT9ew};fY!pk#b=^SZW|#) zU}@^1Byg}A!&{%?o;*;T0Cj(eG=Y2(jPS4go%vL;HR(-(()o@UF?9Z$JpD8RAek+c zi-aX~I#gs`j0lu+q@>W8`<-C6Y9RmgY5<;YZEf&JZ9+$otU*z&mNEa%wFeq>lHBlQ zQH76Toc$snnK>!@Sg>JDTlt5!=yI&xVI=>(+SIWsjN-ea%!8Uf1s)v$%H%y#X_usR zjMO6RZyw8{63Lj28HYos+tH7D(*;MG5Ga3MHNv8^F(~WR;O=%$aCrwe-Xj;UP3Qb0 zKP{Ph-Z3UuOKNGLk)311X<-a*iW;p{n~`r2ktR&3v-1KgEZ6V0Ovjnpw#5OhqKqsB zEh_DK#iUREw_T^dm8GMS8cRS43bn9AI<*wMLz3;cw@Cm9%Z1aw!YvPujneb%trY6VrFaZq@`&TQ{=LG1#P3k$n-sUyzGx-(q8ilxJW>2ESg9 zYg23dI%uaXpgMZvA>UDMV}es6YX>gWK4ZU%DNb+yi_n)@X+ZQ%z83jpWlcYSR>gBs zK3(cijB!FMO{Cn0Dr~E=$WVDF^dE1y5`^5#`YWYeo`xbfkXjgx`UT*i8CFq*ZEZB8jDdT28j2-uif)T8Ep|M6+02BPUB@<$Ne1E$hM5zrs& z+?UVQXtv`fM%!U;4JME*K8n_<4CBC)1jGQWulLsAyLgT=j2+eCxb#A{>&0ht0Du`!jW?@Ui36+p68+m2Ft*;%^Z0yb~{dhuEg zynlEi$;G;J9am6@6(6iWHrT)yG=?1f8-CaxukuZ#%J%{t1RLY1lja zQ-OZkzhKm#LqP$6WkP%)fj}7ck<~UTrV(Vsr3}0_Fa-Go>8A6KHz_gab8c!|0|4(y zDrc!ilwXZxN2!N>A_{BLWN?GS64P?Fx~ST<)A8IoYaPxilV0-g_}z&Nvyx2`@)Am+ zxk(|fG8j-cPuCY8$rPli9HHT_^mEECY7if}dQLlkuICCNOIiT)lF%}27Znl9gt|DK zQ9V`7)>@FT^xn-PDKDNA_VJlO7}MbHH(u=O{&t;&ZHPk{ym4M;FbuEYpH+~e5#l`x zx#mtx5!;I>Zc%L59A?!eo3jbGT;yyo&E4ND%VF+Z z(5bl?b~ymQYF1^_)<-*z-oZF{3yqDGJhqbpZY~S(b=jX>wR)OCb3w1cp_gJ0=3O1y zV{C_rBBO9|A+E_Zja8-+PbiH`LC|3m`st8F^FMOkptD*eggzYwO zdoFJ7Br~?tHZTQ8#LB% zXtxjjbvGVn%7wJlyyyvtSc+E5ht+qRmF^rlVrnV@N(d6sOAYUKNsFKKlBd6YjDeNloPP=~n1O*Sk|46PNgOgHKHx8jMC15jAn+-9z}^-M^h=ppNOT=a6i3MrUsQXUz9e6Y@O?d*ErN; z+X9d{Poa%@vF08;#twVk@|Y>nQzSzxwY^R$J)d)-1HlI?urn-(~~f>o;LN(pK& zsY2J32kG5JZaEPe%ca%hO*~B~dkru`8n**}h40veoGh>2=w`c*Ss3vB9=Rc#+cOIp zco-)M`jQZkBA!+BXs1U#%V`t6;qx*M!-pIn+sUj590L9E@rMbwzn_!Br zQ2!o36j_1(0arjab?HUy7MLqJ#rMKZ>S-Dunb@}@X^l(i=dd8&VbIBizY2QV#DPM) z{3g}{(SPc&P(ATn7unUUOQ!2CxV3$5$e4{#9*J8zG@#@DCMbn63iymrgT~1@0=vst zOKQHQd079!+qL2uHdX_4ngTD)!$bXmVAE@b zCWygK5f?Z@Y}p{)kBBM|p4hQ`PiZ|7s+E+h6qDpHxwN4Wx~R;@iT?8axmM3x;7Cxr5z0KGO6i( z;X%NP(6tp?OlSe&^qOCc(~V7sP~+O1GV36ZdXJHLBwL5<2~l=!y2}5)C){$Xa{#C- zrceLZr`d9LQ?()-X6OC-K|dr_G(H2$&XLPpm7v%RtLt5;m!vH;0#mNx_r-f-yKmUmP^ckq&HY#1h!?7FG=_ABn1D@1RHW@2aMGeAe^V;Dg=inX zXjSwYp-BAwzh6|+%d1Hq#1w&{oWOLltb0<-P4LIR{RF^-A}-G9GWS30f=Ke7z~EGW zs1T9HT!Se;&dhA+?D@PCUiMiWXCv1782+(a^Gr&;!BUbn5E^~&{yMMtZ-qe(CEeJZ zZHadH>}IT9MC1q)rkD_e<#nu724pVTA~j2(1mz3!Hyx9Ulx~Q~z2JWU;>657BW!Nk z=?!5B@NQF<>lm|X4HE~Fmo|pFO@JplOz*#%((&UYp=1F)S1@uwV8{XmwWaUI zpjqs@hD^!9Ky8SDuZ+ra_CY`y%`S!=28J-hNp?Dv+*ny=*>!}L2yYopCWJ7aj zavs1Fw98H4_w~%?bVkn5%Eps7?m+~xIX0Ny4HE0H-!)3JSiEDmtZ?Zu3{jTDlijMp z;o1Tza`$wzO=^u?X$yvhz)kB{frf!}YIce=Ve0FA7-7Y>XZGB|2KQt0+$i;5F;LkyexixB&SqSMw1oxlud6;@zf{RXB*?g&RW!jr{3~5_ETgj* z5$@vsU&&|v2R#F=7oq@^ith>no5T<|e5$07J~cUYH*nLkL!Wy*3(YQoI4vuMBr0s! zgzxF;8rz8<7vAJTuazW)ADRj4?2Je_6)k`XF|hJg?zpW|IxH(SXm#oRv_y zx}HiPcJ^HuOmqS*Z_B$_Diz9BPW#Gmn=u7EzC~+b>*}hAll$tX|44?yZ@fgpyWuec z>L84JHz9U%{QvdCzrp}qVxmA-F?me|zq|M6Ej&R4N<^*)go?WoLj{oD-^JdP%3Kum zZOsJvBedVi#WJDY-We97voHYbFfzJv&gymu@n16L4Mbr3n`g<*F~Xxf4qUMHbQC>v%*}rt>R$1o5>wpDo@O&&ayg9ssc_6e^FSc z{XNg`anV5qts za(0~fX*|R^lVjpx`TVoD<|6(XeX-K% zQS^_=F*>|?tc6ibwI32yczAy(H7%CxMQFVC zCNjg8ep0Gd2`ki5U(w{K*!%^t7zaV`y7ys8BUA>aJq~T+sj{a&vKzG{`k8}+=5ykH zM7(MCPUF4(n!_6mgL+Xd%wQ)7Tkj9+(g z-`Ky~m7{WbQJD-^bsW+jPIa?#owX&pXG&41BaVYy2noGl1sKs>-% z3v=c*=)T*r^}W}XI-$ccc{|tXV6O@;jyF<3Yz2brO>!Lc&8@se5NyS0*Nb=GEaDOyy@RVvjBuLA*NL~mv!ZVj% ziZ@QP)u$2!be}EPG9%thEL!-@VXC|xz7fUW$haa8wXH7k#or@QeH39G^{19tB`pc| zeRCX6ZJ z%^)tcxd(+>dXJFs1)X!!Uv*Hc2kJY}wCx?uqP!&^0cJL|Lw!O(f;uBLZ>65eK|~L2 z9of;v;scTV93*We?Cn#QPXi@IZiITAR;2A3yn*=yT*Apt`wO(f#eaB?hGfk-&F>6a z*1c=6cCyyYq^Kik4GgzE8AQjPj%}$_w#BiuaB4rp zSpOz=)QnCdoR^d*t@GKeQW!M{Wph)q4*=r>Zc+~ITgtN`!{c-y{7IGDCtc8Z5Sg;c z19jjol`meu5oGBPLYG;5%ZE6WX_7UVH*uB2!4am7B38nQ-`fJHhep4v?1dZ)W<@f+ zOF@`t(A*VLU=yO5k~S>E{Mbx8$xIp`dxfo-S_J!X_GBDT`W6Zn8%XbtV_P#Y#Mr0d zScMDqvBxo^V>H_mC>O*JkmF1J#J-$mu1~-mc=ry-n&^(uZVupG4}-ShHSw zbQ6&MrG=HN^M;i1>geA#QU^dwkj?Nwy)t!# zo(>7F_qk@u{c{Avh`DgmXzV9ru4|pr#Qw*>W?x`}I$t*?4aqnkdkEUphO)m;uN7wgL^GDoS$~b3|%JGK>_T<)OIsr(y zG=$Co@jX`G8mw2%vt-LzzK*|MBrwE|Jrcv8b$*ZAq!O2125eAl)!?F|g{(&Ruj#IL z4d>OXy?TF@?S>Ocb{YaA+jot&VL6wt*@gy+3hnvZDrh!WJg{SKzK2ukNnKf|i#nnM z7#@A^M?QrPI8i8Qw3cvn-see~CvUZ27ei4&rO?zz9fUMF#HHi0)i=3trAJ6B!S=_5 z*wJY}-m;o_JL^K=2x4dLUoyHzm+KZ*)of^^#z(q% zJ_XwL(O8kx(z**M#W)#PljjkfTB8@gG1DOiIL03~K;J^n_FK_QyAlWg>SE#T<$jrb z&e!v{8YRG->R&F&phlC6pKP&>J2y+?)tYHHDw;dTh|Id%5pXn7zjHDm>yn+bP>p5= z20=LBk?Gm2z2ze|<{U~%L%OTkLcgDp;M^VXWdGA1r>16E^f&avuwNeR4;alal zB-86actulNW3wxM&ikRW7(O%JWA_-xgnCq{eAWVFBOnPBl|zC#45?vj8KWF z9PEG@U#bc8ytV{4lH*i*84fv->Y^tq3v}hk*%1CUYT}M|(oXqC4|{Clr-f5%p73Kj zLe;tT=J|}*U0BQB7SF54qkHQmBM{y;`f zARHT`Fz8z3)b)1-!7I1IGM@NQEipIQi+I;0x)$0knby17-p_^V)w%u+RNld0CCD1} zfuJKBX5hS~venDQoRm+A*Rw9F+iz|Fnpvez$h&hN|dxt#2au^WDA zn>B*XS7xXM#z@rYeL3C>N^EiB54KEoI-dw4I@6GYKxjK7)V`HJ#1vU{{AbA|+wAZIKD@dB^SYI%9RJ@g#P zGo zdbXMWqgp9pLRLq$5MgC(66*)4p;0=icfOpg!+_yHbuCJirJyXZ@^BV5=3l5zBO z;o-`$RZ%W3x8Io!Z`^wn6kdivBC7*(dm_hp=oR1Z*l{?74z_ zd}+*b5@A0znK>;3!%{HF_@?&|5<9fpi)8Diok#Zh%g zuMC!DwH2MG;qTg9@Af6^B>%J{MW=Mcur)M*=Z0@Q>Fn>R-eX zU}iEG(IM1S8|o|;@(|6Ab9QiWjHMPWzwC(o@8g@VI;)!}%hbKiY#WLn9sq~h_Y>f- z0zZC_aKkHo2u}Pm-<%3$gMbhPADDT+j;}4%$?y`~GfgPJ&N@U}c=k zwpgoujcJ2x#FA}F%9<}%LA%2p&Ci6O?86T4Z~IU{a1%oj;FlL(yLd)}{=?;Nu=xhI z6#K=FB(~mXcI(m_$;*HNTJoLweLuB;P-xv_>`FEaOF-kv)_>RF4{H2g7xOiI2t-_t zN3xZlMp0`;X>%^1uNiM@Bv_W=Sqr3&;W?w&nRvShknle!+-vMst)G@){BVNZUReFb ztUyc|PI3bz@@cScOgb<|$>+939IVA0UMxc12-ko9<8zis2VJk%kU?`UwtN6>3MEL4u<~C|`L8T0RdQ|kG_wp!@ zZzM(C_a^m*+doWEvN{ADUNbxNskOQFcSj8^MRtFqzlKB%rK#46Fo{|)CyeG;D_m+p z>>;LYM>#>~@I=q>)XD32@}&46)^jau=QY0^=C*V#*Z&+hb?_`4mU=lGu>Vq%yC=1D z4hROJ8MHpNpwR~d%o|J2r@7F)uWZEFt&Q5w1#x(Fi2Ri!QbzOESVfxfX?%HrBBX`8 zwTfqa3Okl-Ti}WJ7+}KY2k2oZ7bC1MhF$i=oC{eyL2o;FT@#I3B5D zW?^6r4dR1&-P!`!2P+)qv@5s=0S++H9WV^S^05?F$zYW6$gMlCkt0ABV{3DK-=VL$- zp&W=DD}Cx$YOfWjD>W>8$5}asHl!wQ1lgOkAc9IfSLo}v_LR_JfW}ld+9v1c0BcO8 z!s>|m>@o~-m#>K73`Wx933BKg{zz(**u9;EOe49XM|){(Lke=O1T*&9b(l{Ss(@#< zJDvGEM^cMWAUXS6IUVQMaalwOYI!Gs*FDBa> zjkTL^G0_<0kLCsMo}KLbhsOMTrLRP^e%B5%`i2kunQz^_7Ojt@sA6dJYIvl|R9xZh z7`wzO}31KhH zLWfvF_G>ei3*#m!5UX0me>vX0t$g1A92){Xp+m_y zxeE3tZ+EkI^iPr|1SR12CwWZaOiMQ*syVKjY#I#^X>f7f#cCPM^+#iln=q4H{tHy5 z8TK5Pu#UlG8`;*LOA7jeUefKkyZgU^Z9VZ4(RlxT#jJcq;k_jAAPd);;P6LuA}iam zi^$(9h{9{JUe1s>fh%d^SxV;I=K?rniyfIGc9RO8aMJn#xNq59+7q|!Cy2CIH17CU ziQnT~<^@=TL%kX@1Pul#vYXkYuZ>gS-`lUSkfVn=F>_P7^nqo0D)IA!2rgfI0+Zk? zX?ww$+4a^eb!wsV&j>0zX3(A@sEIY#!qssvsJx&>qu=N6YEf6Rc!)mA&qZ3R!u7+~ zAPNt*RVN6PF(T_FpvvF&tmd)LoS1t;tgU3tDy4iV;}KzV+$MrnDS%i_w7CzmuAG%W6$l2h zU3kDPV+blw6OWly3b&*qp5f}kpq8+uqF?ps$!#6o2mc^WE%bZxMWQ9F7*aYqtn{Fm z6$URwaCQSDQ|xaM=ES=1{mPwN9M`5M^8~|JpU@Z@we**d&OGB?uh1qLg4m>(#$Tlo z3|#3;a0oRkPMz%?u{@X*7KXsnkOv_{1EdDj?Xn>t4BS}gTa=vih+%Q73=>-U2i)LA zJ6TtAV7Wt4S^w!pN*9^{g2gRewGWjAJMw{-JKA76Tm04yhbHBCI@jIeIKNd-Ad15G zR_73@hw6RA0oKLMv9U0psRG^RI3rO8oDlNBU6Uc+EAzJ?wUM6@Qv9WvTvPlSE6dvl z{=r5;sP0WlVBszN$uq5>6aYQ3j;e1-gBh+f?xR%|T?I#yS(}5}Fx6(}((&-L>$7cT zlDzaO?4#x4x;?autxhJv51nq`*1zE%4M2$Rz}r*ikcHFGxBZltoPBv*dIA~Z)SWUiF;ypfiL$v`b(V^|IYnW)K1pXNIqsR z5{436=nk%$)R2kVk09-19zy?m~BWw9&H zF)oEa1k8+7L`FJv6ExXXq-JY1CsfxKg-Nwe?AWn(6PqolhQ=pP2HBeb!4Rg&-1iN;%CFtJk&Q!#3 z4|q|1>4@WVUKmAN_sSK<8N+n{llPo9|oG zw32^Zcm~;G)w6Lq#2Kt~X@XXjga$~mns#8DCJc~~Trv*-y$Tv?3L?Fk+Bfd~*p8eo z=lHtyP36=l$2loN)%ku2pu&$m&Zg;Z+x%EAa#5PYL9CDb%iU)kltQvg29K?v;3SHh zm^*Q&`w97ViHl+KK|Pwj4--8PbTZ;ls%BN_U5Phl z%pWfbJQS$|t7|2WHP)LNG3`F<9Z5~shQ9L4y zM3GLTQ@`e~1RH`nSa{gp!)U6rNNfqgtf*y+4Jb>DZ8?(wW^QobEzfsjRRI zU`|S6tqZ7%3rtd6?aN&!)LL@|tBnP)mC+4@z-)8}*jJMF0e#q{OZ9vll*3A3hytmxaCR1o4BN~iLHH~Z@s+CIv zya!U77K~$Di*`&KwO}h0Ds(ZDCpxStk)vE|Nsl~YWkFQjtqE-RZvQP4%hZN68=T{Y zH$a<-r$ETv6kJ%5)=c%z0*%I>wp|!faUrx5Bjz%MJ`M0bIsboK9Q%!Tg;eC2-Mmb5 zhy)UN zvoQ7Ar##vyF9OXPtQ$@+E;$?`t7M?mRhin;GCqGb^e+PoT5-ECS4Q08*Dfq@ddL`x z;!jwx!UsC-3f8#wkzOAJF4(Bi-gqUQ(I>7@;7ivzjY3AEHD z%2mBQXwJs@w!2QLU-KcSE@T>8Afj_mZN#E4r=FbD3?6d-b3S=QdyAz1`>}N3`WmOk z#gL6*;M8a>7S&_GEKM8~r4Jjd)3$pmwb`FHyO~mJb9{FcQCm)I#DV?$5_8UiJmh>R zzS6+O>&ZI1ntQKxy~NC!EYLYi_PC!%RDtD&{c{rT>-+V(HEoTqSISi7b=5>G5{&yYotJ&G;JZKfynH_vMj9}+OCWltbevH?Ddm`OFUiIz@e^V5dGzcC zgZq_)){tN|^k%dHL0z^cWXF?4Vi7-jJinTA2CX?XQsOs)n}zQ9Om^ndgj1=x{R%hn zM1WN`Sl8>vJn;aTMKgVB1Wjq~0cJSdChZ=xd+8J_hDpUh^A4Q9?FKYh&E4WKQ4 zPu&B%2hd|7}+o>{qnn+>1&79rV+q^lJ&)bj?=5o75?`e!U1j(=XKmp5FNRfw8 zUmIGGRa&@vjeAp*drP;i`ZS)XptHJ~v`2eYw&8lToHfJ}#aahk#5A@60-vp$xf(5{DNGLyBdE z#~J0~cyv{Ye46j4!TKJ*=Q>NGNF#Dc=7wIMy-g*o7RbRWPfK#}x)TZqpAgO;tQkBD zt)ixw+?$WDkx@f=+FIz{519dgi8fk4(8MYDpS^jChK=KAjRHCGRN*@v_1^HLipg6a zU0ZY}Si_v0FX^GWMTNYwH1>+a@j#XaY&zi@~|P7RMt``tSn-0%*F64C}2drJa@8m`Nv*X1^;zo`wam_X;i5 zc3_wSJ3m^^@*P8i;a-QV(Pk&dMbj0fOe>?RY=Gd2L;i{#qr zwrd$8mI+mo#}{+=byBAX*Fzf56j{hbQ=wtxKOA1qbD$mK&bK*j(|YwgY@bil7k?~K zt;nVG>M`oLA@x=WKTj)eC4nt412Y6aQj$ZOYXZ`c%3~b~#X-s*5;Dp@TPr&bb@pIp z#z3f+DNY<$IcwdnG=pWK0_uH22&_ zOUgnOt~pon*rUp$A?>JA1Z^!nL`**f8pqQbld@h=nxM}#ihOyKawN)Nvl&{*+OCjJ zcS!AN#JmMuHLCx$b8!*G3XOWb?HrvIbSW8>e(;HS#`-zfun#Vfp`!v?13EO&9-MF; zBVhEf`FdW?D22si&ep}Y)itVP zbGu#JbtzyJ69?EcD`yX62=(Ski>Fb$g8I8Bh%8fh#nE zPy1?lbc0lFvE`sH=Q}>~mqk~^xnMl4 z9lN>`=28~FK@xHLpUs{Zu+NIaa;C>h2EMZ~1D0z7Nz-fzw&Z0`ir&*fK9@**{W(B( ziG(61l{!oW)h!*enc2?7a<}_Krx>*>w|Y4y36#9RM{J(bv(Wnl@}GISS%5ce2%pF_`;aL_2a1c! z7LY)}AIslY5dO2BChmFp&7zDadZZ5T87gJz&ydr5+a4Yk9pwjtxHMikH)7pRPV=*6 zVcNA%R<#Slwv%xNtAiU$tERR+lJvyk)>AMwcJB@o#FeB-Ds>I+i`4ysytsm?sHk(z zTe54J%1lK}1JUPyLkN;g04wet7`~Jmj6=@K)0%|5UHvOrU4zgg|lV}*^c75=wNQVpll~5N43W5G* z473cwfngylPtHxH&~AMQq32hs<Nn&L=Spb|s8{w9BP> zwUTC=wWd!;+!Ww9P06LDQ}1lLsAIU>LT@H$l$ebom9RJQ`J8|Xs^$M8{V`wHv?S14(@Blt(V@Tf8FWM`1cyHu~gJ@nmDIcjpi zd-uM){+@{fzVLD@+MT|d3DFn*&x?rSHT+G+D5wTme0=*_>Sm;Lpb`r#>!4)Geq_ncS25C2yVvpoX7%vTD;EA*z6sgXSMUv1xr>yiH_$Uu zLCsTAU7uY3`mV#I3;l0 zH&uK}@68woqpr=i_so9)T7c*Xcq-W4kk8R&?~4o;4^JrO+8N3JI(0FM0w9W_6S<-B zaq9!1psWtoM7o%NE>$+D$=x%Qzr`F}N|rrT!;yID;Dt z*qKa!r~pHGsGdQhDLCTyy9U4roSiKH7>?=V$wcWKlQ~?$D4cmqtniIVjNl0CjPg2acd_uZJxbI8@ znac)WcKy>%5NEX38*lNaPJlOdby36Yh2D}G2?)=7Bw9~n7+;gt9UP;9^xokl$cDuY zDZ3KZ?OsTLNjwQIc-cAJ)bCV!(qO`r5z;_MoLwu4)rV00jUXCgI={MaHHBnN#>=Kux1#sBit(~9Ixrw!urY5@kYvsK zLkLd*@=t0;k;uXS1I>8fT=6_6wk;R2xbwe{qw(T0loP=mXeon5U)ubgFri+dhGoKB zK_Am-&`rc!NMdjOvP6>JIAugGyN2Y*t8usUC|@a+3LJlcCA%zmh&07K1>sNz+BgVk zMwNdHs5uA-wH#+URHjyueWEDTc+}}8ybra{XS79Whf+4bg0CHXkJhiN7nl$->oBhz zMz(Vn1d&!_Bjcif4XhJ(XHy5@seqCQbx7@-UeviEEJ3zbmQ31W1cX|s8XayZnO zdki^5Ux5H&4Gi0a8VMC~;s8&M_ZgVK7fKnUI{ZG?4q~e`V+xmu0H%L@m&F@HL1SMh zAFgrXJ125Rua1iCUlZ?sT*xYVJ8wi$k7gtdBO}N(fJxU(iZeNr4x``gd&4DfB1x}_ zvA-^N3FXg0L(dYk;MFX5*LKg5;50dc|Jb#ANQr?j(8t!NuijfL&$P9ebGky6lsRQCaL298CE;izRS=>_^L^JPwIX>G3BrTz^wkuHo1%I5d1{&CwOV zxYg$4)Lj|fbluhM_&#-^XclL5@T-Mqtm9rlDGUhr`q3(i0vw)~4CL@{pC?pwgWSZO zMy23(s=EqK2U^UX&1Q(_y1D z0+Oo!BD<5L9zB=JrexW*0EAETkz$$5&tXY)K$v(4R7;*p(ii1V)@QQl@Y^Y*BC#Un zV2H2wIj^VR%F85))h9L5WP)Ec6fWa7a7g4vi$k^6Wc@pWpE&Q;t}3Jfsio;PvOiSt{463WQwnF`Df=BMlgmWydIPlE27-`TNm27+3q|Q6R;# zlfHyX9SPI>^_Da1nsPede<_ho-dydU_mo!i&u$O<6OFirOcn?S&+||p>k7N*rVyJbN5jSZ@~M=Fg2KNye1%h%zj7rK@2+wI7bhF!36JvgFM%d+0HwtPkY zAB{TN(f&WZ$_}nxTnmj4A)) zbW#J|j__8C;WNaGF8P2kY3^8GXZ$@&Hz-NDMeqWOi%}_>N>HOZra}Mv#IosM zcCGl%8sQr*NbF+a>>d90l=M>H9Z=QNTXt8=4n?8= zco?lyp;SrmLdw2B_B4YWK-nx5-@?UG&Kc}!O7?(nD%_))7h1TMSZ0LZnL|Cn>^${c zl+a&~ZnYhhy*)=h*H?A>hD__9yl7{UPLWo(1dlj7#NAQ#wW;P}?$(|;UN9q<%Gbt- zx#vX5l6`m&>SYAcVXB(%h%V=os%i^mjJQZgKy>7PjNhytu9j<;IL&WgNVmPt->cXd7caa(2e!5k8uXzQ$&im@^nRiM|ePPOT|4K3GV<6(HZ(?QV9 z+~1qA)}7Lx+SK6$0$Ca?R!KR&yA>{8rPI;%RMwc{g`1@h<~Viq4I+ETcU>{BTt%D4 zscdW-HFjr`#JW&*LmrGEinz3cD0f1}Rel8UX21Yw$M9;iO?*Z___z-k>zX; zhz}W0r)nWZT8KAV72 zF!vMQ=u9q)=%YmYp;`*23 z(g-A@x+f{+DV9gCEv6paJP|HCmgX>j^6dcwGTzu+wG$cEGl}cX$V22c=UqR2HMxbT z)v$>dveIbo)EzR06D;DUZq-NK_E;Cm&>gbsuZ4L+Zi2&=&beumcmG{iWSfS~Y1KoZ zb$cPkfr7d@PrW;zgsQgX1a&zz+0utGDQ*7d3ES#$#HZb-kjq%)JE2N>xZ@o zM<&4bH-MF*q`=J+PIYfH=hzH9JhC;EwY{G>|1HHT1|sF+i$RsR`%}4w-fMY z<1}I4E&~JrdI_#+_tO_4%ZVu2zGS2yaZluUE5T7M9(%f~E)f`qqmCq7w`ugifw{_H z^8X`p7?85P`R%<*T!WBk#3{s?m#?<357Gtxv8qV-DF5IL6}l2@s^%;JIyJIk%{6NV zbRAJazp}ddDL@si%Y@337Gj7-krtq?cwno{JmGy`zz9Fr6c?Ho<8wbKkawosTx37y zl?lq%`Q6^8LxfKON0v6L;+V)*qP8~WV;6%SaWI;Awva3P@vmRoHhca=;-s)U{o_@D z)03|%p&yEbWqJ4$1w_vMGz-MxsQGVzT;VxkQ?It4E_y0_=drwyfXHlKUj79hBJr6B z>lO`B5g{zKwYb%dvqsr=)UGFdh46`A6Y2D4d0&r-FS?tgyZlBGPQ87WT1A72kc$nI z!|=PtDc>`bI(+NjNeF#+dn+qdYr8$#*+;Ce3vRJiea3Ay6~9B^&;jX=O;cX*KDZW@ zE)R@S)N=BT+NypOqsA-(ljsXlQx;}Lzw8OBM7i)irRP{~Yh>kA>Z>`HQps&aK(J~r z@kAf}VtjZ&bClg4V#zXhr}lNX?R)QKPdqiREAJAhn3}+@zm%WV=`|$oVG0= z@@K1tX(QNJwO}^5cEw)JBGGA?z0z4tJu}YR!i9_287K|KLWx8Ujs$hmw(Ff7MXvM-%=MCwH9T2S&j=}Ga$K)I1TF-@&JxZn3M2l1V@nPznOZ#>iDMHdm?ssk$#_4 z{ZBBZOC?m<<~pW7_Po;&nM+5Lul;IBtgA=;I2Gm}3j9LJ z;@3S1VElu6R3sQ0a`5=Mkc1%86n^VEL3s;4pJmZmU<`9z9c~C!dHPNc6%d1x1kHwT z17&<`(*&F;uML=ClpA4!E4jaV=Z@nAth5ESo1eD+F?0YH&i^~THBQbXw9CU{n*|78 zsSU*_&uSn!6sJwt9%I;)KBRivihORcwfC9A343#gLqcu6S5KD?SX&KJ=6Zi!B*4I^ zx4d*zLIb!PFx5s{!0;~a=d|W4VY+`rEn}$DV$kZ<$d;2_!oi)?1>Py2IcyBg3Dj}X zfMK5aMwk!8`D*5|q!`iD@Gjbv5MXyY=RuP-Bc87I>Eiml9liq0XT<8!z@tlc$cOcJizFT|Eq7T$e1@QVJ3>sS=jcXtRu(=Z}l%$ z=0^8cHsx;cm9&&Bc@852g&_>TxQ0;1vZ1>TY~rIP!|#uO0>hL%Mr|ePes6Yr59Y^2 zCPMj?mT8YSX-S0tRq2{@9S$skt4F9Chv~OXyYLG1#V@3R;%A810-;@v%$V!slh>Rgy_YP2&!$D`E_)ss4#ZdN6VTh2Elcj}n{P$K^{OQVx}g3Yj8_vnDXr@>eBOU1@& zXr&d=GRPm%^fxb-ai^RA`z+SbbTqx+&R<1e_8M)W_u!|?7>}J>8zPx3w77pa{<0oC z+w9b3*$MdQ*WH^e%qi9=ql?Xdh-Fc#Z3pl4YDmtrM%SpcEMPt&Pd89(UrUh?oRn9_ z^yG)8{8MmZhQz-W^0(Vr1@CacAjP;@x-4DW0#?4bdsd(>B{LHVTbo3Avh0Eoj0zoa z1Gz%oK+bHFIK}lV!ZDA+V9!}Hi8^YBR%4C9r$eNRi7J3oH8!MUNkatv-r@vk(cdbRU~*C)k2tqoM& zO+|BJLO@dub9X`S?mPBnW1IU-l-Fg2UzP_g%f4<0d3Lc`q>HDN41YZJ`#v|CW+{~o z$Q#|w`v%(>i9<Ky5>V$Xlh8yt>Pl#`brsGC6(rrf%qBn25Sv(L#a*9^9N# zfx0Qz5UndLVVL|t{U(W$g|Sgjn5c@`{!}W8<@j#I5u>~@+&m|9arBiaFy)zn<*bG} zS6{l@?WdWaT8ZHF^B~H57Z3hP!Z+mAqqAJ6-XC>&I${x|27vk|Zeu`pHmzqRR#vK_ z$?L5;HYY7r$|EIiwY%k`>qQ$QgFcp_!CAfqEF<`%s?A2A9}0Sqc!_xKU1gv+Qt=^W z+99mgp!+M|mvoEBk2ms!KW}v8=**589h!Op$*Hvidff@C?4*eE!ctJ4RyAg{ayn|W4g#R7UW3+CN*^H zP%dR`gpmUb`0Zk&9rAPgZNDM{Fy}EWN2VIPey||4`#}Fk4#FYe6VeG$Y32u_U>|$! zci)R-4n2gTdEyC6$;ugh=6iLEA<87HqVM^YsO4`Dh=DKlUR23A>g1M*e$zJF_;>rD zRQ8;!Sj|Ptp-SWTnuG8+{$eTJDIx5s+*eYy#^oG?8V=S=t5d(eUflm3JUx{cD*&+E zUMN6Ko(EGa*ur5NZ*fteA{GQy!tw|8^fblPyL8a{ccTKe_>0sR1v8!E-e#mnSa4I- zz58{8p$qu{$WI%IAyeu^Oy%!Q;dvMr8WH4PR~coOr7e}^e4P1q0FX)$Jx)Z0Q5X?J zd%pO;tT?Au@ZJI$EdZb}yn+=3&91>9g|$^(w#xiA%oUrxGG?5(Y-k0|<;T!}7?@SD z;51>i2_m6F!e!0WmNv2q+YQi*NHOJsy3yY0j^R9xx6?c$Q2*iSw$efNSX}!FBy+~_b)5(AKK zOgt`U|N3~=&~*^54t!4|xSF4`77umFR2@aU@6cyM;lSL#go*V}1`>RNb#_j@6COEi zJD4!yW@<#1y--q#P|+2FTN+5nhECE!MHTd;p6K7hL)&`M@lofMB^hKFxT=+)*Ph^| z8Z_!20bhBQTs`E9>**q#_JqT2#xVC5C<7ka*Lqr|V!of5Qw{)Qi6*fQYl{Iz(7c|h zE!>!*Ee>PCMoQ`vCHyNnB{Wh4$H0jis}D5~=m?4xfL%VV!qIua=^l4J6zg!~sk(-r?jYb6M4lgZ{6z$|^emE#mo&E;S?_GHI%TPL^KE=yg5_V#L_I6WV1> z&o?x0?aFt-s}G`L&RGzBYh|){x!{X0knPEkBO6Na_ys%QhP=>K1IH?U@SBkM8)up1 z8@xhY&vYt*h}5*@ozrh5cXme6{B3z!l}h*1AEg&a!@MLI0Edr{vJl7_A^qdjI>+Z6 z&H`G8kV9;}k-;ec%vBy{LLEn6Z^buRnCL4(|25RfGJDMbp4owVep-&oX4MOYCYSu1&KE*Fi8oQLN14E)ES8ps-fSU?CV9dV2?rS202IX zNlk+GNYZR%ax~cNsrtvOHX)N3PBM7l0l=9trhF>2ye}El>1nx0=%2nLTk$kH6|TC4 zsCa*PMTO~fV^(}87)2^XQqzQY;>hA=eS&Z5uTOU@2DI$t=eqplE%Lrn`ek3krA%y* zzMxidsL`KS%26BbT2!RUSiJg|YV8z8r?C*<$3b{8$|HR^Buw?_mH2BJZyFh8PHNmr zOkxiWr*ru{M0l)Xt7cyXQ((7eM?9$W7n-+!ARTW(_;v25Sdqy()r?1%9R7d?>DWmjlQ z60*PKI+HA8vd^Kk?tFi5S`zbjFG;#wMDOj;k?F_eg+~GV!j==Z7P|f`KoeY}ON5nd z!3a4q@-mXgG53{Eh>cR_Gr;`#k)_Q}{{v6tN9T1@<~H(H>6_L1goJwlYdSN(Np=pp ztDyXr=lewIIdUt2p-mdW$`f=~4VY#FtsdzL6JV=js+h{A45RgH+CK`z=sm(~*0Y{I z+R*l+=9@jHD0OdVID4g}N2`2B@YqWzW>NhCD8H`w>bCB=(bP9z78K_|EW^WsyY0Ec z*q_`Zb!X2M3Bvznk~52W0Lc;{T=dtm8S z^Zb>}Xd|9V;L)tUji|o=Y%vB4Ly#Bc(7+LfuPD0k;k71~zgFQhi0R0uE=5ah+8V?D z5d4p53-F;99{S6P9>&su5P!vd1OnH5W%$YQ-FCBu(QbKUR5nPOo`g;1$y!tR4A)J{-I~pM+2ptKID)Plk1c2#o zlh1EENy&Ez`kMj)OJhp@-3BujhP6f256GdqU7gEppQXJYG=29^12#Zec_tPH!)L9! zF&CtqBKjKES{JV-P~Wf$w`v?jLt5mz!rsuAA}iFk{D#?1FA1vEy^R$!W8&B9A6k|% zvG7Z87)4Mt0{p#^{??kcyIrSB$Oi6RS30cK(O!;ynIe=H1RV%d^h-u)5rq(%PP7+f zV;K=c9I(`@lqyU^Ux2V;Jsh$4n2%|8**Az;a_Shhqkh&h6GZK_VcnD@2fmTgVR zDL|>%Rwb*6QK0o3a0a!iFE^&=h+cVJ(t}eUI$Y_8XRERk;x>m8wO>*R;XFjt`0iol zGFpVgM-Rq$w;8m)akb}_JyFvX?FOW)`Q7Ifzrhhl>Y26LZ`wgI_3Uc8(FTX|l7J6! z6x&$5$i4Dd>_5^RJ`lIbU!Iat`&%2R29+!Cn=Q?K?<$0xwY--RUq0Q_a!h%>QKum(Rfw-Z>EOsyK$*KoPXBUJvtFflXuDWs`7tqEuVJoGw05}Z8 zdlAnP)@^a+h^o$h2V~;oZDnSgAmKz0S*s>wAy1C+=qW z^_%O#rMW%Ko-r0uHp_z#TAlzA=z`39r~QW;@TVRJP%37tLou5<#Y6clU9T_AH%kpr z`+tJFy!RMoOyw~sJk*NkR+I*Bz zdA|hRz`JXyj~|KNtDnFDhKI*AmF%@g%JH^U9E9>({F~^ebXWI7C0in5rMBZ+MSLq6 zcD8yy=MwrlsT|Kh(WyhHaUYK!Q zLRnOEyB^3F+e_i-%+f*CL@}>g`G^f!_ZR1d;(Dj9HORVe2+?U@3nGV01+QVs$|u$M ze6t>8)5l)#YBmRzQ^J?~NPh4$GeeOgj7!C3LKoG#$bHM}B>F{=@Nlm#cl%H#OoXqD zXDNmcE%twguQzU0p!`{^)~PIY$7$P?ApnEyonx&fNlN}K%+?3?nsXnYG3jG+X-;Q~ z&TMM<{HiuPmI4_iy`%XaGnIGglfj1=^5wK@;P<(Q>fArOaDTVXR}LuR>2g*lJfo}v zY1hW#!Qgli-G(F~Fmf+vBQmZH!@tH!e;;-H`pf&VoPaSxBH+q1xIYcYQW_g8UJC6k zs@BQ^r4$1<-5K%u`C!HuJZ<@4pj`@GOg_6Xs2bkVXe!xk2|+Bg9<-t(*=aXjZMFQ6 zK3dzd$c$0S>5hD7pz!;x7p1k0D-+iEC@&te?Ruu@lD`6a3x^;q_nM9SA5c4O0w&eM z29ATxgTCfa{)g^Xx@nsX0}1x6aV4VSSpHaJijm6MRK&J~Ip-L-IFv>Rxp8loI_85a z?!iWbzwx2ckotHmA)n^Sv^?NaRrRz;>BJMCCF3w=Nf+gEU#b>ug*-vRPcav#m1DB2 z#PT2tJHm{c8m-|6v?42v+&%;46A8YY!5;qsgBZz?J0n>K`f#p#c!)#g%0r9$W(!F! zhb4)Lr9t4f)UoYG8C}+X5joBrO348n5QL4a-{v!#5W^Z)GWQbf%EDHEa?0Fi;Ux{w z(eLL*ibgPnd%$pP@{RD{->nstP(bI<@r2OOWd?5&Jj*Ha1&rLoxcebpOTJShC)|Lu z-rexe&nYN}Vjn|fj6rvA8_4ufe{6A``h=Vi=7-Jxz+d4*1TJB-BJdXF``v8wDNp@& zAPh=>M@X8;c0utkVB|Fc&(fQ7=X+Sz{pWa{87+#oE~~YggxUj$`JeX73buSi(yQ@) zyd?^@5zm{FM$T}zsgATV+~wS|4@Bwd4l%+g7pRzm0D^igvf6z9krhZWYS6CMb$j?l zQc&!4`^qR&O&Nh*k(j$oUt0jn2l0Qy1c>!EiZCDJZ`ug>0Ziyggj{?7isSM>^c1AQ zHwgi(x$#icI$igR4&R}-2(C!X%G+IIoU9|D`1NRbWr9!<_O(aAe1iC!GWAS>2>o}j zETdkxyDQocV*G-saij5zCp*S@UYbsj=J#pWT3!3fskZjWhG<$?YN9qfhN105fikVpppXqz%&>!0%_lEeHMkhlH{T@&tbE- z*ziGjP8f}clNmT&xMzyckcCS7=X0u5+bQjRp|skN!}FsfQnbdT%DzEn%HVtv7G%j1+~mj2?*LJf6H$%bu6M-` z0kv*w?%RgeLg`o(T6*nl7TG$JOf*sv>KT=OTF7p{YV#h1g-w_g8VdAC6{T-CO!vTI ztl#%B+;}!D8D2J_!PLk1e7z&j3~2#a`@cRSv+2jL1BC>|hDVf6P*i(5aTXrlE*^+> zh(npiFcxjcSzLLCl&UN0&Mez=Q4*EXut>+8RTKPM@gY%)(SD*ykQ93caNzH`ikKSc z)41$tYScXHE?0?s0%ik5uQS83W(xPmm{9E` zt1MdSmfq{wt8};3Fr`mZx{u!u9_G7DO91!mY~Zyzv%`>Ks`*H997cEbELTv-xhRiierNbPUR84dlMUCV^Y zcicNT_)o~V0v6TurtCLkXRFfIS8GzF*yNOjW62ZjnNtkV$yISn{?bFeO!wPVpDT6E zWXQzKgpk=Zx+UdDG^Y7y=*uTzWu_Yh&|eE)&j!KP#;cz3d{bx}@kSI>>Ti3O*==+@ zMFj|xmV^ha>tMIjM7lfxUHjo#59hHj3jjto*M3I9Z~li3zN0;^Y?OOB$|>qYk9=gz zC4M$JgY=$(%cq+Yy|t}|?TzPcvE$z~5oAYbJMplFOW$w8IQZ8U@&V5}q4jsa6Nu|6 z5lqD1IS5D^ouSPr%x^@14HXd|B)_+A3?ofAIu{#CYK;D?-c|4XOkibQD(yOn`guR% zRGO+FBKLrDih^My64bG5~mUQ|)LZ*V;vLof8u!f%Lso&MeiU4yWfB z@dEExEP>A4K;1|Rqi~us2bRjY?a-J*;=l%0*mU1ycQp)vUUssx_9%Kkjuj!|*ixl} zk=~+YbTnz`c(Rhq`rB&kCcv{dPXl+?tu$qUa-QLO(>qz`mSBKp#d(}43}eQ9@RRFP z=!A2h!LN~7qplbMf!?RZ!DWn9u48`{*an3bfONwNW54yoyY$<7T`pq6Klg*GRnhLR{F`>VWHnHfkXsDaUh;J+ zKgLw82jUSQ(5Zmw-9`nCx~%yZZ~ZPy1NuIzRa9|SPvYhr|T!3<+*D? zoz-_-OYt3e!LVDhjrJMr1$adk>5teFj9eAstgJl0n(@TyO$lU_=ks^z?kS zfk&D7I3s>=A%>kkUw&Vnclp}ccz(6fYD&CqIDO!D0xqH6uLMqH!uZW8T?oPO3;n!F z%x^sV#0aI(c;GGDu4tJFL{TGEo#Dk^kbziNU2 zwkv7Um`GW0mT+>Gau7U|Q#dff=EtKVR@P1-SlZ3o+K(X0y^N>==J0nTIrw#AP-7>U zV$rT&$K27PrLtlQlFQ9VSnYH+;fOV$3;tFjV)vF^%@JPSRpAid1AZiUHxA2tNdqx{ zV{uI>g@)45;DcI91o1;9P@UjE%KpvNlGR%@7NV}j(6WIJxf-BObv`L^Y4jOsf8izd z-rMv5QKSq0$X5tL0(NkCZM+G$C|zq zTFOz>6LyPdW#lU5+Q{xv-M|9`T2m>xzViR3D)hn5CZ~`?!NqnSq|tPS!iRZSn&yea z&82|X&``>I40sP6#ywHR3S&3}w|9ZD<&?H(s1EU}LD}CBu_eEq4#O93B?SqFF+mZ7 zp>D80)SAOsLVgyI=IbY!QMRVaS+K$115McV-F8Ye<^YE+e@BLl>?0WYX{Q4uaUP^Q zJ-cq~z^Yv>rCY@ZNz_!bW)S1=bLDT=KyQS~1Dtg%ke3V@aD&r@c8;opVEFoFY9#BN zAUh=K+YeCC1;6?VYu?Pey|$1=w)G^=R-690ek)CK%&LVFzRD`@Z4v83gM)y$^6H+|-a&@HpT75Mpev?(Z`_$Bd>0%L(; z=>ehO&#>KuV=jI_SSJn`oEs}kz2{DlVVdCtFu#67K+_xu_~mW{3u3hmZ{W=mPVf_U z%b|oe|BUHW%SM(wsFcrYL-{k}_F+E_{oycIA?i11!e(dZ#Wvl1i=!FQLc!d zgNBdb(;*GZ{f_}w0xV&4_@x+dCIlaQv#!X&!Rbar3hePx2fq_x%ryCEsdWE~F$s$C z_@(NiW7b^=eOj|ALr(#$?!^+IUOq~5*z<*LsmkUcsO)@rSOAZf zd8M6BDi!}{90@xI6xtN3<4=>Z8``~l@tpS9S>{|(W`V!p{Lxqy@Kr=9IOt6Lw#bWP zDsOShErI}Jiy(Ga94W2L{tN6hm55Y;=-y#u9D_zAU@hkHL%E$#LMKqWjCK(25lz?b@ty_Qp~|6m`5t&1FRZhFlx_zkFelp{nb;!6T(DoiV80t(&Cv`?cw zi*_R`n8t;wm%#udshLQ7A76DFi+QUE#F89 zP|_vR6~YG=v}f2=%f}Q8t8#U}B~s#g5hrhi@5j+^N)${eRt>)4mYN{yGKpLT#|GQ# zw7=^ccG3Bw;KGB{{vw|-XnRDpVg;VrUv`}jae;Pej|TTP$oc-TO~mX>v;Mn;>S*?8)|c+c^}@xq~Q= z`P;`TCt7GCfU9p5SPkR{*adhR76~l} zzZIDc-6&yoNG(NJG4OO~GsQnUmv}&|)q-%6)fL!SBkswozpMvKG+fbS;(`v6*Va!l zI#f75vRp84zuCW^@Yi!*vWLWSAhb@Yz~12hGQZ|Pdsetw8q-7%&Io3>tDxPl+^Qa8wWFmZVHnmc*jk=?gtT18ti zZRpKT#f{71K);_=dnqf~7O3qL-#Qdv{r8X!gFw$41#)Xd*sX!EVU$DpSr7=H?zv=P zY%j3_SVYQ%xKsJZ&0gf+bgH&L6?hJN#)_#otA~1b;l>=qQd~IuL`tI@$nAV~X<>c<{JxL(cIxLgG$Aq94F*nacMFDk zuHyF#KtrII69KlMYn`o=w@JV`hbo+xa?!088D1NU5E(SR6Mae)V2H>MC*K0O#At}J zKsT&#z-3cb8xstus1%vO0a8tf^V|b&nWZ$WeAeM0xFThu-rg>NW@aAGDEZ@=-@7V0 zEAN%Y3Jq@*ox%-qxuEm~Vw+|RH-^9)Uq)3HzEGKkW?w6l8DUN@i~EqeyrJSO!>YFDFr-r4N|XlDxC_o`_`<}QBUcbk_m2izI&5UPE=15;516>sD;K5St@ zOgwBGWb1dZtl*TvIsn>>c&bLn88AKup=PG+zTwMC$cq&6!$6TN^KyU-&<`Z6s(9+u z#V*m_V{0%~T*1eZCv3g+Fw^Q8d1GRot`p=_GV(mjJ=!;bre?j1Nz};y-C$QX@c}An>aOf{FN}TOMzem)9|b|u4|Np zZT&Yh^=xy~6n!+m8mw#Bd$s=(tF8;T(6TMF@OQIboda~sji6>yKD?$InP3sRd3I%MMV_37@?v06 z)K2eWUH*=VWENKJ7^rKJma$*S7efygR)9=Rc0kgLsL;%xK%ya%9Ge{6b+6{O`J46t z^PGYwvqc2fdDmWW7bQW-#VQ^V$W>>`uFa5K+v+DPu zV~+$kdg3S0hC6km=(uAc8Lg;Ixv1=aC4xAc1*i1uCsD6hucHqLP&KgBpg1QsSI;QQ z?r5m1V@@}d^ za-tNADV-;U5kZqH9TJ=81u!xt2nA}z^r72fW7;KGo=z^dFD3h;_LTOrN1Qd+*E$Jx znzSrgYY1FmONm0L6zRGOZ2hm7L6Dggh*&8Vr$ey&#yv{SD{w>?@i8pB<6JFSBlUnz z@;N(=LSrJkS`v&I*QefDMMNhR`F=h|H~tH^)so*5t4I6Si%+kL-yc)6_-j> zZ)XaiU+2gmO=V0(H=76x2AEQLTk-^&=0Yf84H>lBUZVI9$mh#v(QUxP>WVBeKMa~B zI&EUunw4jKN+^GS4R*Mx1u=R>Zv?uK{5xaE%9FR3No4Oj{+h4=H(nWWOTRx|Ho?Q0 zyzfEafjtXsnm+#(jepc!ZDHhgUi#$Da2~X{D2;Nd?~F$bbDE$`%j(5?d#_4J9tT0S z{*u(U2V`m$JRGEpNCuob%Z13SS+KXY-SWL?_po4X7#MT)AaP5gd}lPS$jb?RfOnm( z`UhM_y9rdd`{Ay8jWE`8Ls~MPBKQDiwL>xKQ^2634iJfXJPb6(W7sRkWqhrNP3g9a z3OIU3mezE2DSTCEraX(SGMYN~S7a6M9#Q9(v`;!=)Xa~|=FCI@D{{GI4GsjBAj z4{QKqfO%S0VNkDgi(T#vB2;NljY7|PBQ`9Rd1tE4Zp5CS{OKr2J+)gIHQNNt!eg@E zXv5VVRn&Tq+Bpfze{7PV0dHJ|SS+OBN~*JmGPa2!C)X*rr;M+{U++JqOP) z|7aGlB8JC3`MAqt;DM}nO-v7ub4S{cLb?n`*ZE2|zpr+81!k(PO~F&9!#FxmLm8$T z^a}P#WUaPfX15pcl6$)_Y^swv%O6E)In=C0NSdPK*t}9|gdk8EZG|4vG*gAQ)v7<2 z*~Z^dR+t+i^!JuO z{p6fFzdsbKJEX3t3;BCW@zxzte&utf{KM7!XGwcDqY z#^SZynVF&~*JV9in2yx0LU&J0E5FJq`ZVDyd>7LalJEr0Jn{MmFm!`QK_eW!5;1rA zQ=(LwKXIsOmx{0+zSo(qlmHkr>C88Dlaz=ML59w zw?0HRyLa`c=bnhf1qmEmKubtKu}vRTq58m5fF+G1et5k$vg2hv@H1rs#^F~M)ou!M zEdD`v{EunxcfD*1;{><1;qrT%4qEPJE4o%1}CW&lf=-|LMaUag_R*^u?nb5Dv|? z<4i$?xm(-4;hlHAqRz$s3A!c!iR8qcUAEU{A&9`4cSz^)dNA%TZ?{Ugk%tjv*Vmy~ zgBCoJM8n+NJ{Ws~A0eIzXjzI2_+IxRF)h2)54~#|3Hp>_u@8F- zD;P#b0%eVYJ?|~N-6u9z>jtpq5jNLDJ;%4LbOkJ#3gj6*3u{!a$09`HVSK?$N!fDn zKb!-6V_qXE3(GI6Kx0r;o0%x9cw@E4@s^=C5bovFuMmo)+c=X2=7ZU94~81!yG)FQ zTYi71UO3}#E08p`~ zeVZ2Pm~C&Z7#La+8vHxAw8kBBCm7XG$TbrVpD}uRgSq*o$5NdXgVj#HThIniV3Rm9{a?H*C2yV z1>33bw-JFRZ``)4#ND`@C-M|=@BFr(@?5T<}lcu+WTY1OFr=7GlBC0%Nzax341tk3CZ?( zF%h&Jb4Cb#0I7;aHw@=wPt#lAO4a0tSOb0#%2}sq19NX(irFBl+K!BoAbMm%WY5Z! zMuP71(KaW}ZSxW9JJgeh7q1%MsH0d!gaNBed3*ID68Nve)s| zoc_0fzQsWD;L;wN{;wX>7fy7&)wBw}n=-XDCKi3`a?CjIL-%^ev9oxv3EUkY*nwO1 zKe9v--(bynN{ej6c&C1i19K{>*a=lMN6F%TsxR=L-y+ zW#rGj0f)<+;K$<8Qb@h6UBNzc34eYRF68D2@t%q-zA)nJAzszHfc0L0YJ~m@HNvXt zp@yb9J12YyUgM~h2T~bN27Qq6Se@@DC&QiaOT2JCkQ-V#U&7%LkR{@u#C#Hb5D(I9 z@s6hJWZaWnInueLHS{p zCK(e?Ys)0Ma!PHS7(fjLAKU;|5*!<*frnI*JiA%!s`@U)*?KTPxy8~)r2ejEkJnh* zTRn0pWV%5y9$74=wxu|5`dxPQTq#;r4Cd`6TX$VL=#kN07*wqapffy_l)W$ymR&7C zGs0R3-YYa8$jzNq`ATwLM+r^-eYwDl`-JoD&C}@r=T&-tP-mXb>yVuK#@5UQ1;A&2 z_gK>6BUFddTm88tIIKBn%YeyZp#>qRf#HtHUBoKCo~; zJ7)AMs+(+Ne;;%eaCMj#%ZiPx)6pxykS^RS@+>dm+t*(JlkKig!_w@=dfF_FEW*aNkS z>`zuded4UnL^oM!;8>K2eV%h?p}&U+YmHXTrAzO<1{pV3@!~B^bjB}oscy-;QJ)$) z-Q=ytN^0AnX#eSUXRYnuM1E=&45SQhdtV%?KV_Ppm>p-62*h`K>4squKW0CIR6Nvk zfavz1VT9YFWEbIxIaIfs>lEqzClS+z+MjoUf)<5lMvmLtnC8L( z+lgJKyWkQn;X%cbTxk`n?Y;UUEmyX9Y}D%b@?H-DJ13?`X`XQY^%as5h7u&QuC}1` zRphHlJe>_#InHKp#D#8@URYv*jq z7lXRPl)~jG;acRFL@VNPlb!l$c^z=~fUmcKPlv=?4`VadS;+odl}P7)o%&Nd|zEeTOn;7f01 z_wS+N;d&XS2I$9_n}^?0MjT~z>VU}p0^~l^00Ds$o&&)ca^#HdF^O#gq4KV3$s$uk zLda$sdxW36-%l2}`X#W?{s@$}0(7$2f%%nl&{^CgS!}gsj1C&>)(rXnwU?}wnE5y3 z(&AFaE_Q@*=FwwS3YfW-C&(FatKBGhF=F3dSEXgk$K65RE32cqGgq+Rt?F%grWXJY zrDa=pu?9>N3_fJ&Nx|m9XC!X8KKNzFT(pKby7ax&8okWMBS3BCiiujt5*y2sXD;~$ zF=n~+#6yqp8edKRa+-m$r-&_?)F%xVwHrz;BG4Z0r9U^6)fH>aT}tfm8)=QbI1F{? zOH^gkpVuR5f2s3Xw$8i~ocP7=hUmXINB;5yp8E#4yqs?%muJ#B%VM@~M%;a3G@<<9 z!m;PD_lC`){vt@dX$UXGk`f(-i!fp~o|!`tV;Z~~WqaBu9p=$?amZ7J{YW zLPt!i0BZ<^K!%A!?D8RyC7C4?4FfUu4@W|I29D|AQ}DH>tl%k$kw^U&DK@Bu^bVpr zbzJY%f&s&G%A4-xmI9HIzzJN)1n07j!83stXo>EGL+AgP?y~gq9Y823srr)&;V)w{ zW~g<2g9X?T_Vo7zW$6$F>HP2<4>L2t=#urGIkdeeD%%G3QHx5SnEU!WjC2P2D(2Et zi*a1}G8?9={JlJ<)nbdJ?;z=&ZUs|d6@C=L^G^uOX%z10gd%JJcb3k(17nB!gbHtF zCwl_+3=93OV$=55*1WekG~F1(aBVz(@1{Y%I7li2SXW8#T#g3shp&kY;S7ijHpM`= z(mh_TB#8wohyV=I++HS{Q4Qm%6gzV0M5uaEz6NpuXpC>Tin|owG7AhMl75;vIDkx-Pyv#jOZOM^fAMk0QS!T7yLQxyis?kRA^DembB1O{75l(ewYePcVmu^ z5#?DGBklrts`#X1WLD4RYsDVfYt1JIc?rl9EvI6W|J@l)z(--0#Cxx}H&c=Dr~&lK znYeO%? z7f2dpN7bjtc5}%}{YF7A9DrwDw_WjW_=s&s7K|#s|>_k0PR*; z3($+ix>p|5Drd#ireqzmf}1u|sVdtNn8GB%KBgaQfr3%|r8YZT^#Ayx?o|! zJN^bxhYKKj*1Xa^{lNV=ODb!mVNb3%ZMp||fIYzg<1kq)qke2MLKP@8%|wW$+2D!h zCPC`o!ckapk3zh$o|?9|kVlT?3%Km%+*O72VThdip2Nf5x;qy0^H1kY)YZ(42K`b} z@){l%H9ee0+pJpp3}(0 z#25Z5Q7~qrkNPKTwZc&eU$Cg>B7{=Ih&j(p0GgrF!k!iyDVCx1_E4nV;gua8iSiO@ zcWl)Kcpf@ZR@5+P^7gddRsvjEZRrD53&6y&YoNPhvgS|OWGmxaN_;tD z2&8b1Pe}7!rHgv>-gh3cdWj~7v1`1RYjU!(ktY4&q@hPvy4rJv6Q&?!44B}q<8=3Y zY%Y0?AJ&4I3(S@FyG7CUXG^@1ysJ9?+J~yo?((Eh9pFa_#KHcTWGF4-N+6&n$C(5b zKsJhFBAV2y>T~!QTka?s4wt{WtAIIU21tfX*ufW59%4V7z4Gqkvnum;j|7!#jYsCf z2|eAs0op38AQqo{MAVBT*@~YM8EhCHN8r%%nn4tJgkRB}@1fxzi3o}*TTus9^&phR z6hsvq6j^<-=rQ-G0t`$YVY8P!oR53P)^wQm`x!ZVnN&I>>$iod(-P$HUrBu9;&JQiv=KMZW?FT)v_4fo(!1I{N_@Z>k$o#cfyh03Z#;)*iS4 zX>6}PR_%`J_!6-zCJoy$hv2fhP_%dK^YF+;M% zOc{W8nvxdlc_iH3M7!ppmTUd5sY2@~T1MR)#LGlTK^ zu_zu^T(VQMv44=Mfj3~3|GWi&b4-E)skwC38rDGEjl5MNeSu4g_vv5 zV0>#81<)Kz<@$ZhE5{6(S!CoHl2FfxTd}~&u!cox)q8GHJF>te6D@=0*d<0~(Tx@l zG}NZ%rrH=Da7qSI_{|kYH=gvaCv>KK1Fh4AzUPdUH)}T+>EbgfJNUN8HhNA)15GW> zPpLxxJylh7(un`ytUZ~8+4$$Rn-ZSo7y058SZ=~HUn^}|T#TlpRb*~IFNd_<=rOM% zHKD%{7m|RR4RE*B*`v*8qKC~((`H2_V%URjtsL9%^G%q-NbXrM28Jo=?eWXafsmh= z&8gQQofV+SG>s{!_hHsU@V}Eu9KWusO@}OK6Bnb|Pq*<{DVJCIm2Glb&Y1Wt`}$C@ zSumrLbsXKfp5}CAkSu%;(xZjMWMv}Eo>d?wl9cl)i0m(21F=)dLu>$N^t@!@9#Z~i zY5%;_dG#!z+upKflWH;F)r4u`^4?bD9SM4GP#7McGb9Q1yiflaX{HaFK<#x0Yn#KO9xgz%~|3o)uFCKx{76DFj^3tRcQ^HOe9E5J#~TCG{dNcDS&MK-3I#A8E5wROEpyG(8Nqc zNI#YL7iE2A4nj_Fa;1dUc*5!hvH(LC(0OW(x|+7-^5voG+7ZmGt~J(l7>G2=riaM! z8CV5By3ToH|3WAK2O!2g)vzP_^H>;SRYg_)Od!|#R9Bz-6RZ52Ju;<-=8=~#oXXCH z|Fg{Z9(Y?%8?5uzL`7^^f6LthI|y3aRUbGa`@_cxfVZ)>a5V8->^7}5syr}HrDgsG z{@WeVAzgaKh>f+OX+kGvQhq1OOn2>XU8yCWpMDwC`zQdEA`vK9RrC%q=DX}GlFlMnCiD?+2<&mp+)7}<0*TvOFPi!)QUhkYd< zjbEogHbr7ZQ8_4R_5s+}NVTY92mzn?P5e(=b5kIp7^=q1QpP~<2&nMpl@UH`13;hg zr7D!zO?7>QYlgi6uI;5kV53u8OAWC*h3x+lY)6{w1r>V2A_jkXNO;93-=jHPerDqP{h zIH}ax)ygfi+?`E?t>|17><1^EVCej-7$FN$Y#H67?bYPGE8re<`QZ1Y-tSXnras_j zGt!E@2_ZHyZ{LO^OkiDbVA~M}Ifn&4;-S~56ES#GmEa|ivmW{)3@@{%EsoH6L`gK- zgC5I&Rqw7IdQ$~#~N6T$ibd3%aneEIW}9m`wY}li`Bx|-fa+vf$DT~ zL}7f=j#K2Zw!}7}PmN{JaHay)}vSn?7DuU25{B20w-T<($Cr zwp)>FGOBn(5QaR0oqAb_@F0Z^A0RYQbs=vpO*F#E@vZXhd(VF?;L11 z2n{M`aJ;El0208k5*QGw8jV0yP0dTmksj-JvOBbND=;f&TgULAnO5Wr&9#_m@1Ts``YiAm*z9ij~kb{hO<~2kt4o#<`_}j z(e-9W@pbO4^^sz>1dmh`k zd9p}n5AbHCordnVo@I*vloj?UpMzkiERpn?fVs$wy%iHrAgQc~|J$7vpZq3b!L828 zAp^pdB$CysM_^~Fj4J`@WDIf-aHU&tqd_S0u%*i7W5niG@b27J7{=fk`{a}P@=HSE zOS?Y}X`gmCSxEK*i)ZI|1@OZro+3oP;=l_t*tR_g;K*Gmx08(+`pw$KwTECidTm=* zrVgV&y%i#*23+JhJMaDoX!UXUQ?}>CW;;U@a-*g0SmLCwCs!IHXrr zVBfK!c(liE*opdK9nspH68=|irN4L{xcv1Prl?DCT#w#Cp#-AvzG%k3?>U_{L&F}{ zL%p%_3@}8^NRv9(JS@xY^ga)wC5JIHv1zZuCrR|~wRrIw&~P(%^`@p9B|`c)ptGOZ znRA$199SQ~A5G@heQ~R3GV+WB3<4FC<^t9lsLyGS*r&sNMS(mn&QxGa`U|Eb=E`cD zUX?suV?+jWK-V^-qz^^gQ9bLfF}JkAD%P~_F3lwQk!nEF zpCk{HX+J9ugp(8Cb`q*LQ%R?Nssy>zbN9du+@^_(EIu~qAjqxs?t?aW0^~t#8WUeB zHnVCWP)=Uxt~ZxKmqEmz=k*X%>1Cxm702asbUAl!Q>@66ClJukOllUj@`5oIwjq4E zT1ke~rLUWm{%SwUlV%5p(!vNOe*TX%f2L`DpZEt1u-ZG$z@5;1Qyud2US|7}wRO9; z_Np(FZ5Z{!D0L=8n5gz_n_Vg*Px?&QOZ~Mm)rni5%s}*V3T60Akua56HCsWn(1{a* zPY66ZDHI@Jqu2KPZB+tOLKFmq!)$?~PZ^&OP&7fl=3-v}n|0eEcdq5_sjHwf{9WRcW5%qY&{ES50X3s_m2Rz3OgO9)Crbg-ytsJf> z0QIe74JW7dgRxhZ7n;Adz83b;ax@vD_iS+kA(R5H`^ZKAe}GVqO0+YeYdIXKX%Y`=>11~gCZM8Sr-4(6i*LLP|@g+ z?c^Nmn?Gt@z4SQY?#kY0ZTGdH7LEg37wqGu^2uQ)51dsWp#)#vI7B#RSF%%a6!#1q z0Emqpc0{9$NED__Mmp`B7`0!L9-8Ph{#e6hnht!*QC_s6jOPOnQDqlNDwSI$4DmLM|@W04bCdKgM%v-m9r`4_YjhKJ6KoTS*K#ZLQZ^V)7x+ zS%E2GVjepITE}Xw1k`rpybg7v#A7@e9UsK?Fi+uJjmGHp2+~@l158+vHex@}m^MEc zN$o@by+AS-dEMzv$=W+sgeHzp#W?=;u5XFWrt8sa5SfWI7l$6)Ddwz>7}TN5`q`Eg z9)Hd?W+yRnFsDJJt`P-!A;fUg;&Af20ipd8Gk;u&iPr_hjI8XQDwnZ-jtz?NK-hRN zap*12AD4xV_Wr4$IdRDM$Va*^Q}awH<%?0w@UWplj~n=I?uhdq^0lcAEYUWyi;WT8 zE8=4aWjA=td@Uf*s$i<FbbA5?m5MB@#qldhdlKrBL=a+C01c65Rn-xbeOZR< zf=1zb{?*#X9YcS;>!LEU%9kos$iho1tpR{T{d z!P&%+{PW7nY#!}E4hm=mHiVK#3q1N7-sb%1Pe&G-yC%)UO-EmVyuug(WU2__b3^53 z9}9MzP`jjc)H+?0YcBFUyb&<>;{7G)xC+G#+$t)zTZMu!gKxpc?Kc@@U(k(65e=qR z$55f&+1zjEZM~l;;3ELgXc0oCa}lDNE`wGwLYb5PtC`ZES6>-MzBN^=m}z%+MrhR> zru2PSCaFx@=k386y(Dr@9`aw@Ic?fc`E+OVyGctf3bLJw$+Kjj(;3CB6POf6Gy$z7 zpg$JLDLk1TohU$I1UcN-t<^8^DeUte|HGbvZ_-k)DXxl62&-pYfLMx-Q_7I+4^xPI zEq%&-Q12@yzD|tUR#a$h!_bD$pAzBt!gpBgmhVzkOAiZ%rs${m>KQYTp%z*)2kUZF%b(tCB>Jumw~zO*k&`J+TuB4f*S|_2R?BboBtk^!`XRu zU#vpyme^l`@PBLk6tJ}WMHR8Z&C05fV$YOQPX@V_BWTO&9ZvULOk~_0UHDwz4#wT0 z9IJ-wUatSlE+0_eEeZdPeL#UzUS}=YaSUqn5i>@QcJ-4RaY`h#Qak_il}fpkm#m4% zvT-~r$g{fsl2P@rMEY{A2ozXgWo@eVzHCUinzwd<70Z83mOYHSN0E7$mu}?f{~5(g za!0^Ge>oC>Rsjc69UxC3u<%@~4qWKc7FON83FRE$$lH8o0j2JX{2`J>X(r7O=HRYs z){Dplut2us&j0JOzt|tKDnKAWlw#3tsw>2jw8t+AS6lOm+hL)6G8#D)>=?;-g3SQP zMjdN%&pV>ZD8NzNyn`}3@R`0#4xXh@+>ykhFm#$RH zBHdsxC0*arf&tmhU~&W1{kk)7FKOZqX{mCe!mr8woOyl|{DUSQ@-sxXT81s@fC(aF z80T(}eY8%VabKViQU+c$mL54Fdu6j)8$J^b#Sl-uC@I}gGDdU<4HA1f01WAibSBC< zh1|Q-bS3I{@|k7s!jaIO#xf?RdRA>?Il!jUJQ5Ya7%k(nSa8Op;0f#zl1aZZ1KJs7 zWQ{DDh6d*2gzr*bOC@w>0-)ui-b!Reuo1mB&^L0xP=u|D<`Wk@N1YsRf5(_xvoN_0 zkq|td$!_JoZqkO_2SyNDZ}+X+)(xKF!#0-kb##=_&X#H+O$KP<{$6>mE{6yvb3{od zD~$l3V3iq-)+*QWkmx$GG-l;Iu9E-WTVp(XqsLe(PART|J_%?L&k%fCsnUzKH|F4( z(C5ORHf$#3$>N8ekIIh8aD{p|%lf{j#*p$t9?NAIhFlI2sA2UY^x$cz($p|s?<4z62y-QOT%5cV)# z!bp^_=PDww)i4#+zv%GOVXClvwY7(V*-%qwu{yKDtORvH%k4IsU3c@L--S+izLW>Ub+tm~1+l{sLBttaWiM;LH;Q0qqtF zOr~}&>qjC+>jTWkh@<5{F{M&Tux;V;3LPpy@~543b0r8jR~^mBK(K8KdA3bsyqJE} zytlzk&*%ImsX~Ca*;4FFT@)mpDwZ9&=CKaU@g~#rnJhY*hb~6|h%kEP!Et(ERdST5 zvC|`ENIUf0q=Yq>n(_^+y!%kQTmT{ziE0h7v)}fo6OGQ!W9>47xz82r7b!&*bC%zb zTXQn9iH`PH6R&)8o=_5}QFLIf`i1c))|91^ZYjAgcp=lS8F^&Wu)!hPr813U8Qp@X z+}Y_DIKGwiWj;9?+>8Orn}3Cvc1NsjT*WGmmY(hk<|&EOMJ_m@Nu*m%9ZGtTC3x$R zO(_i|&E_C0Sr42F=2H`#{#qEx(PC*&M=$hq)Y=~I!A#rLIQDxP1sDI}75`xu0q(Bnqm9aS|`+s>?9T2(DtejKFayJktoQ2!!iTCE|0iwUbvobWIc9gJ-O z8`Q~;nyg%-9yrbrK1}bL#6cjWMn^|h2d8>_I&-+KCnZ5z8}8Qmkb~$AW_lZ>-;I$G z57gUPrqH6L;5};7#}v=JZek1S;0rZy1$&v?y1hzbMewMhPl?huiNWB7n&hUur&_>8^a5C{@onH<@cL zx~SMoi*MiIn2(8<=DX!-gGVn$HG;tvMb{iD{>Ru;z6Dky6&fSd@FeOyj5!J%UoFN| z;(uWXWud_Id}aA$X84Do9m;0i+z=P4OBLlZ*BxD*Y>n3pbCyuSrQgVVX3_}Ixjw}s zuPhw0J@x?&l`45?^ZyXByl=nhU^tghK$$L)bt0;OFHSI?GSX+70%$K3U8tz45?$4A zbpqu+;!T*D1mcrD83ZiPZD-ol4Rfy!NEIoG;YUc&Hc5%Zh0;$c*ud8IFQ)xuhwx8I ziY~9*%8rD}izj&BBa7`3p|RKbZhxJZC)uVas=M43-Q|RR|IG6N5&En*TCIdLbDPe0 zd)uy+Q?a&Li>z>)FYU_j4}KpPw^C$qDO$g{v#hvnVVf?nkp}OcEc4V?*S+nk-Q~RH zs`yP4qO_za|M1mN_7OkdzW3C`65D5%mn|%D^Q;qgI#{745A2U^yD(_>@oyZM^=LH@ zP#S}v;w?neh#V>o^VuUEFcWu{;B*)XCi@Kv!)~Bx_G%$z^hqns^ak2HH35C_jt*n8 zV9(SKIo4Ionq_C&eV7DYx|}9-hsz|2nHI>iEtK+?xGsS9(e;i)h)V{YcS_L!bL9;FB5gh#M&@^$23>+yo14{GN&_99N?c! z!>%`WkOv3Ak?{HLEp}-nvDsk{MdlPceZVbj90Ms5%&DoH&iN1M9AgPD*aX{SVTW-u zekv$01eK<~up@fJtmpt#^%_3I{+GdX`_-blA1?>0k|pUKr^N=6Fzh^B{+^W=7?nJH zb?FE(-EfFA!b#6f9%LOa!}@?WxFfsPruS+ywu@(`#$B^XqvzOMk{A^ehkkzIgv^i5 zl;7Ef2WO82a!eo3P`Ma-{D-&MH%AO-!|;8|odCVugUaBDG*23-N~wrI`my-oI8Dlf zFDTj{XX($YyP6D&ZzLW?o{z-cM>K;PF1;CU9Ps%Tqr(uuT^SZV-{F zYW&hOLJTZL!%mSaM&^Y)bA11NO)Fx`Y&sBsKSO&fpd6CUk^gr?sXtvCQ35FFO5?h4 zN$7imjyLDwo~IA`g2q7$i(0(b(*L;$5vKZc-U9w`{QJaB$JcK?T93&7M(wXOtj zriV&Dg|3l40_26CDvf=vHyaTzm5-&aposf28_eKC2)*zMfo2ut{}nBjQ|onR%BxQ}yuIsDd`&^Bv%O`{3eCI@@}hQJ zdU=6l)%c|o(b8}0wIbJ}gZR&Ub5zS!OtL|}3cPh*`M2cfZ%C%^(QurI0z5Aoc-n1v zok1z!H#vVbElXTZo-hM#{05XWGb-9$E+hOM8MUY83YN5S>XXX`23kQAz)jEh4D_PZ|lYZ?)-Q=Wxm%(}}# z{}Yq~v2P=w$Jx3vdVR|NLEN5gA5$1J>J<_>G0q=J82_-Id zT9D>Ft3C}MRV|cZ(oPQum6nrb_qbsW)NR9#6bXYl1vRmH6(e1(vLQAw^ARoRL?Q#E5M z!cX`lKLUK`Bo4jbzH23b5{>e6wGSHVrE`W3K3HMP1IrNJdM7rx@j9~kuluenE@MWF z7ssxOlH+zszW>K`9%{ct#M#bNhw+7F`x=&w=Q5t-cHpi+nMk7~i5}y+k>%_fn%QI* z)`>7!Ac3?mE4->%LQk~C`nTPBXRzWAi!VKAzI{<3BbyD8hj#!2#E?+XBNqkbb5T^l z^~DRm9Qf3jqC>I64ze>GxI_aGP98@Z)5CEG;$@Li!Q&& zUXDWtppjgZZe*<9xm3nWEynci6Zb#V`}d1zuA?`TqFdu;wNO)m04v#qH)R}RP>SIP zaX{N@6NaagimjUBTkL(^C*@yTXO^b7m_EKwV?Ki{$p~U3a$O*7$PuarF2W(XzcYu# zyT&i-%iW*a<%M@OK28Ao%k7^_Puj3ZRVzD$*^>J&uxK7w9;c*yehw)(&4V&=4BU9p z&9x@qyn&4eEO>!BejTs{-v`e`P$hVv+@nb1QYb>0aYTqy^1CtFobr>zxXeWT@V<@( zRnM3SB>5B35LcQiog^guvTS2dC)B>$RS=6@<7n*=d~-_=(Eh;=vVoYb_6=Wh(U}+T zK;|nkqha1`XCu8Z!S(`iU#o3VQ?eTuz`xLuK(*_R2vY z78m27Kj-ipQC#Cs-5BRXzKxBZ4F3Pzhe?cc{izC%JXfSp7g?e?4cikzlSDn zz8xR985gS-5vQa)c3p$wC(fRQ1+LK@2$ENiKT)f!^{^Zfr8lui;B0yspHq-&8!yK@ zpipXZY|kJrC^(I?HrAibj#l$(&U{Nbp#K=PN^=$rYI!v8Fb)-exZMp84(T$wyhGsQ zS4uKSbPHXO$`%3K&?*IYg<0imz^y6h_82ok9I(qzzop4mDp+O+5_BO>mAzMsEAI_8 z!+^`1t-3M<1J^F_9Aj#AiF}_$!H|^_@`|ngk;hCP(-a#l5~RkZhte@hH-^SPkzXns zR?xm%rv9~?EfG;@4WtY+gJHQVhMCq1*9Nl-1yghwBQ}CqT7TzXriFy_8v9IIoZSC5 zeltD+t&IGHvGH9HgMKa}8x?;sg3t$f;=!b9p zGD=(o3?KK(>X{)+V`|4%j~9b-YH+`^lQSaAkB=}HZ>atm-;4&W&>19zP5D=RNE$U6 zmO;C$%y*3UvFki+)`e>cf1XC+CJayst|wS@Fw9k9$?E;aq3H_9>+nkgtHY^$pU5CU zb_4E-Chv`Gr|kbfs?(8P@hvuZLHg~jlh@w52^yb$A$ z=%4%S6dY})^>Rf*>4pP6X{h=eBTZs34~s5CVWpm#hvi;paNp~Va+cqJrf?TF) z7$)xAZ+<1!zHZSnZtEpoI0ieaTdEC)L%822by(T`l$&%eq@HIPuv6MKD;sn&DrThj z?5I{B%RYtH9bkhw>L*iRM^%zWsr!DFdYOrsPu4dP2pcir1`Q@V5Q4BbTV(&`ozYf`SRgavPcF`jRLg#b2Bw@ZoRzTt73V^h@dr3l%l3vT(w?x~Y3OUNQw@j4Y)C}JJv0GWAvMH*q_cM3A z$F47LJxMF*SJk--Gn*ie^gE#pE^Kyjlv}pkqG<3qJ^A3JdOnI=KM{Z3Lr!*nWgYyq zkuw|w0=n0~lfD`=49jcRAk`9lVf3YG3?V2$rs&%XqJ){4p#s;ryb9M;h3HHNHfe%r_M$e1Ly_92^K>Rb}`| zGC8k-pUcY8>YxUM)li{QRf@Q&>l|5^D`9oMbw9D0Ocv3BY2rN(C3F+c`2%f=-|z*w7yfU1 zf|d&e3K%H}h4g%%Fs3&#m}Tiw*giSR!5fc99N&t$;I@Eg1!!0swU?5Ub0-w7*&%$A z0%S9Xwa{2r{3ij17i69v&O^xLN9w|ags#FO>1=^EDHR?XVkar+u7z;+LX0dz>NrSH z7hTI9DJ?jB61C+)C~Cc=k<&&lk#Scx5B1TICl+50?)-%GCmM0ELR1uVA;xKD*TBR88uVl8 zu2-3lwrXyOKgu+##bVZC%enC&!AZQ4d@#gJ$B67Ii;^Sg-&?Jsu?w0iB0^erULl&` z`=ZcO^P$g}I6-Iib1su{m=L1jfmL*jyMZvW!Y%e`d}P|bJ5TZ-$s%vfdS`gx2Yly3nai)fEU@e-d}1#%SwH!Z4?{cF@rL`G1M*A9cGEpSuce?r`Ld!7H#IEvM* zzcVsKLlq1x12+7f zQDK`uTd01`Hl9T5D>s`_YRpe}W6#sAUK(vhMW8mde64qe$mr%(d`k0ct5i;i2Ta(N zlYb@^Re3^F=HSIEffEXCO!z6XlqJf=d<&U*O4U}t2TDp8pktXFPjiWG!fo0^WNg-h z5odx0+tkd>Zh8|_HGhkPSm3dtzIT8i=vqOUf$37ov*58rFszIxA7r48D|7T%;W=H_ zs1CG-utO8&q58a=&1^@U_kAT}bWaRt$002HQ&3g6w|@>{t`)^bq=!xE9VBA@($?XOvGnbTW*^x)n*o)ZEDJbLE#c9XTD_D)7}!c2Y2Jdd zZOsFdgJrf#m;Y9_gxa@_Bk3Y~ECfsfr!V`tvJgZReZN}@HV zZ#tepL}d4fRch5L^5&z{X3)3tp1Z(z3}MzG;NY@u3Rx;nDkd_ETp@?yUp*wd$4;zr zV~E#HhL&CnJ&Pwuo=Jb8Shpy8OH(KCbT}+VMnkSHbePTCmSU&<#j1dR1#Ni|Vi>8< zN75Z(hIxij6f1h23L;!Je4)JH2)vvVq^N$USl%3_|7J%I=x#1uAB(>#+&}q$tM{ZV znZPjs2r$j?IE%633PUl)vxj!l+@?*KF+(?-`M>t_+QaEopr;?M@4nSRW(P|q%*$yZ z&V_k33$D+116urgt)+0j2N>aX;RSxb_}3VWwODAlo4e~ujV4^OcSDcen>`WXASjf> zo48D<^=vc+6EZI$O**SQ7``|m@g>g9Sx<74cw3wRtM}zPg4xzzuAc$KML(?QiGNm8 z&>3pFi*Sm-`{F-Q97=hAF*htFacQ)7a+56t#&3Oc2CxR4R#`!`o%qOIvTB}I4_8Wh z--LBleuSu4#sk3-v^D>B;(EzXthZopZZCwKLMM|((D?o4Co)=zLtaUj_^t?98x<$n zsEJ!T_hr(hvad-1V>e`h^W$6N;0|Xb-)hQ#-O;U-gFv`T(oeJN?zy^Z&RvD$uiOiv zAIHG9b8mpZg02Z`2HPHC^kUE9sr)u7w| zOg;2AnF*VRU4kAee=N({2S||SmL5-$x9A_E0*rFygoZn-skJ5;GFThH$)`J}Ro@7W zE&}*-u!q`gookl2B(5x&MZ4S}ZHgl5MwnK~dXf^2?ON7TQf*kl1l-5d-I8!lQ8MCf za-$bs?7qzcpquf94F`T#%N{>P74U|_*AGIIYVtdHBsY)wmumhn^uBoQGNBjR8G(cK zgo{dqs&doQ7>})eYW+J7uf^ZrkW?R7z0+bgBD?26Z}P1hxoJP8-F^dPo6^M|E=#}u zix)zlg))%wc}xT*>!(m8d`jFp@9FXqDiSaB%i_Cq)DJSXwvbp>Ly%|;Btqy@WwTAj z7Koe%AiNUr=~*b^ggv~x$c(XZGFlmIVGM#1UWb7A{{Dvrzf^QsH;xTS_fKO3uCYy2 zf;eK#l1+#;VrjEP;FAaSQTj7QR%}Hm2g!UfCZ3(A-~E!>EKx`U<1CtT zgH&;^2dc4E&do-hU(G8B&?5#9lv0JswRZU28{ ze42HF^&L2a=FT*vKJ(C&5H2#GLFZ8yueQ+0jvVdRn8r{iTbwZw@x8cX-&K@PmRSxr z>e)3fvGY%(0C~Zb?te1vldhEY=QnO`9P__;@aW#DHyVX(S=R2?td zDfO|Y(kYJ4#DfbwvzRnTha(TUMSkGxr!Ig?A5xB}6PJ~uD>R$K)>y?{VtSi6tm9pS zbI_OEo3RW-1vJh7@6CjzS}X+AYcNmJl!OX?uEl~IL-#4`#Oz4vd2Au6b+oOehm9dB z41--Dzx-@FeEKK2zFu91Q6_YITs-0SM{_&gJZ!(3ds)W%At(8r)&X`&{|S6%Rz-c< zen>hR0xo;SJ8UKVgcfN5dOE(YKo|1hrRFtOS)hui3kg2F`}uw_;#?Z*Xf7pw6w4?= zpPdxN_jArx^AOS=xsN8?a|YS48cLQgOdxq4_v>Q^*wknynvTFZHL)HG^SDNkogs)O zmIzR;JoK0n+oKJe2>lY|0o2u+T`6LA%I-IX;vX5kIAYdzNR-Pg!fH-?{}%K;hz+q$!(4hq$3kqDvxq1<~7hh0hPK1TJu~3547SU26OaH zG7Sjc?Q{m;9`inDLwd{v=%@%-bk6NVjg;|18${Y}fD4PZmP!%na!tFZ<83Kus(ht9bJFkQAK98ofp4Y-?5KP%s zcqrj>(Z`Gc;sBpNd=aD-Z;Cm00I_(f*Y(TU#$)Pf zXQ?HQo7q#Ow0uY7za2$EZY7est*eHS4qDrroBEpsn+oe0?@PN( zz>TmPtkQi?`1{k1Hth;g!YSDS!$+q|90dPBaL43sK}cX2m$v(Ki!|Kt5X!_B?aF^} zr}>vWIZT*#%&grangT@ej-O@8NJ>Os%&dR|dPongpE~10Nvl;3%pD9WNgnvkRoJO& z)5BO%>s|1}DqKDh3{At-@JiRyk?bF5lBrWnuD4@^u4!E;!0aWfi2qgmG+@1SP2io7 zY}{PFFg*;m^oyM+_nkdq7?)GfyghLLJA%pDF$_zs`?i3Mlq|%Bz6>qmiit(OGM-Ip zgKdpRsVr-R@`W|1IZN?!0o83%WI})4Zc}yp=G5zm3rSqBb^!j3^E{PenBqTBn)b=s z$IxLNjM;YW_(w)9WN+mI5yt)BVYIb){ZbW_pso)p3qI{bq z8r86-yH-y}r7zQbcBsZ?%_1`PKqJ(z{Z{DZqgCj*mVu~B<@%QJ0^?3-FFwHy!u%{g zc3KqN5z-`7f8Fh*_jChzjl9%y%76h4VY*tiaCGQx(EW$)+9XmEqh~*_G>j>jtB^Ld z4mA7dG-e`O zH^)!){u4h=_AQ#uR9Nw?* zs_Rhbll%b-MTrO1bMhESwV^cIIW6|z7Mx)ajSBY51zZ4x5arlzg~qG8XA&=^Fry#< z_=?_m5{v0Km6|d&LAIs~{v7nHCzL2-F)d~= zLs^qqh)uwQ;l-UzKumQ*CRMZrNIIDxp~%R4QqST5C^@2Th!hBykSg)PnLwT_XF|Ej z)W3Eyu_089emnSBP|jH7C;$Fu2trdDZin-5p;U5+julH2{179Ii4%~2O~NR?z3u;^ zx5u?n=IJuzzTv2X8$!m<^%1<(sM}?DQbzX10wCpK#<8w&7c4xvk7dF39HE#fSI@?i zJH!%QW7-5ecv2?KM4!aMc)ctX;v16uv4;~@0dVN}Ji)!M3Vb-J?L+Q!1ox48!ZF}nj-5}3fMGA20OR@EB!}Jg`!15WIzeK^95=&mW2i>3 zTxtB~E2&hHG58BNl5}@A=1tZ)mEYUfkq8%aHJeo=P@`igh!PPsr_(bt$Uu$3B+@hf zLP{0pSQ%mW!$&(!=zstrdyP@!#}xzHHPT5f^A~g-$nwAr7H07+07{gd0dbt#&0vGozmz(9rT*FROX)x8;6x(^5XF#`umwj)5ylO%UX|l z)cnusWE0^{AGu+&R0N+rJpTse8-Jgvzhq34J>)?E37G3|jS`S+sxcwjYPyF+oY-2JN@pQWg*qipsDN?2)z6AFcrFGVaNk_i)MK zSn-#w^42Hj;OC!w-d4RA*;X|X3l~G3UV5n>S01b$oOk41$v3PMx`0;cY=w2+1=!*j z8>ubpbQdoN5KDIRQOHcH#b7OTuEmSb`1B8Gdh@HBLc{RT@})#^{QX$3pk@Abz0J#t z-GsPg>9-z6cMxo}wnCM_iTUtJ!W9T9RH*5ePszS;%NRiMk;o-bC2K&5cgWZRb$7r89Pl zf~8W4F&|C4l?Y)a``uv4iMXN+72E=GhRh+Ru zSa8J}hY~X{onj<GL z?*X*nu#3%-3Fu?5D>R?k)J${-Z>pTqvMmeY8Yo}x8fTQ&5Sr3fxON2TNl0ji@pSW7 zoA>y06$0%Zoqr{(G3&d^yd3$9$+o-LRnn=H5uMlYl`JSC^GpaThaurX=i<)&*&3NF z3TKh@5|6at{Z<|gVN%4mJMWr(UsAFB2bs*Kh4R1CbX6tQLN_`uLk8Q1GS}g&{|@xK!SY41sbv?;-!Ozq#u2`j^TdDazxVj& zdi|XADzl(SX~UpJC@jinJcUQ8v5YF{bH&im zDfBKYB`i6ofnrL7@4?`pw{@_blgjD%SC8j*d$iNGafi^Yr?gXuAI&=^OvjhZZ*oN$ ztbxwJ7zOHJQ#+9q*%oAsMwzuZP7eG_AHvX0+=m(`x4E<%YQ%Ubx%i>?czN=1`T~@e zFkk_UDvp_Be<1AIW?7vnvJv4VB>9N8jE2sqKWlbCdC#e}3Lcw)J?}g;qL>@ZL}C<* zowK;cXgt@w)m|q9gU|7Ds92}35SIUBf$uudO6278@>bwj7;^Vl;a<7Yt$PoBT%abV zmT#+gXthI*a3D~p{_LTVGcpd((_M7#q(npm1ii^It?Clx3T0WT&o49+$4sPurJjGg zD&9|sEdcf!Vv{BlV9ijGAO{ zuB~*_5D*$nm#i!)PK11#8iy16Qa%+E(QA5e=4H>f!zb57zT6Ph5Ke|agGX++09BCM z^?!$P_d}urO|G68uty6FYuo9^yRTNu3J&On)7eRT;kia(|3#)Nq`muytvzY1XZ0Mrhl69y|!>&+5D`h5`@&jKUV0?oAP#B1QO)sBy4woFhA-@(m@7VPG*d^p#hxe z)d7p7N4f`ga#PxI+Gh9a)J4W`0dxR{4&AIO!$?4(A2aXI9d7v=%#f zOg6deJ^k0fG&?+ivcAMjvgyMJb+I6a`>5LK1S?;Pp|90Q>BkiQC`yP9KAufv{F#f@ z)lBxBamLmI2V1@NaH-fJB9B}DTkTKm!iNuX7W*TV$R|D49sL^Z-6k?$qch%vFoJ&X zS<3%ia}m0s4{-dCMTMtNJ^gW+@n34U-cH+7VE^S)l zj;aLUU_W=0KhL^2tU^K(={h-Nf;&ngiI2hi2tXv4j-L<8fd7E1MFm3RbQG987@~pc z){7SAmKr7I_w+Jep6L#Rr1D~bSmvvc-N9!?B@+2UB`~Uig&uT^^KF@4{s zUJ;Y4ToypXUE#ChgFNA|a>R5lC=a1mL!PMmYa6bTts8bt&fN@)?5Typw!5ufPy%FNC8M|=7qPZX8y?CLFc{D!3Chg^kQLcCv2$q>)~^6UpXiw2 zQ<3wjcEj?gg1wMtlhDB{huK6+TY%=S)F4Rhl zKATJUN3K$Rz$QN9JCQ6%E6`T%P&K>_zDM86f1fB3!?Gs49o8A&LKcnB0j&u35jBB^W0x5`4q~s>oXAV_-Dh%WLU1!0}LJFl_EqS z-ld2GG+Bb&(Fkw!$yyJz8mu0uYRa=B5_nT6c6Qi#)%=QjbWl>u)E?`{(A4*SO#cq@g3wvMf!c#G2aaRabP?P5%_vC20?SFNk#e+FWD6U*u6DpOtZGA z2bc9;=_8VnTd+S95=l#eOcQ9|rSfXjNu8!)Engk;4#64$*fR$maRa>Ns*jB0TVX%_C^$s@a8H8ZU2oq2N+-s_X&mo6_V<^QE?k zhZ?O*x#3gN6{h-XUBAyPmD~$q*J(LcXAr=x(l#( zrZmY&X?rEq&^>^v!I^~E7*ieB+ZuT zx9E^$q@6sJdoH8$p4RpG=;veWZBz09q~G!&-938T5hs;qQ!xdQCz0S(Ay^u& zt;TD{8~rcAW5BGYDXr?yAwgMgG^9jI`V=~Sfn!{~8kxhT7LQ<_y(GDv#YyY_!urfo zbix(^zB-U#N;VUr8`URV>H6$0*&CP2PWdw9Ud@=ljw73jx!AscPXeWzQh^rP=meQf zm4Q4v0*_c1N6G=xO`|5nP)uv+hB;Mg6{(MgWE?AEvNG4esf~0Yw^{v4Cl*ZM9Zwpl z%_8~3@NdRKJ{{#Ng0I`^WLWDSyVUssig%1e%TZL$6-I^2{T`iFgU9vOZS!kP`hR=L zgK|+wWwgq6v2f#>Nx(^TKt?}ybx0lO_+%ppl@#v%hy_DX6u2-O&T&LZ2z83A1uTq_ znGSx{ZuNB=EA`;yH?+T&Gl%?~)5Hi|gJl_i4V<}}nqMd#ekGis0{+<`2Wr(v5G}CJ zG=K3iqRE=Wi@KQvw_ETuqR`rqpKDbX6Q8-&q~lnZf&@1G9nj&K4}edgZ5djiyQ^u6?ujh7D73;d_fH!y}Qq2 z3|U)#)rZs{7<-NF))m!3e2vw??${YDoW^sLO+$rN?)3oV9|mw-Xt4x$u4&G>xKK?Y zck~yyYl~Eak~y|*JCJzkdeTnB5)hnMcxL5Fa%(&HWCZNEHyaX&;u13qtfZ5a00L3) zHFX$$dtv*gOaw*hJJ3Sbgdc7IG}p?=L>k^}^x}A6ncO1zkOxsQ91+8Tz5ZbbBCe}j z?Wui6!9mtDPGXV+pJ-g0N(y0cg0H+G_HeW(tu^jj-@}1Vt2{mVd53jCaSH;Y^S61F zTJCy2x!G1P%rr6o-{IXY4G=P)hCn7-cteHP`G3TtXk#mJKhSVVlJ4K z4~~E>`#iJ%vhnWmp~3nWTOHoC*n5H7BYluVdXr;nN;813<<3QaZMW z+ev2toCt7l>p)tM3N$1onEk`_l?4Dp$17aqM)BMp*#IvySDIyNsm+_sLRB6GC<1X_ zm~wTn?lF0quoO{+NF&^P)ZSA7AyM4BbS&$e3%QH-ej?*6}6j*rYXJgIRsS+8H_Dt6Ht7Sj*SMa=>RM zOU?@a3z1z1eEo|5Sc%RX3Dr%6Dxh}DHh%v$S69Q%k&3TAgr`-Z8H+72#r0zHgTCNK zmk-KNo`fN4zLi>Rz4(|E8`Zl7z%!B;1BuIijKD7C^z(Kj%pWyL7P!ZK?4Q}{Oa@oI z_+6TYm*1oN*@=a|Yd^prw*&2EbPog@bvF#UX9WcWo5ndD#KjJXXo*S!AuPuF<$NKo zh{*7tKNf!Mp9RwF2~GanyWR5~lq2fIg>mJC`fEj*Z702DD4*4kS)2YqCyBXQff4)G zv`4UXJM4TxS;^*GP-{zJLtv&l{Se44i9n{P0wFzT-Fw)`0#|P2E@t z0!(R7Re#=>!aK34U?I5W&vgp2<*pc|0XCI$+rhDPP&qoE>|A!8AUKZPw&ILtAI!_(HvvDI(p^*f`9x)Pd5mhjdOkQoPgqkINF>#YRyv%f+- z!>ui(LIUuIZ10-`Q^FYQBu4bbpQ*2j^#mqNDA2oQW;`4kW~Nnjj;UPuVuQ{nIUX_8 zrX8x+XQ|!XYA~i;6=NUf=PQ7{NR1)({9LvPNAF&sgz? z9G;U>9m+l(RiB>{uTG4js}z6GnKDJ&*GQ)Wb}n+M1jYKk1q@nK zH$$?lFil=^9QO~s=M5s4^p@KIQju$!y4l%umR#`~UaR{4$gOko9z{^PTOYp5U{Z@& znn6A`qFo59c0`M21d1k_^tB;kEJi&>+B!<*YTc)_ETY{jU4Y7yW{>O4Gx#8=@@-gNHHFVIv*JmNn%&EQQ*+eb0jF1-4j1JR54DUg?XxrbC*XxLz{gT!J17}kpyaKz?12QPRsZJU7p6n2d23_i14A6PO9oe+4N zi?Ew3!jOP76`q=K`}o#|s5V0O9VkbintqSL!o$ydFU@mniVuvCITD59R*m0I;`RV! z?HugrGVL!|sKGPoG-VerG-l;SB?%gFO-AU=m+g^ej%?k%GhzFqmjYv#)T z$N@ED>=~jrXcyv=CEDZ0gcv^-=IJj>XY;^qWyxY$lgw&D-xUzVPazr0b-lcActlL_ zl*3T7cBjXOIe&Gngor}&u2NX`*>3Yh0D&7a$6#EQ)ll$XyE=#!e1zS6P*(QaB&Z|i z(i66?kGABpsh+l!Tr_Y>35xp6as)ZVN+++rH&-*tgq}wDsI16-@G!Ud_JvrUaDYUt zOvY+18*}bnqoz+8?>%Q`hMu$^iIa&D@-_yO%tk);!rkOzH>dP?CL9on-(4SqV_}j| z`u45x1?}n)&+MBtYcORQ>8F$^Zdt(KB*=G#la(g(Pecxt(#0_$={=^Xn zM*L&pg&9ZAGtB#gE`vT{Thc1-sDFnp(;u;;&Wr6-iIS^4-B87I+gH9Ac^mecb^Q3tNbUS7!VpZMVk_#c&UnV1p?&)Wb{={m4eR9cz{71YtH-fkrkO`r=ga=>zlgaS zEf=A1v7fc0gYzr+ds|tbh6g6D0WS){6dAXx-khQHY600YO#g*-j`P@B=4!^63HVIv z+4enVMGAMeQ3THS)}8_HvkX@dk*t3EY&?vir4+DxAHFg@yujVTp5&2c^3K1Rq6Ri+ zKSK0D=anF{Ya;bsTZ&7GB(LS;zFy*ZwWL>*hsueV&%8X)XHiiZDxXStE+g}@UcMMr zZ^~21sHi>Sj8J1pqcV#2ElwvD!S$icG`}0uabobaYKNy+ySK_J*zCv2yn}s& z4f}ZG(*27fmafW#UWy2 z(I7Z8(R_XrY?fmw?swgLA5Z&E2QBOxp!GN4jaCukuF9BMXKRjMkky58cahhXhzz3+ z`8_#CtnY72_Ceow_{B;OtE4uj);evR(qX zl z$bkNk1AJ{$J7_4>JD2}`O(y?z=`Na^OPf*Xzd8&-j4}nN0BAg1wt);yv9Jb$wpPV2 zM(&WcBeNAqCnM9>xYsi|WaA=l-@!#JSCb|&f59UZMQlX>G^a-H=Wa6#>kI`bTeX*OhzAsrM>Ma{WqKt(5FK$|2HY#t*?c5Ei@k^AH=1*SBrXZ zclTvQALu5Un~F)G`@#liXUW^~*}W)>Z0W@$LSj_u^_|kYHRXRI!s~CyI~#r*hK}D% z2IB_c^^Fo00;nt5vkdf9P&DY*s?>e1VbagI$kO0BuX$Ng0lJ6r4~I+sfNWm6N@YQ2 z=6Sx`4GoJYadiwknT$s(UpB}nbj6b?5!Y_YJ8IJQOQTLdTSr6_$I%%ZoS{H~Zs^6+vDA`*sZtzbN%d!W>X{Ecu|j!rncV2r!jyYaTWX%tkO{KxyE| z%o~>64@Udv!fo!$Ehstb0U&-V$)T5(XmA zX7*F01*s0@W1DOyWAS!nVxui0%@|QwRZI|K>V;JrXXLL zSLJgi-X1POhf_?PyO&de9ny1Kwq$+tc1P(CRwEUaM)+vb(|LYovQ5wSK*v1Wu%~-$ z93yzisJMp*u#ar(ucq8ldj033xxf6bVAh!ALeV%`mlKGbvrNq*4f@ zm-8@JbSDCunhcG5B_lQ~0Eds*;-@}CPqjsn#U>kRPxqMoHSy`4=^8(LgemAacJ9fR z+AUZs>UA6Yzqmr?Rzs@%Gu8diNC-t*Gbd;V2R7O4v8aKkeJv51oH+cWgyW;?Bi~Zq zCMK~j#_VXukI59ir6sm>1OJ=>u^_7XwZ$eLmk}D}5wb)pwf5(kvMRey5 zh?EF$n6OZ{cv9TQTz9gdo`qf6k-!}Hr)7(kS`R4|BXN1!=!km(!))HFYB>aMJpQ_%Vex-Qv3Y^Ze8nPPbigFYW^!V!98?k$K_Sn__#d!ck z{X(&y>??t+`g75m{zOJwll6F@f=>%+Ztk}F^-k~0Hgj{A+B_>&(KBJwl}6^qduUH&D0`Q?Zas_30&lhTns zwaV=hJa**?l1R}|n0WSAxUNis1I9=)j_)@xWfH+$&8Yy8-&%*ZQQ& z&)G=zm)^=>_$BW*UP~`7^gaVZpP@6-AuNpP8*W6#31+Us;eRTJbR^-cA*>Pi%4YYmL!qcOhV{w0x)S z2&-=E(;n_)I8=jXKaHCb&&3$bXKv+ytQ1FCPfeG?sQ!7Bfx%vAhTZ+6L!>Wzv-vnl zFkqAj&~$4_-i&Y9_!^UJ(F%-2RyAG>m6Nk@{;h+Dt&8GTW0_yH2o{LY!O6@tkT|Sx z(soA`eJ_f1>$xb@*P?E&T9sYXwSZR$`J@d^Re~TrXgXlLLX(tOl%xHWgPd!+W9!yP zuOO);G~>6>2MmLn$NuEGCRw79=#ZqTyGhhlZ_^pf@tlqS45}^6b%on&TM3aA2H`_X z!hOm9Hveb65PGMS$CymKpWd}#&`7u-PzX-r!&KTNIVr}E?u4mrCJ$4Gsr}GQr9C=} z8ZdQ3e*35##J^BBiO~r;jl!hA7IxQGW9OQHg?cUwZfjJ z7d2U^vrv-Nn*KT9*xi&X(ew-IRkRxNuxvxY zA9+f6x9~FDzw?ID6&W9`nkE*!obdJ*Qd_0=7FM zWR(lt=BST_<>o#-r9I?xEiIYh#!1WHs4x84K_VF%iFg1*(I~Fj*0gulmct7AU~7e? z-B0-vJM9YOY7Nrq>r4u5p0YZ_Y7t}@l~5U8luI9lOrL!IgbY)N@{uPP69l|gSHz); z%$2>Za>~)UzZ?AZLYqa2gk)x&EJ*uizCBT<3zOPIcJfpcBnBX9uF^D~bsKoKjL&8p zt-sepkH=zY42r|{*fr#rS)0_YW%sKeIK|ax#25=W$BC-<97b((ZYgvY=3K5tkMC+- z2^P+OYO%Zv9_$teNT!LZJ64K5k?2FWTSZ=0v2vWX)WN9OG`H#v=P`%>FAfz4ZURYA zDF%D;E$1G({sba8_?K_1^vdABcENbUsurbDM-Q}h_;Xm1@BQNfcIF!_t7qkh&p$=tUi3dclF1@r#CcJt5)@qOKaIC@|357ML z$y8w*H7-MLY_D&dMs%WmCo`chcX1kT7Idm`B^XrpF=Yp z->b?e7sr=TW2WNQh?oHuf>sO0D^Fgd%^sd*JRrYN<`eTPOJ%`BxrTqHYu9@^>bek| zAIF>EL-3L=$1)ld#kGZ ztB6XMh@$N8y2wgrL|@^RL5l-si>{?M2z||i{;+DK%|IM*UK;UXq%9yxGVu!`jX6$+ zSs3cmur_braaABaB)J;&SOz(a1fh|wki0SQ4rq|`HX&|*0HZ)kDMCSNVS*5(L}-Bu zSrK}KLNL<$s&~jTKWx>nWMw!~ZJ=$EVS(jwf{q{7|14O!_e_Tg*o#P(%sBY**8sqC+H9 z*u1?dkfVc7_|3qUq?K?Y0??p71n5$6l7em{!9XTk3J(&Eiw^mF4UYGZ7N zFc(vC{~Ub@JDDeYIz3b%d{aAyd|1cQo^SNkzkoQ(XbF7iKj_Q1}*IOQq% zcVNeBqH$2J;!ELXHT=ZdcwR05zW)KU3AmLs+rovl=j;dO!4rPN$1S{Ynm^iA>ET3= zYmRxaKxHrLxfHPsEX+O_soDT}Q#_32rmSjVCHd2N;=KEocsH@-q@XlR#&Hhyr|g>A z97kz&(r3fgsv=}1wWHonkc8+1k6wLZ)#RUF$m&y$B1BPj-{C+3ov>c~g zsz+nNDp)<Eav-1Uk5BBZ{HKF zZP_a7`nQRXwO=7DXgba}Cc0IRGGP=1x2__(kpLV(==AZ}`J0;uzG5GpM&)n?$XKt&+%nUzH z%_7YaW92AtTJ~#NXy<@d<>A%yfrLWlfJ2&cDAM6?DWcuE4X3jRD8?k(4ea1wAtX}2 zOP6n3=Q*uU4Wp=LllYF#Q{Cj*ll0^=Yj$LCCY?8ctCBdNX>q8X_-)R zv&Td_$FSqQo0;QUKSDFiM-Pjhg++?cXNJ<6Z%c-3JF8q>CPY}xNQ>B9JRk0!t^y)a zu!SBELlL`?OCP%dURn(=nEeL~)SmQPMPUX#Gg1?ih3nN{V#P6vjceRlFV~!4Di|yC zr4i$kqZZ9+d_+%!F&JAx^_Dd`;RIsN_fm=@2 z6?^n+(;vQdHFoXaUlG7h_+i!!AKLoD>#h#~z)kH@AIOFE1S5+UC*H^b4M0AVYWMbf zyQS$+Yzy)Y=C?;e0P8QjdM*|QZ85VseTP)c1e4+(K){v)$JWQ`hI6pHdjhTrj@0%b zAuqwFrr?<&FME!Q4HyaX|EaE3i_!-(|G>zS9k-LLCT>V2bAm zQcs6_AD{y|s_mwI%^wJy=a4!=cEOW!-9u2ml_Of6;^tQ?l(zj`{fWDb-#IqCN80xe z3V)s`+?&22`vGVK>>t?`dZdy1_Ny|IZbpi!qUdar%!&GH?1z5^hDcEOL&x-!o;83XFkglO;9}z$@N@$-$dKaX@ zuU{(%6Wju!V(whmMo<8gm>)y{0s?C%6_*o<4?%Qh%)MO}6+xRgaX9bH2@x0t!jNrC zbIPxxt6vQt06RjF$P2@5?KoV(_KWvac5Jk-DT$zz9p*{t+TC~;x~YV;SXv>v2BA0De{3t4!Shbh zqA&ND!G5_nzhAVtc4lcay)UtO96bm{Uzo?5_BLh$RX?xeKSYg+GNAOforMJVF5bnc z{2wuG*1TJ=bQJ_Z`s*`p!vB^Ktb|DmfFZqqm7wRUyE;hyGSjc7UWeHhSxtBtOyUlx z$#%LaECaY1@SYwDL<-6Q#4XOm2F8ij@5W43sY2+^Mu*XdpuJ66~@#DcW{u%e~ z+@ZOcj~Rp{Nlu*o!BfR?>L$bP?9MVCUNkF`dbmhqGYxU*P11TRre@O@05yEW3y*8< ztWfi!a>^sr4tRq>#+*+{>-7zkW$OH`$aQ@IyXSVKt9IOt( z2Yx`Vp^T=BbDItJS8@=HICuG`5B>fg=qG(7f&U7j(L{D!W~W#wC)VxPUp%PrWv`U= z8G4I;zcHvqo|_>Z(5O~mR?n($wwVzzw0ghNaJZ=^+VkOn52x~I#FO|zxi+AZrF3Mh zJ%wIbsABVhuQ{<7%Qj>h1t*GPJ+gk`p!?3!>o>lSep6@_n1W~|G>cL#<^Fh|``-2@ z0X7>yb;vGNIjzK65Y$tf(w0Uqmu>0cY2qrb@pA<0s}c-hE%BZ#62m+Yyl(HY`EPXL zsaphFl%nRCxl^#k=Q0*Ot7+x@&r*yhSmh@-_Yl7z=GmI+(mN_}Hn}-+9 zvuSR)moi5!3P2%Gyy2v(QF8RmFm_B5V~RpF3x?ofEz^cyVsVUSwksn-NoZ#8 zH~ZXshk=|KJvSAxEbyr_=s1$+7T`l7p6=5ncAw5rcak2#cbcyZ*Rss>0A zX??Hh=Xk4{ztCxc$TZl-GI$6%M8LynqMc`W6tS-zK%{ao^&91QJe*VOkCaV znf~6V2_AaxZ48kQ*()wPYNj&knoPutpl0;ahO;iSV<)YYQE2y*a)6grV#(q-@xa24 z7qBU?>GAKs_pk0fGN2^z*W9YOpyoI$QOeTd(K~$8={RHJ@1kn&6B(Vc>29e0aG7HV zqi>_0Mi@igY^;HTM!QeB?ZVw zEw^Qa*V}{cO|x!{a_$<02U|Vi2jTkm!a?`Nu8Q*;4K^fiAbRG7zy%%N`Sp1M{_^ch z*f^8sOdeHc@`yC&yREwPbR1e_TMWtE8x(A;*H|=%(E1Ejtf<~~;tZ&M^@l@q%d#&d zSG<>N4zS+r2^6UaG$UuLzu!u*_H(`4&#&%(hIaN3y3-b2JelKq(G29)^QWeZy#uoP zvZ7^RA2!R6P}Cse{gC^{CIgc#8|gACOp|L%W#GS^UZ4>H1)eqO#(l?07P+&99H(=_ z@GG1%mica$N)IJa0Tsi=yv0W#YK~eyii>g|9>|8pOHuhaSqwow!>fJs*d_!VoyZ&w zG@_PK5d97asy5~gGc~#Yej^46o_1tdv`OR70+E&^W<~P_ylD4K~ zk$gABL=WZr52$f-a}7yg4-Q-ykE%9ob3nSdvA6~O>*cV2%O9pRN(Dy1)F;046bCjS zxh-UgQnNr|N~k{mMS;?3K&i(#JROh^Br&_4OX7JEGq70VQP#d=jj7|shd8oUpJbu{ z+RU%kltf2*%?oYVfGy#hd{NGeZ&5>0KF*S36v&~RKEzIQ>JX3mYXUBFG|#+#Io=bIfdR7yXY@!y-a)5@nh%R97bEIrXgYf8|o}X8mfi z?_iv8sulH@v{^>PaAV>%nP|Pt&tv{5ebC>s-V5G50?HS9^S}|Ze5r>zt#O20$(H2< zyXxb86*~TpBhyrzE4_PIy=zlVL;fd6;)GSefh=_wf8 zDyy`VjXh*|O{`l&H)*kxnHMcwG#4<=o~WjQR*t#cs%kY3S^IrDoqgNe+--R2bFdBZ4xZ716VvKYM7&%9#{SFs1~8bw%`Soe*LV_5mGz#C0lm4k^77_)JoImtX9!S{!;vDuzm z`FZ?SF|-)NoWJEwFBSKfCPn=D*0`Zom`qWQ5+Y{U^&u07ccO(rO@$ETZEzBc@{c|e zRt1yj)WKJvrmRk3C`*MKSYNZw?*V~a_sG*({my9)j zWB73LWBP?}ux=;f*1>bEvU5e!%x zEb3Aa^wD32LcyBFk$}u%>n_@N5cIuvv|@w7H{xX~To`p|@@}xs-vSb8AlL7#PvvRuZohQO06OWb6qI*SA^2&ipIAC!mQkwR(j5J$u(L!$XLq z8+vzFZIFl4iV5VF_9}E5kmMCjO4TZiWwO;0-cX4h?9LTCT@K zOraDu#jzxJw25M{wW3Rzzg0MDL+Xe8cB0Gp3868JKyp;H|K{3A$Rsi<$ zpnr0Ft8DIQ!xX?2(ysw8qXTT2vD9`F>Z0hDxK(85a@}=VfjJyA-2^gA>yyf>So9Us z?nsltQ`iet+qy|buROzxr&Pp3)`bHI8UX_)LbWHfNahzth|v5Hg`2m(vdJSQWSOPP z_>FM2qd6qcN~kw)arj6vznJ}Xs=|oImE|-6(5$;FA~g&m?=`@+$dn^14;4LW9O@+N zG$WTY^`8h4o~Gw5kYZyWjVAPKb>l1bYbHb*?Z!umC%wT&TsgvfeU_xVZhdT!C(j$K zKawovJYZxqe79FfCI#gy#Fg?g#7$;8bjtjtPpT$TI<2XC~*|+kU8F-d7#g>IA8E?Z>63{pT!rNaX37-x4{9UNzdD zTXHxuAw7s8!H!x2BiG4Q;;_TNqRsKay8fv}{*x2zo0~vjKgp-gt?usC+rRC)MX?p| ztsT7Z8^3*6Yr8K3fPLOD_oP4#|Lk!wMg4NZHnqO^C2JpU{Kn%-4dVGYw*i*@B_28L z>>O1Z(sAH>hwPCPib7hdVJPwZvgiS{mgLnO-fSZP*WVW&4|fLL#CU_}m&|wvU5HGSnr-dHt~l01 zyTMQLhZ%Yd<=R>0@F0-~{8FJ)C$4e-fVy&$5FW@PW!RJBa(1Kh5dM0ivMtd1e+lGtP)^6+ zDjPpxv-G7xaXlRD_*^0He%k`!%HCx2F#+-ugP98TJ-_~NA28V&es7>Qd!!4#_!oST z4pd4BW)KYy%UAaq7Rz`GAyIMq90Sx+AefTCg)YC#ERzU_;cEbfw?8Gos(z~?gL(VA zPrpNgHfhW+&MR4Ef^(#@Fi3H2mzVwGL3mG)<@?Gt0Jm0|-d6sP!zP!%=1E}XS(gD+ z($v~IXZ`78I#(hElM+nTefHg_K(E=|@*wR$t#ROousRb;nfxn?z4xsaHr;7JDU>?in>>*wQOyTS10yLk6`*)TMV`C-6`bpb5V{p18 z)r$~ha9ISqm-E&>+ZqN>pSxP=lF9^{PLmO&2!PI}pn$D=)) zwh8So0(=GTay5=ZGVFr+0n>JzAsOAp_2+UaFETJHG4b%liIo;N zVnJJI)OGdyvZQ0hDK2e8BkJfAnRFJcWn`P`Yqr1f)Oai4(-TbUUGKUa{9H|eDJ?8| z&L^Y2k}E}BP3|7@>&Ycnf_j1TQmh;YbnzgL9~NwY1Fx$23xMLNs% zM_^KSmK%pl7J)a{!O(}R=6A-~Wtsbe%WZ)pLjs#eVThCb-GgrY#gz4+_!2G!&Vjn= zDnsLZA0LCU(Qqh<0OFAhdYQcUzO>fEgDWL4)l~rod}rwE5h3vKb*P5J2n6>e6SvC4 z6-SeDt^mFZf~}m?a&vQ8Bv&gGR%PqTu}0iYw9%@%%#AWI8)NJk^Tj(hH^|k9j>y)pj8D@ffCX90;QQDoJ0TMCqn9vqXyyYnlK@%{iEC0;zC z{lRwenUI2e*bK4=T5*oX7`Ib7CTLx*_3rD4ETCX}=-zYs&$If} zddy2|@cR8H>r&&L=6o4q-=6cI%WV|wR|p0!VszqfgVt9!l|Q+ZCkt6No-364g<|to zF0VBPkx7Q16QJXRq2tzUF7ZrP@4@&lb{5Dr*40Uuk&HqCR>&`UdM})!)!4dPG;7jf z9Z*AK+%?v^u_UT`20V8s8gJhP#kQNu#mxMq{pa@z)gpIYV0YtHw5j~4g)GPyNw4Sr z*EH^+6i0}Ss6aWk%1n^*X1x$*3ssj{5HrfKf;CbUi`7Y(kN%Qk{bR>$$deDDAxll8 zzA2z|`U*j(tB~iXYq;`nO0aE_(WtlkA3*__DtBOM9?8^1hZ2@d0C+wyNZ~8 zI*c)>rO^gZY?q?RpH2`2fW-g?G$bVY!cEpT{h<>^yz2}`UM?KE|CT?*kdg}P&~xCk z96G%gEtUDGv0ZR(9c7-6w#l?;X3d~eDETbiv=`9E+6sn6R$Z_K!F%TJZX_KTt&tx( zdP32oE4kukC!)qO}5aD9t=H0R^OI0iEE%j8;+iGGEF1< zY9$fK$C+5LFgcZC{{1EN&Pjwj$tRpqB`);Fm1@uuko(>cw1rlF90tk>OAIu!_d9Aq z5&zG|+Wwr0t+raHbB6ms7F0irz#BI+e|i}-Khh6r&q7dwA86IcPe^lI5Moh7)j?qf zabWdMBd+>Q~rrF;hD2_FZt4fMf*4=F%)DOsW;gPQDm24Pw7 zx<(~|hK|^AEmd(zwVVjI33LJS(s)o`*licoRPfbD9W4M^*3n6+dhUJT`{2-BzN6=j z2&{1rTv!`|8#mId2?ILC);>b!*XT~Q4F*a+GhhvLn?Ct-keISDQn=M7jlbu9yWvQK z{WE8G&@P~0;bs0#F6Uc?X;%PjtaN5rw* zmiJv^3iX@*aRZ#^qiSWUZ)pw^XraC8JY51?^;RDL%x=I{A1_W_7ByCLoNkzvAj>!-f|8FuxuvRJqa_T>$2 zF%P}P9W!p1GIo~7SOj+m$ugI4w5(8S<}$veXk6dM@mL|~Pyq7dJ zNtAJ-r*Cn*<_EjBn-{PEyJaWAHHxbZ#NBZxom%T9A~D5AZhU;}OKYp-?ZZeDML4Yk zRFz2XFaZ8k?yU<^*I)jKV%X41EnMr@ndnd!_h>=e)2c96wQ23p13bV-AWB%84=%*l zE$!@WfY$wJeTrE7^9_bKLf(Me8HSTYZ?3a0YdlLHW@4(xu%46`qh%QUZ_QzI{NX_s zIL0NdAKj+Z0IBLW!2{DWh}+t?$CB4yUmgHxBYq614aJR(UoX4@3HiRb(cY{Y{2|+K zn}YjFL>k{n0g-b77L~)6sXFZ(%Dd~`1K1?j6O5hdBi7Fm4(_jOH7A*-T}zN4 zRdOKN`n0bo28ltp)O;w6+nAI>CWj-RG0bd@_pIsv08JgS?tja!^q?@eY&n>=i@%)% z_xP1Q=GdZWIG4Ix>(R}aGDX{@aglZenQ5mMNah^R(x?H=QS8cU#bMXUmLJdsH4|>8 zHf^-XUTrx7k(_zlyIy7%KeCoe_3UjF8h9IckK|Bm;AF1_?|mS_pDB|IgtV{2ST$?S zk$T<&4Oxi@a^Gh)LoTg!PAs(N5=lc{r0*#7*`|~$a)0+6lMr|wos9rD|CRDO3muxc zM?RE~cr$%J8R`}jiN?7gGf4OZkp>k7u0D2O{?2Us!}G+l?BmPjgNd`{J=O~)wx`p1Ta7=xl7 z7L`E@2?UHGne?D8nRd(1r zq%8Z0MRU!ceJC#sx7(9AJ~7%EnqV!$&}f4U#Ap$si3_!K2Q?9C=z7fiGx1!F=ffeF zx;3sIT`pymDms19-(_!oeY|J^?~?**LjA$$c~1A(S)ora0*{i(mGh-xHawqW1C(yy z>c^H_YwP9(@MUv}MzE|dLq~QQt-`=7Ru6llG81@7`mxm2zp54Pq~xV$vuD|R!`gs} zK!r}C5lSj(@@-4{Rv4ZT%lAEpWc@}z*wQx=0_TBVVgA=zv@0&$Hjev^S^O4SH^X7b zStLv}QStt&*8dsNyKy;lA5h>a<|FAx_Zv78Ysg@{SyZ~zVcZ1*=KfA+?UQ|b>h#Tl zs`(7ew{n75pXvj+5kfPYyg~Yq$`E6D+Kf z^QQJ-t@y6g^s*QUh%qHQB98se-_A-S2%hhNfj<&syVm*gkJdH4;eJ9*=@HNnD4vpT zSijCJyd)MDM$OI|vVD3FuLtNbzp81?C9L2ogbc1AU~8r^LhunAR7~GJ3}7?o0{XxU zKrl3iChK3W!17V4fN~4?*AyDh4Jeh5{*E1+A_)e3Z}Jc~*8ek}!t~=3uOjCKTo1_y z%d1YPNcNt{VpvWypzf9*`Rb>DzbO3V388AK9LN)J?vHx`27%FsZ(XC59h+)BM!dSD zVWv)^g1{9u@3hj()F?Ljv!9)KYl9O`dQ{wXk^kBr35#{apQ?{AdLt(Lsu3V4T@U^R zS)h?-T+OM<0Osd_2qbJ!`9pXD7U6T@<7g%nFv#V-_B&=oLEEWm4`-YTY?8q#a@sDh zVJqc|Sy|_82F4Dy`qocbZp%PEx_zAk=~)V+`J89UC73ui1%A3#&Y25y6r%J`T+A)= z()q)OEuzKBgQO-A%AiBz^>H2QztaFApWz~R-*lAoVC%#(iMW6kPU2i zd-s;WOI=)+SZY54a^sGjsamXn0xs%#P5IDgSX-D$9XWqk5lfiWtnp6s@{cc2C-3L^ zz&l|?m5aoS)OnVpb_~a0p*{5;eB0elrG)WZu%!=gd(mZ+>2iZ*fa|r%#y%Xd1NH31 z$hvR2ixXk*hBnFs12;z4CSe!gt4yFkUvyLCMDyjq-2}#ZBkQBl1_Ov^dw7x~EIxLq zcVmP6AaUE34&uK(^C58g0$|ofK>j?W>!e}{?F48v1k+c<`KX?%2{9-)3)kVA5;cqC zVrMgZ33J<$LD|~AJrISLkKmWHl42JQ(|Awa@jIX6XgA)#YMf2^G^{+W+2N!K`koyM zyI-@mQN%7GW)~)ZLCiP;uaX_1PNyLS{cJqI0H;n02HD$1-rqDwqKR|7#ellbM0P9{ zbZ9>mzEMk(n$}9uoH|&op_)3Om)XHxz%3#yx;itu{}S|<qWOao=p#Ya3*94YB+>`ZYm6ku)rhbteJ({{%38ne#;gw(K1 zfCP~+P3yXgJwAB;w3@u0W}X!4H!IgrE2Ehv&QiBb?0Et-CLFJ^m_tl9KpaVAa@&>X z?tqxV0>&*XOk{?J0@^a&!9s6v*=HNQ!ScsS3;={Kx|WQy5qyNo?lTZ+^Ek-HVG2-_ zP2<5ZizCe?TKGH_EJ}4jO|hYpYO3hgZTzHbE2;bx)cDl&=20GEtS50~s;{~K*I=?D zQYkwx0w3YT7GA(3--3Hi`=IN$9|Cj(jXvheLsqBgIUldb= zKtmBy+LcIeHYKP7Qo1~(Xr|%IJTUT2H86NuNMsACJToYp)Z^UF{7191$+Qmxd)Hm{ zGkmwc{|Y~P+&q{WCzwt@>ep?C$X6IXe)n%!r8yc}xME^v&!@xP7qNY9nW-a4Gr$R? zgOc`QNwm{ULAf#Idydd>@ki>!+COKbnnsLtx%$_eZ0wS4OZ8Oj9q|_f6M_X&lV&&f zTeoFO@WNb@4CT+tMQN^gD~{f7S{^YBiT(cpIX_jwmgQKz>BB#~4E;h=g6=(Wv5TlD z>5pU)im(7$qpzBOLsCuvs}xV-$P~Ok4tBXsu)o*8irVDQhEA!ddoLgN@ghJ!5?uRh zE1^%VCYd59Li-rk1a3#Po;dk=Kmn{DcgHKH;Vu`MU#>HdSUW)%BavFg9NxVJ+>2)W z{$wd(JJ-BbrPt7NS(#L2FiFV2UYxpoz*Uj|B+2tVTXVi8OX9uWi2|~DlwhFYhr6$w zvT(kQrS~?q2;>Wgq`!@{eT9M!i_QuX)}JxW4`ah4EZ;(j2aU2WMp)6H*DKN8#D}Tw zFmt7vo2_q<9r*%biY%9(j@r0JO^G8?8@K^_%7z1Nb*AP3e@jtbR%8bmCx%*(8)vl? zM*ja%VWmU_aV`cqEsUrflVNm5vDh(}pl6*DK-U5L#py(Wy?C=H0sz>m5twztBGJuh zla`pkU)f(8eeARbxx*m?Nnc&l8S|LVaB-J$Q*UF(fNS*dgYQOg)0@9b4&~|^BB0Bk zE~ho8kG=--1^JML!a1&Mp^!YRQ(f9%9jJ$q<+uhlB})Byk~=CF39e#B*m=IOH!{D- z@~nk_atT*0@ghH0*yt32^an%C4+ED3a!d=uhDs2}d9({KD`2?>s(%-l z@TU?JELS!O5GBOTe?5TWUv3ebV5d?jk#}uyMlRw?)h4-z9ws~YgRJQ-5~+hvguladpv&-TFH2= zf@&+*4#un)dWuKj9=nW`0;{QI4*gfs*xCCc)5YefN}jPmy~AlgUO4YZxs3n0u800o zvW6 z8jK$q>!3zV3Cso;GQNOqS|-l{Ka=+WH3+!}(E|Yr zEQcVL-VYEF!9bb}A`Yr->llV>+1N_>-;LHk2g$j!>pePHA`UrMjn=gnq-;X*mm7`e zf|<~@ws?JGBRhEM2KD2$SB5_*$j~^bd1=a0m6>Q~eC^yI$4Q~Stck|dOIJ!2Cs=f; zLeZQg-iINrk9y0jC-(P6n92I&MO7#k!)?!U8JDGmcqbDeWf=pfd_q) z6?>6o_btSAp^S8DlxF5?J~_HGy>ZHu#5!^7)G$YNvBhzakI;ckG7%EuWxzb#$cWF= zW!Y?iL*nghj}*a|#c@-5uXv~XF_~dIMQ8sPgavU{@nWsRB=GCe^Us?@;D0S$?UgIh zdJ6IuiH~t3^Cp?dPUP1ZD7IjjwQ!Rm!UQNr`CfTg$YgvFpwpz)>~=tBiQ7`-yT+_1 zjtyY(EJLn&OCp}hcHf4#m>Q_vb|I3qEC>s&Gvy*1#|l2FgXr~eTW{2PW2#99R&K{Q zM)y;11!5X4%Cg?rh{(d&Q|8a4BkNKu5B2Q6C&v@00zCp`#dHIt;u!DrKypfdDVYE> zbbEB7U6~qZ_0LrM?9`I=n>2OH=-wj}1BlH`oJ_@Ad90pn*<$*gAde*X2D4p1jtgU% zXJ$Pt()vDRqv`qGy|-Q(2_jT4B>rc4l>Xo}6>M+-QO7g4*(mAh7z%~e0;-YM&|`Tg z@-}iU{8XdL#W#agZ_t2S`B6vzOukj~GhXQd+W0oaj|jQLxvz@K!+E(12Eq{0v@cYE zJ>0&^XmrT&*e8j>1H_$iSScGp9v0avotdSx25zX@;GE;4!knzwapJ!eB&+Qz=vHp6 z`;;ZBRRaYbs6V8UtgWLUP)RE=91|zFiLmiF1wN|YdVp>-<>dNcBY<6_M8}eD-njVx z<^Q-V<IS^FKi(w2ndKLdP!l;`2~CRn7qB>Ei&Y9h zx#I8h@%lGL01w>|nujmA2neW*e6cmOF8Ip~ym&f_Ga|Vd*{=Xd{Jkl21qN{>t6=g&)&Bah^syNR*6DD_ypaC<@2REYKT}E z_R6OU<-K1x;|%KdGBf4OJ=zb>ffIpC>~1(t080NS4J*$wa&L9T=!$S(O)M?CBz36T zPQKlAVVuS*x}BN++HV4hGN%z$KVZ{tq+T)c!&dj#u4tSr(%Vxqs%#5QbQ<|Lgo$yW z+HTc?btp*%bfF4OCDUNnNFpN^(Mw}I)meg$AU2GHRx=^M6XUSS34n-G$s_qBfX-tW z*9YDbPDkgeqZ6uXQ>}DGwSyK*mwS3%N+xT?uWMTlJYkVQL~|EbaAQsR#g~ZZ*Pw0M z#{t3k(7^kpwJc^fJU{B3cm^>?P7W3~DHsGh2abB||Nb~h7K>pUnY@hR{IlWjh z>g=M-U`|P>7SpiD2J&k2WNbj_bC_L`g7i`PK?={ zmJwhuS^%utdu9Hvj8XtmeT|)AH)J`IlY$u}s@incg)z0#7r)QfQr<(GpwiHFJ8s-+ z;s20*qG#+Oz|`_YpY?4mVf9)*shQ8*J_Qq@T3=~pk-D|YCU&)-Q%oYcH?94m9e0YP zAHQhnX!2%Fm3NIjR_Hq*I&S(Eq)?qcfLVyF{Tk1|;4d@k9XW-j!2;wMD>AUfwZVxv zp1{q#b>y7@xRSPEV?UnVyfQP`6Uvhf0zgh7(VGq_ z1Qi5hcOfXtJm6~Xj{D|X%N*AR#gMg3Kqq5MCJ(o)Nen~6oz3eg zoX-r39m1Ze7?KIKPNCf(yHzsfZ}!&oXb?TLe9T=1etX{3w}bv-~^2{U=Xf!m)K53)%!22PF)QQq^5gMsk9EA25l+bVP%dNX&>+< zwo2;-uxj2n0DIwB$r(6gQS#z}>#uB*b;vm3Bwy(HL+X{Nh;bKZXXBl??*v!!);APf zO@LXwy%O?>@AcSLi7q=4wJ2#$pB1!bgst~IYxU-XhP(S9aFKA~^0LUViK(Rr$0|L3 zh;$yx1u-V?@!|G`Do{1sF=m(afi2>F%){qg2J4{9N67hPN5X`5Fmuxr=08WUqRMUKXM{!?5{Y=X2!~*~K**YtI>9K)s=k^Xf1(d=f()oOiUaO8 z(G|Sqki{JYeX73BlCl1Cx?C~h3&f*#3j@O;Ra-kPe*oLmD=8W7HTd4>hqZjbNXp5} zL6jA2A4bl?-Y@EW_i_uJC8ejCSqgT*7db*<(d3*S7aK2KYaXI-Pc!{q6^G$TX($aD zf}k38UvSMgVs}<|eJA|HA;&iK+^4p&j$*(i-$!YeQs^fG$Fr7T3M+b6^51qC39*QK z`*`kyd@WzIS=aARxUC2NB3W~OkIOFX9z<(AS6_l=g5ZiWPt-~QM9sI8(8kRBwf2Zg z7HnB<6^Zz&a0xK)cE!zbvQuO9i9-~_TRm~b0Y~D{B6kZrMSNYT+3AlQ;jpo2+3iY6 zuMKcEI}LQAL_%=~svW>L>dLUdh3*JfeR z5B+=K#XE*3EfWE40;NWc08TpBd2ZcI9DN96jtu&=QmL?A^}iUcxzS7Qh${0QKFL+3 zZFG0HJ|Z;8V7U?CK}&(-=nQ$*E{pvd4Kj}K5b=!XB>9qIQ5^hBCFN3qR>^|S6ot>O??Rw;wyNI@&Fy_Er87{bf0BB zUx?}bOS7C@DL-n=9V{e^t-1?S1JzJLU`BgiGeNIH5#S>Yx8AhEUT<_BI4qWneGPI0 zz-l{NzJX2cTYU6H>0E3);N+Ih9{mG~;~f1QHO_&99&knrJL`MNhR*Go z$>Ja<7ju*b1oidCEt}M)FoFi?2c!a2lvUn+-j>|NZm0eSwqNsg@8&Q`;w02LYcOn3@5GP z3W9~AjpdvKiy$#`7-Vk70pO=bJ6&kkvM+IF?9PA|{fDOAj!@I)Zx;B2+XuMj2Ads_ zvP_4|*2D-Li%a1D|HOs1p*IF9Jx8|sn}%Ui2-l#B8F&Fl5;8>-17sfbsED{d&yj3o z1-&Esm55NZTv%X$xf)v%gS;V;_ldj0Xb(q<=tGF)7xhU;3nloN%{cT>3vJ8U3(Ow1 zo9K|7D)-(SSiYeg6jH}sE;=jlMyI2Kj<9=`(3#D)3)J!E1ndxN26}!srA&B zsAz~%@Hnh{!;#6S(&wnn6=C`aSFlubch>Y#VOfSrar%cSuBPkQYpkWY>Z2%E#BMwZ)o`3q^*?? zVbh2yr$fs_CDHPG{PoVVx*z0mX*AB!e)-44m+fAa$p;p0+MGs~geHaCbc?!-05d?$ zziq7N_?C!2(d8NWCpNI?fGKjb24@((uCOzz1D_tdTba_vKAszJGWYx@oqmJu;xv7Y zeIxB%jJc^Et?O{=gL}4%w>Pa!BAyQYwws?Rveeq6=wCo&Suq9w-}q>W%tyIXI8E93 z{#sR5^#)NrE|#6tGrS)~&d3H65^yhrR|_e$K#}nCm?7xHkonqYH*Gbz$CBDX(;EOr zd1tz@Qw57205uY}g9r)<nOfR*cegH7NY3CM ztmpZ%)oOPypF!Us)a9PBUJRY_h!*)Bm8hY7I%$>f(0D36>p{6CqF6IpiO-UNca=kK zzYbQ0V1;oQ8fC40+?aq_iIu>7{*%&!??c+gLnE;ej~qz;w$zvSp=UKd*tnB&2n~Az z^s7Jgs>{XfYZ40?`?;w+K`_hbHDo)t4SFh0A`0U5=xp%`#G{3l$XT7YIMJzKkAbN* zh7G23g)+S*aLvIk)jv=bymIx0$TF<(f_}ju2BmvJ$dz`|Fr3Je4;B6ZdpXfdPA2<{ z#HS+63m=Ax7#uYQ-XBxqW(b`PRJFOi1+zW0`4%+H>-htXEd=eh=f3E*lwP21|NGd} zN&V>bWas56kNH3$W2gNBtyq&dEb!}4{}*{zmDa3h^&IoCf>H{0bl~up9I{l@JzSks z+Qp3FtzUK!s$b4CZ-pPLA1!;A%LoW1L6u!i)zlM(3Z^G z@H+e!k9%*~!~cemlL}!?SJa;)(caSR|Ga9&3{5J!*Zud>*p7zhR&V2RM}qraYteyK zBXqiE8^^*G^kN?; z5Q5+Le}4`ZcV7rFxIz{-dBhaLOwfSVGNq)p6*>2&F1$k0nOqUHo$~vEoZ2nt5VUyx zwA&}HMKNN&Z9IEqvIjgJdYV`SDJF#3vuv2)t$fkf!_Ql-%yYOx_N$k}>}At(bXb{M z=_;A#Uww{p#2oEqDW59eBZN&l_WM>0U)!BN%Q4_K^>!^ANN+n|`aT18y$WfiC@JKfbx^A8gxRq zqR^?iJj*Br4

iKb`iN;*Hg$`3&mhC$N^Rk)io_kjvPqyoF$pNtr9Yij4+JW8n&N zL+mUV=Y=M@a2kuYQwI?gcS{Kyxsf&?dJC-qwgai9w+m*rZurfi8!f&Y!8pXbhXu+K zKqO8SJVw%~Q}_Fvk*E8BSKIWS);uO`Od4k9s0mI}&3({vPGzsjvs|Fur1%^l<~xyk z`NpDkx~)*OL?%!>&m0ijYxl-jdYVem^Hy3R`dG^Dc;AxW5U!bY`TW&|G@?%?16&8; zC3l}^?&%sP=ENJB+2Ws=CvhwnDl-%1&k$p!QD4fM5RsGYMM@0L^pLz;S`txkripF2 z{Zg-ObnA8HX%!Gz z%B?jZ^!db!sjj6axSz4~Y3$hj=<*FD=P=xfb^5_A*lQF8#PO z5owVc9(=9~i7+M~y>hqlx^sP69wBGA$ZSejX_XhgA1mIQ9@>8JD^gK=(~hm0VFD$l zs;Kq4Bl)Koot8v#aQo3f#}oR{V!R3By{Zwkz01_G5W8@)((5aEHUpaMr_~}iVE_^4 zZjo^}m|miyMC$FQsC^Wbb{X7JxM2Xh>KpFnYVp%wp63@7K#t*95AQe=XoNXwL8s9d5-GV!N@8QvmaWCEnvEFXTacC`NEuParI1%LYj z++x3KeZG2GJOxXQQn`rse}qPnm+W=zLTLiO3~SMdi<>x%rt}l`#h4(sh->u_&Fi@m^Mq5K1x!B3x<+Uqx^p}G!z_2vo*46x^ z>(hFWLCG-%q8Hm*!Oaoo(|Op2%!0!jJ_X!%)h)?FcPZ(wt`z7Jf=wkM)0apl7o$)R zMGO!U7XaCX5#;6#5#)`dGfIC1%6?!SCv@fQ$;`kkaWC%&5JyVlN8l6Z3H z*y#$zx}|Osyv-M$ZKa^PB;1_DK+%$v=p`4$talvo?3g5Br<35Jiqfkk{xO!=+qbJb zvGaWivn+?wbrw{z&%n!A%j@rvY}Vma?_U5F`uTk~f8mZCVvDjOu>9uP(F_xEYdo}e z*zWmjSwXRb39`P+?*dv}=JgH6P`Zgi8~xPODi=eVLv$UwZ_o8Siozuw|N5u?5IPEy zu82t}82m{RsD|z*I~82&kzBRn$Ix8e2Ba+#&2K0hO$_&1SN>wEsZq5b{QdmT%=kk% z%X+)e>^x-2U$lM+TB%lf@e~e{pm$b-<7aklnI3HX0=Bd5QyV>EtBVl*>bBX@rSRzH zC2eFop_DYVPanCpQMEd3LFn7`0jQF&w828Rgw266t8*s@2G{V_#5M*dH-)#XynMOF zvDntU-3!Vz(i6p1Tb1%6k$%SFSUI?;(GQ4}b>db&wT%nKmI&WF-wLVH6^B8!M3!|p zCr~`y2O-F3&26hQmKJhproG6rh*;V3*#aQBS@x1{`%b3)9J@;&gom1ivb*}XA`Wl5 zF2DwK-}J($tdABBX%j|?p{;Y{<_Oh@eLj^X<7^cxB2=(tjj8$t%s8KcY#G%bOE5le z>~^2Rn>&wALge750Y9}hT%^lTvayA{^$77GTl>GZhWN(b4@b;wXx$fhuexJRX)D^N zBH%m7*|@YM_GS1Q1EAi1|0C$CA|83&i!5Sb^}<;`ob~Qf!Yk*?B=+x$s?x)>zZ}L- zYlNQXv4v#kBsXC>68-ghdh=`)WzL08j`3^9-(2#Lgx>COLNY}Zd?_hl#NL+h}V9d_*G z#afrk)51Z%KPyF3HL3sNrRfDTTEj6r~FIi}l>(tMqsB_V# zp3=Ppnch(@0~SbusTK5>df=7CeNivm$HFhvLSg{-a~tw`PI9EW+%N>!3=T9~jO*7W z(NXp+jzqRDqm1=#Vn*NfN0OtWWpD}=EmQ1V>b(CX-J3zrZ|y(FHZ%O@JI@|)8&1H_ zXycp)B`s)Np!l;T@<0_v3e{WtZRTj3Z%oah*Sv(NJJY58eP)5BvRIcJ;N~FTK zDKglT@!iKT@3{MUF%9$8rq-yp%DN2C{2|3l#`@-}r_*dy-voW&FqMJFWnLrRD#>`K z$4Gc|ijBLsI-;!GP8HhK0tj;x_J~22PDr6FZOx^KrB*$UkMWmq`6~r88o~4$2 zSECzZqCpG&0(*~qq;9u$j`xPZn<>FTl)(pA7`{{IVT96CqgtV^56f%`0I2Gg*TK@& zU|0)VXl=~~IR%~%->~vbrZ4R=2Mg8KJbF~nGr7uvw_zBR(H=MyG4H8Iy4+Em{`Cc} zC&bo=H}ckpb@>c|06)a+%m~XSl{}#Rp%f(PKIFU!4Oyywvk7?=CU6|TV3NK=Gs3V= zhTJ0qylNY(yo_XBiELU~4fb0aCKtTV{(eTG3OJ=4A2v?Vm4lRXwG~?h*vE-3!o4T- zIr~GgycZP+-(?MYiFN9G=WoX$CS^=^v|4~?<~CP>I|+&LO$mTY`p<#UZG#4^o;L&> z)CF`q>{0j^N%1sC4LEe(QVI4f44Du0@W|s=$DYwiHch>EciE)+&h}Vzb3IWjU5wC< z?G+Q56)w%+2e`B!GigzJ{7cbph(E)tc#Z?^k;>=z5F-lfF?6s%R;H9`h_xcn+{#>s zfI|63yzmsDoqe(M>)!sRY8fXU%o?+h@;6c$ zkmO-OHlQxM1s7}I3%w)BLc#X{a^JI`&1$ddVCE)uC|^biPLBdqI^Z)GIw;wZ0gvQ3 zi8UsTWe%9Iqka+ZExy{kIHbD$SUjU!yZvj=v^^~Qi<42;c0%vP)y#=1B)W?C2&SZrdq)62Dwnpy}x@sc8;s$Wtq%%r0{k$SDB#X1E*=l0 z#g&$rFJKymelo%tS;Xmm{%*UC5Ysx{r$-ZD0rN!4|}PqnK< zJMTPrqULTu(UHZ1y1}bgcSw_mz(|ALo<|rct9aMYoD@o2SFBCbByok*VDPg{Fk6x! zj4kFCX!s|&!$y36#w5;|?#y>&81(Pp5Y@t~QTuU<`^Y_BzhQNFQv&{O#bK{WkaMyy zE4dxb(D56z{!Qf!8r0|D5P!Dqz`6aeuQ#0Lc2xkDyrFdBmy_+fm7fK+R=-^e5mp+N zE#aE7_~pb5j{9Ephn^53!*jV*gxiVuIr`mOGF&tf9n|w3K+7DEfx5DCfDJfVAjs-- zD%(RFn+{pmvmF)xAdqry4uuSnoO0q?Nc+m%B95vQ#|B0nn$pOneQ>9^k9qji|L)Ix zqU~d)y2UKdX#$;9!cv{1ZB#>_&)>VS>#hG~PF#t{J@KaK9lo=u_Gbt>A_eL5trt&=}`S6kaifkneQAPU0BBNF>5yJy1#=4710SW;Z}n!T=B zVIn{L;|C$&%RW~VCHjHdtbY%W zam*Hmic!)!lxt7=)RwHbR#%0Jv(Z)C(1ER19aZz06K}i5F>Fh$gHUNJXk@@I7b4uW zl#4$-Gww5Z^O|Cyuh=*{=vSMfh$VUHthFALcgH*7ILSN|*HqR&K!(L-x)zDw5t=55 z!0>W4uS1wlt9!M2Ln||jjdzvO#MW9m{h}Qa z?ZI54df{*S5n$yo2ph99Qc}R6TG4PvF|@e$R$b~AZ>cud%Of)&Q47{8dzc;lmEKQ4 zi{HyrVOdf`i`k5?jGZJQbSxj6I|L)-q5@xK>hi!}<9G#-=ArrgK)#(WcNB1Zl)LfR z`y;f1?{iGMb=UBz+J?S1$44W03POLPt;W|9Yo&u&L4q)J=2-pSU89*rR3%s!kvfcA z3Trp#X%Hej`P4(K6KWJgb_JaHGMv17xopCFdion7dWq1vF#e}>7a z#T+~&QB3OHr*$826}8+BD0WV%YbYOSXMFNGJRYVhSn-SySR5%y;J<6s2loS*oub@_!WR_qjAp*@`Yi*_wB`x>Y>%vfQ~h_ZTNh^FR`^- zTOQ55i+6$D_wV9ZU~koy?cIn1!?tBOaN^OSfH451x*$nUu9GYn2Yzx14NZ6U27zQ> zqfxu80Y9-0*)((uby6V+7y^)!VMh7CldvEm2STv!=<>OYC;**2%X4@F1+FSO4PW3f zmS0*buv1?m!&q&BlljgLizHq5o`)Y7g=Gg>%T$DW0;r!;uzKm(X z`|ws5`B)n9iUn+mW(+3Ky?8;~9l-n#enWqRXb&S>a`&O2k zBarqO0_i-@QlSbGmPnQ8=aRr_lon=!JaH3ydRHuxl{hwA01RHY2$CD#Ch^X1E5F-< z3fpW$a9ksUkG3oItRcK)I5X?1gB$IU{10B(gwxhh4BR4Y)FUp1E=3t?Jxz(>G8b*T zQl*|~?clR|l1@8C0#jFbZY}X|icr9(kKVCXfoan*lAPmj^OInMZB&F(*U&ZAs@P-t z-JY+k=BNYPMcZLDx+<7z&FKipw>#loej(ZAZ7dh7Ja>5^&W=2Ft!<31Baf{Dv^i)& zVXK&z#xe;gRe)I)!-}R!?behI@S5o9c^hQGx=3>g=>+2MVXXel7OcOBdE=QH6n6~c zJGoOG_{f`vsupUG{uVX=V7$E)$j?_0LJak;78%?=-3m|?$pao!efg12pZ|5Yu`sHR z^G=m8;-PHk>~z^L@UENFXIOMG`4Q{*aU?(G@7zim8?3PNi}h01s1tPonEzmYsHprt zK>*8x88qks()n@13EA01g7FLTI!ble zHGp+lFA;g8(!l|Y)DxlO(tZgnDzB7XY~Zek=9)QjyWRC-wd=H^n*xMMB2fa;`w>xh z7)7hL$K)=MG+m-&KcU%%ZDfEXTlb5aO^Xn``B+eGf(UevPBaFs)b6Otl#T1s#_$mH%BWDgvck%4lN1SP5M2Iq6}3he}P?z=th!`<6aGx zRNk}u+r8odrW*kp6p3rrd%}r~qLbi#6E%jZa;HomGWW zNeY)U(o_8p07)M^QTMifF1kE$OXewqlKueCiV3|Cb&2AWN(Kee5qK*cL_kBNK1c&n@X5ud5>xzo#0DC&_O;1ZMJ^qfkpxfP|kU1iNSJ!eeEJFiwSF0Ow8 z`^@V@t{(7AN2}HeT?@I5HpGSXVZ@Ni5uYrqT})kJDElzBs=o{Do78m|6U7dduj1As zvb2^KVH4uLn~cPmRE|;hXoH_5f4|Dbj-n>7X7^3mf=!j76A&3=MYL?SFR4BwSrC3NhW`?B1^c3!&)=@aEf3>Kwkq-}RkjK2qms;?(I;k+@NqXL*AQ|NaGh z_`^}t2Mv$RZf1(mvavWA2c}Sw+UOITqzy_#t_0%gQ44_jc5A(53cY+7D~^oTjX%k- zi*uV#Kk6P~D~}?z6SVYwQNF|xZG3Sew)-)PTaSb*x8)>shL|5_E(9SkCahaw(`DW;_Ep%km|7MVXL3)pa`VhaM-(J9nE2a`v9jD+UtR?JLrRX z6n%pOm^4R@kiOknBzpC1Yx4Ef_DXg0>`G2s11{trXtC%u1r%Uq9fa0yg#N$3ja9r) zk|20i`mY=Tb^b_jReL=GK3!joZ+cf#uPL=6`|bSnzFj2K8R?+&p*!g&X$dLq|me%tIbWVi=gwTTc34)u0P>sF^_@&ApMfm zb{xbL#U!Zy98`>uXfaG;8k7r9iUVO%dp|vc@y0Ku49DcqHMcP?W9+z(#_VtxboC~uk5w82nK)xl zs^R7vs4R*#!bGb2d;NgekrD=j)#GRdz{y8%eUIbn3~ruTw>nXWu~XCAn$0;j8yEHI zElT4GsAzD8;{`H;tvpx6PbF!ri4M%bqW*L_vWKQngY+dvh}P9t5cmSM zB{bT5cO`TzAd(j^4_mhAkh}T}Ar~lO=~F}craKt$4`PEjR?k{poq=dx{H+CO1VM1> z&SETLGJW}QZnIzcF3j^Dw_1|rYUmIvPmsj<{zWdTR17-AP$y4A`wNmbKB~3Bfxl{` zt*9xRVg8b=p?_t#9Dr=W3*JuR20=O%Ej+{N>lTp|)|h&sMT|Z^x;b8Bo}t?gnDe6N zW;I_GKUpitEn4MDgXvsCyn0NUU|f4ahOyUb%IyC3S&IGhc4QD366T4M5H; zf*|XuX-Kp_%_(?LP98y4wZ+qFRPTsxMEH6Yx5iSN8&D4BOt^lLSF~^lFQmkd)Lr2!wzKZpJ=LNv%3VeehT|4c28qC*zS8kN7nR zdrCI4yf-PvOxux_y)^ezUUy65o|e4Pe<)p6(*lJO@N!r zo+6znyblrzqv%Nrfr*(Bv2}$s8^{k{*9#o*lErJ^O43GAMBAHhMg`^Lf&7cdAWj9wP=rEylLbBF&3}iK9m#+387UDB0a5y1 zJ=x_DGPIdpH>SnJ2h5K=?D6vHYXMh7>nXZ}D0G;j3>c!4qNt=zRiajRS?eR7`80Fhg8ZCkyAY%?XJYcx^1*Z~7q zqw1N2lYehe1BvC5ZS18DY(T&{gJBm6Q0WHwd0Azdyr`GKtB*amParIys!IeRt<315pwH!O563wtQWp?1&u6pBgjkTZX z;31jK;Oks(dXrswC`#wJGl9!`!K7ug}*?ppUqJ_WLqw#5yW zuX=E}6er-H1#2?OMj zRWK`AXHZnwK&WdAj70fXCVh`16JsQF(ZoQNxD2~Bk*w^hBq5d@U|4ErGJd@yXHh2g zL+V-8JNPhX;II^C8*E|&(Vn(1GT;PeEW=tsMkl-?i+XCM;o#4Qe&1ibp~j}%PQl_HPO&*q_4?DfiI;XkyjPW(_-JCzJq)AHEvQKZ|q92{XGE^B)8-jSUsaXG!z(g0!!co%so z9O-{uZ`w)I!p3#dX|Lj;u4}Osar|Ql{10fIASNW$e*B#MxW_vR`ktb#SE-1%ReFF+@#9W1<)NjN{9y7z1Q<4Lb11zK6_FoBm-Rgbky4VDi(c^YyCy z&5GB|;tk)VTY#XNTx>_+Ax1Eh@n$_gJT5==`-4<)7+4ESb?$LVj=Nf)c}VTuYIvr$jrwj|5P9GAxd1XFJd`W!<(ZBV~I_XM~& zC%_TKe9?(g6QC?8^xG%g5hM~eAuNh%crJ-pyEM|#_d^fO;}0`4XvVulkmSmk>?Q=< zq57}9NiwN7sqnEr<35>$&(v@f*dS3kw$7)`Wa3L3t zjQuBK?1ywnoAwC?A^aXqeL3%hgK!=&n&cQwfizF-cV-g4;{j(b#Pf^8H??dBdfdxc z!Bw)iUF>x!1v|jaD@%$$1yf^$1F>8V2m8|cW9pX?g2@mCYIDQ>yGJmVR|qr>&7>>K z6bhHNhSIiu-*!t^5$x8e+YgH^5~#46VWsE~5w$*L3Z&6gUqJ)>M5vtCVo27YP?#LK ziPtgatp2n=$5=YG=b^zQ=ODb^4$|p)=cy`Un`#A;D)z( z{FQf=@~1vg^`f!R3S+PXEl@kcZ)5d8EU?Njtvi=y^!f+OI2E;3S3Bg@_1OD zlGrAH5zS_UgYa%|P{-?rnw$+}@q_&+&Jcnv?~b-{Voo(4`F2asBbBxFE?4RDtl`QU#M)R0A?V1F|Q=QhcHvaq&^;B?wXzi9Q1 zV*5PJA%COy*NVM{q|@V@CXzSBMLv^%F3^EA5kjueY>}mB?%!e#usj}E0x=wX>z*6R zCBRQ739&cG3YJdj*3*Wnx6l0YCeeWP-zNo9I^)%6Q5j4`Abxk0K^!W@%34EC{0E3D ztP#UdH8$cB`QWN+5IfU+>QWgqu`wMynUz{7H5 z=r;n`8`CX(+nyZxa3Ms?N*(b|V00$Nf-&L1{5*HpziBfQMMSty1#X9cL1wz`>4Z1F zzUU680n+Jx19JV6Ef&k2w_NMlCOdH?<|tw0;5!pzc3!6vRPmd?B~wcsv`>VqCB59h z7yrLkDEA|C<&l-0pk!3m%7uO!WjhRsEnv)x-uVhhpwA+hP5GsJv8dj%Mh!_KSQao} z4Dkm_&=^4&0XvnKlI1D(m4YPx?QsbSK#zF&DCwZLtEd`~*3>0xR>?K8RC9?VoYx6# zD~S@7d)sT~ec$vO1MV3?i69XQHyW&Yg;=Kse&T)ispvrY+@?Rvy!$_!^>w*z%cZM* z_eI)0Pzf0le_PzVAG}oF%cnih$_|Vs_Gc<7b4~G`7hw1^L3PfT%_;u z4%3vVI(}_&6J2%)14oO+l}*>I-uGK#e8o~z^oq`jk8C>FsE@#h?cqH+4eYR+NsHvT zM>A#GJ%9B#3d7><`NS!*Qtk;($DaVmgbQ%ve{NAGM@?tOOYR$SjiM%fEY?@)oH8u8 ziz_TmFm_+nD4D)=h&Y6uKWPMCwtYGeZj zH_D)n*c<-M-KVy5nHm-un0@+q6JVj{^p6NG(`ogLHG9CiKd29Hz1C6cKMAN8L4 zwF?cd0g~O06n@OD_^1g=C^Z>{zD;cm|2;eF350F6m2B}p`8ZTKSMm_Q^H9@0u0$z! z49_PS&2kaBpm3#wZFpq|bI}_`Ba#5_Efyez!(tFKFLj7Nlg0(MJ3Ziq_=NTd!ILiI z;B%C8)0H`7q&zDcesXHN7s}-_U3PuV%&N6Wfpw$nqx=S!dTo?sq25f_)dkup*-8Dx zk9qhIZQF#?;&yE}0H!W~ycglE)baP!Bg#BsbSl*FVuR1emuxSO}U|%duq2Z35Bja(VJ$h}rkI zXF{k@8S^#M+0AdAv(m5UjAD-zmXV0nkS5m%z<4IL)#HV5>f*HD~<`O%I?VUt_3(H&w^7qzWtD)O=s(X z=lOk|(?t?`eB@0&24Sr}mU5z9y&u?&O)Hsb8crjdN{En%)8#8$17QtJO+t#Y_AxF= zN81_4M+iL{he#z!kT8ntG5^FQi^XnMP$fVh@@={#pFlVrXl4XT|M4>xH~0(Q3vsrBHm^d>i_DDwDlJFldp`x z;oaWIl0=hlnT@1xS9t`HPg>$v2ZcZ@W#iqc-1GKT-mjM8=O&MJ*OadQ?dQ3~BlnYe z=z9}pe_Hkpo?A`cDd7xQkKAPNiI;_r{q8<+PfOBSQGkn|j-s!?|it^JaF6db}vHEVolCB0D#+Es<@U7awjIjh= zAzSfBE2KVQ3ZGTxK;Vq;Iplv~HQBYdJe6{`&3%;wN{RL#;gPUPF)By>b3Pk}$WUC{%5Zo6~x#^7%r_usA)+$`nDn;bbq{j<=|ILgE z!;)1!6IY#Q5;U}?@;UfR1w`h;Z2qhy4&SK@k=&ldLVV{HLYBrQ^F)(3Gl_I+&nkYvcgeQy!?k*-+JcYgn&e zP^Fl_zn>1AgV^vPgQ~NIXzhb=N~_cFBOdqCw?{r;>+Wf-$#M`QtVx}T6LRf*aDxXA4FCc@^h~RMK`@8%66g-sMB3B~L%MZ;_Mx1b^ zSBM}LM^ILkiY`)bRzg5BuK7Ci0|G zb2yp&r=9Ws8{1+*A|WdP9MH+$JbZ?8K{tdMaSy>S>H0OG7>fF z4jAqr+XIR5wR-eN`WJo02icS6SMl{NaCzXsn&?Fi+pw#JQjLv|IP27P zI3*}UIbVBJN0jkuCAuOztD)9S@mcnFsY4jhi?UCKc^c+iL=MS)KYzxYDlToqGJuq_ zxc*Q#`EZGoil}-6$Igng^DG*zLm-+Sa5tA0)Qg=#=%|0OtML2GF0Q|^>gEdyA)OD1 zOLCg{iBxqg3yUv;*#<7yt_w1n0ei+-c=bUW>c(6AR3aJ0{o-U@rqzbmnvD|+)CiL> zn(lufD8%GqdAw9gW4F$ew#D_0S)M2H<1r~E^wu^X7=1rZy*l%L&OZgtjQ@uEnV~eu zE8-i`u5nSKTij8M%koR`YH`?J3@3AnAm|l2_X_s-7q=XYTwXz`9EjmbQlae^Vk3w^ zl)h@kmClU#*}%&AaYu0C;JkMv)45P4kWOT+n8PcRm@CN?b+!O6~O{n~H-;X^&yIA`VLhVp1~Xr0KNAirLscilE9fV#MYN83kO zH^!9d{XZTG=6M2`Qdx#^WVk?9RIb8t@g;lAdcBe7)uT~rKcLtWt}qN@b1WO|0$l(m zew@ur)ytL(Xzb&J8Q{HO_Te?inQm>>>3_hzY=Ee~LB~-wp;yNmZveLo8vp!|-&@j) ztPc|E19YzCqvxH7)j0~1seVLdY6mfZOJV|EhqsU*r$U9^-Z`^Cuj%2-iE2m7I_mpp zz4YtM{uQv%P^5F@NjWuZtx-*M0E9~40S6!|FQ3cW8Mjg~z}-Jh*k$t;C`wt*x`T0m z?)Yk3%=LNRMOi;i8?{_dpUlx5=;2&FKoaSLEj1X==iXdR=-sQ@jn~>J&EWa`JD=7u z?2$6uo{H1bNDU8b6WVPtKjB(MGi4(UznJir`SxeiRqXS>v={IoHl_!FY`_YT?g*6#DCtx^Y1^l@2*rsBQh$pU2x`VqN+L_uWF|t5 zda}U@xwJlNn!2xJ2ZX38z5VB-c7>SYz_IQZ-Xq$9Rwa}7pR|AONyh9V=CzC+evW_4 zIW!1sZ27`OHec1yL{%A2^l5qK3EUSvD9k~!v?k^vB`pUnu8+1mVF5vUZ4%5*3K^Xg zO+o@zFKNGmAp2jMOV`)fKtQHHY%1Xy@b79>=`e(QK#ND&JWH9I(rk#6YP0CGNJfGL z_#1w{ZM&XY8~o6uKfnM)-I2y~NywD6E%;s}O)Ky97vZL`LlbG>v%}wIUMxGH;8y|I zUmV+**myTpGz6$SVF()d`>S_l2D_OYfsRnVo+Aj+FO)h-Z08Sv=ShAzCGG#LpA%(GHgH6XEq~xR(PFVGu$1WNURWR zJ&^4>pj{E?eA0ER`2o3fTV4!&)7H66gdsNr&&&8}##(pN^d8`Bz3t3J zEW3tO?wK*+F>V5O*1#i?@$!Bf)Nh(rpYg%4hDnenm>6Ec@2H7mX!XV~sL z_`e9GxW6cXf&k>IQ5or8=`#asxsm2}<5cNY9I}@JNebF@jEK!A2Dfh2*!GG8p>AY>?xF|e%&jQ^~PbG7^g0L#gFmwI1jL#lNrR_5v;6i00zUGW)(LFfm-Pz$TI@xgCO z83|owq+oVD2)MC`So0z*T&CS66c%c(#NIrYkOeMsF13@`X1i*UFEhdYAk*;%mrT6B zBUaOceF#`;=F4jbjBgla812)C6SGG20WUrAG}4El1CS`*UlS>Weyx<*nEc_jkA8q( z?2F-4i7eJagJDpfM^Gf+t2gsT7tJWi94pnttAl0VdI9F1rm<57fvQ{-Lq-CF&@+j! zfhB9eGKICyJcWuUsJ-`5RbKRj&JZGK79$Yk3klMwpz;3XcasQ^{U8Fx+)e1s3Ue5Q z-);T8Wvl4#?=lcqDzf@mffcuLsKcMPS z71ZAXi}3S9UwbU1L9oGHzQnWdlZ#8uuFC#>|6T9YCmx%icQiHB#E7O@*(pU?E;p_ zinYBoSWC{O=002iWK4`z^VCg!x`T}X1g;ItR`gYsGO~9obs7N_Z5^CY)`1H98z;0Z z&*cx*K5oywvsVHyQ|DRUL;#}#A#=(M2im$H9woZ@#LWE#O0*hty{EHo`tt}f2~0Uc zz%zADXjcA!dp#P_LUT}F_DG`sN2_Ie47JUGcqJia@D=snaD*8m>k$%hez5iKMm|}` zqKq5NO$9?g!mm0@e_Dx0-LG+IqFcpiA9t0~z|grht7CW?@Q-E{U=S?2_eYQ$(5a@I zZky~48NF;?ksJJB6-0tDl~!bhlXpGdc>j)Hn(<#GQydcl&>f&;m2>V+fJnK4csB}L zTWikRB)n;Ay;i|Lk>;#xSXtmS?jwlqc6zqT=4d%he9I1;hktEV_&ko~oAQ)aZ7I^- zu|q^ES!7cl$gQl#%Ec4};fQJ_Fg`@8YJ&LvhsTlYOp;Gws^Wl=@!2Y>iNQ896jy#P z#C{E?jV9Y2hN}$v%m-y~!;;MiC#R-G|5$=%pw?GE&v2tsI8?Qsg#>g!<*LfAD2WxCk zob7Pq?ZYfu4IYww!?7N)=^ge#OGH_Jh(*YBrp$EFS2o!$DiYLn#W_=54w5{Q`*cmY z=G=>JpM||Ekb-@ul{FW|(V-5P%yO>?SkL6463hM^Muzbw`7BwEx%0qshx?L0Jz{j5 z8-E@6<%GX>j4CsF-Ky6)sw2W?Z1@$+vtJ_7Xa;slK|a;m?fVii_M|J~gopy4vNpzP z<(O!v1hU1+jxlXnRlzwEBzMM7q0=x$v+wsRh)CaCBu*X}|ecrQ{mtTSO1Wwg2fK3O7lA?UM*RA^+71(X%>lrNkyxTt0QMrCI&-?)H7{?o-m~p&WJ$-ogB@pFq$_9serlP zt4PI5<^R{J{&zL)na7?v#>FLk73QVp4;k&%0YTE76&YAbHPu^!@ch~)AvA0W_WowC z$`pwCmb0&TzrT3vZ)VSMpuwSF-zzRIb2!;x$gI4Ky0pW5JOoGS;?=B~W)<6CY?P~m zR1^?v?SL+pI3wZuv7Ke{9#jq@;|?wXHi4Yty3_i$0CpKti1{GCLZkpxD-&$bT@v

IsVJT>%Wvff(-nruAilWjC?=cG?no|<31h~@pcvJ6 zx^yTyTZY}fSEG%VO2N`$;=N>uM{fIm9>JUn?+k#S9WyCF?WR=#xh8{{gLVnw&t066 ze4n$)oX-l?k?d{z79zbk2VfW)+Q{38+gs(MiN;zkC9P;p>2F%&mcL~x_t1ecL+-v6 zFXVsW%H#hrc5Om9Amg&Z($H3YtDHFJ+}i{c^K3e~*_TZzGYs8@zocFzD;W|gIH3@@ zgt^WvO18fJ^sYN^(dNr?$VS$XHE?Vd$5)EXGXLLXnQ3x*otP+1KsK9*X)ig|Pe{Y* z%gQq>vDk0u<*t)Vmto@7u#YAfYy`=wDVB+ycGtUlr=u8amd1<^NgB%kiOxDr=86`% ze<0&am!cDa6ht!l&+@0%{fP-!5|a3v?{Sl}BC}Ffh?RFX)UtQ!&;eJs0xtWPgCz0^ zb@b|R0}wK3FpG6u7$i#_i%8ke8J=@XN43O7&aGH<0gqHg0Mc3&(V6-+0V>YTkW>$w zMs$g21S9iv_v$o|fPhS1Rdh_s;!=(7gkgOzu&nmD2O^gDJ{!18FxrGtCwqRTJXYn? zXKeCA8j$onVu(^K(g`Zih>uLaReOv$e@HXhrf?EY2yTsTkVafXT14+iPTC`=J{tSg z80LBahCOD6|F>RZ(1=ClHei&S zZ?*xgQr-&geQ(p@{Dp#0O|s(sLCTYjQ*a@>mmp-wpphneFdR1UN0QJ8IYi1YSPs7U2sP(`~G2Cfc=BV9&wc@8(I5Fl)L6MjFq|Ds<^jL)LmL1Dc4tX zBMNxj|l(&S@bxgFN$ zd#bHYZfgYf51OE4TNEie3j$Q4ODd^ozhVHy+NU~*y!SN zinL4qskmB}_c+SfhANZ&Ecqp!+-p4;pZ-HvmsJRrSf~O0=!_Q&CU~0KSHYMZ3=W7) zt($jdLwriXsmmavCm|w9D74vhw`GIQ63@_@qU%>O_9}*6 z`~E48;EM?!wDs#*Uj&;5v1~I}(EYa|dZV`IenmZ+xx*U$H-buDGfs=@vCHsO;*zqm zEFoq0rF+{nP5hM^5V$p-9fnY9FWx>x*-)DdROCn@61FlPLu-H2>+XV8TW)|K&#|I z3zO`VCT7;JM$>JZu?1Xt9|?q}!9UNFuhfnUsQ>Ly;jll98QGApi@!|}C}rn^bgTv7 zfM1^HcAy2MLTG1>i|(*~eTby?fqe;V+QNUsaU zQ%~$p_<*Oi%^;FN>AQnEXYZIpjT~BV$#BQ~2J;J{;i{?N1OT!`6RrImLakytRC6lI z&eC`hhO#WVg3i`U#H8u9tANwU@7Ve6fGTZvGj4?-)$bt;z0fDIHuKq#?Xlm1!3_HB z!Fx`vRym=c=WHa&n<7oNho*AXQW1q-yy7OP!KV9d{JB14_<#-~S!hGBRl_w8lmcl@ zI~EKj;^(!w5(r?A#~5sID_%x$uu&BKLJTtVBOaU(xsAwR4NFP2_Gi|W5{ihx-- zo*=GgObnxa+iK1N!}T-WgX2CqJWx6nTM{gC|IrUqos44O_&eF**W}@j5l7x8b;|-{ zc0zEyq7K*6-w`W*`&NI9xN^fS`isNC0dsCyd zbo`uy(N7f?0NlVm0iTUw642g%hDHp7j|+lDCz7)fPZlQCR33nW=bgTuoao0D!yJm@ zM=ofgro4&I)0vr~!9&{4EEX~>{C=}Q3`yFMbW@i0bp<$AYNpp7gDZ2KC-V9ouBf3W zqp2gtI85yoD<*wCkY+YcZ>t7x{j<{Y0;fVrvKt;7F3*C=;y^p8%J=n9uL<3%ydXy+ z!vK2Z@C$y}czq<>_EO3#-S{BCPf-Ok?tJ42Bw6Vu_?ZA&4xAcJEdZa6eS^uWo|>O5kP3F6rOh0ERl5Sy(?r(S z!Dx&kv`3pW^0RUkpBX$74(Zep!YgBo>(Fz_$RZ5qbylclC@jU+-`P2?QQt?ql0)0` z>BNE3D&A$Cbq2^^gjOn+JL%0UPK$$~GtTbhJ2g3(RU;?rYA{=&XB$zNu=S0PPhRa- zURgeU@2o(e7h*cu(2_3`q8Cg$x=%l|C*ZuvUq&-x)?ER=s( zEVD_C(9d>_y$ut;=>{GBI=dlOht|g~0~RCvR$pO=)v$dMHXsNAPmS#x?&6fa7RELG z=pBYakk_0KM>R|Qb-ot=g&$}4T{;ysE9*y>buqz~B$pA1Ka>EOuhWJ}CR?8CG~Hp7 zg9yV+s1uIWA<8i8#uDbulvPpRAsH0Wkac}k9Cx&&n2F`H1_!A;`ubJ+so_{* zko{^pMcX3Pw&61(vd3L`n=3#(ok2-6avSfyRe$Hz%?#|CX}JgY`WCC|24Nc8TwohrT$1Nc+m;0V$TsL7^FbRg&`Jex4WBJ0 zw7k2F@m7qo82*lk+e=T@7Y9OtDya1HV?ov$%Z2wdA#|&(elefTFtxiSpWrs_3t|2Z z)I1kje~i1ygl312^o<}{Cq2tUA+_G;um-?<-;LBL`Ii4)FV(;W)c>P_VG!@^n-FfD z>u7$J8o-wn^=%elCs&KsJmzn5~riQqH@cToTW}GI|uum()f(H78lr z4zy(lW9%RL#M+5Yjr)^LGV!x(Czi-Eaj(+E=n&5*p${*{sL6v>I$&fDsUlI))Ze?@ zzOR@R+@FJ45DA{ zYhkCG0CIr^i1L<`j-u>e#b0KMtxK)L_KJNkexec+Mk44w6@r1kDaO#%Q4{(9KB zN5?_7yzQdxG8V>UtF$w?K-8e;SX*HmQCh z)N;2qD86K$-h;w(Et0zw!&VnEbj6YwGnPDuMtUvGv-~dAWI)~U)&TzUj!UlhFimUY z&C_vv#3b&LpBkM?5%ZIFcdnEAw_4{u+8sF#G3gHDk2c`wgvG6i`$jDUSSSF0t_~o( z;q~MivD-H+pykH+Rtr~`mC(;kpS05$1TJ|j5J)LnW)1V?li{d`I=B-Cv9Lbc`uQz$JuT`*J}TEDkO(L zAK0hr1j5G&_`oK(VSBjcO+`@`BL7|7IeeSQ_p%6+5z#;|Z_-!P*V zF>6>g9PWUfZLJqrEiu9l1r@|DzDx;WI9rb2fEr}*Y^4(p`5gE>O`*_q^ZYag#1l>r ze_ksW`6z9`FcX>#A*E*=3RoJtJbsSH5bEN$&(C(z&&u`Iq@rqUzXFyNaER1hmSpB2 zc_%*40P0TI8MCR$mg`{Pt|peZ;Xhqa*A(l$`mKtH5p4b`Pt&kNe8Dx~hD~|bbLkx- z!R{v0N9FqJ29%f%AYLa=rJ@zUQbsI?-XJvFot6G0N$JrY*?ZXsfj8TEy8imCn<1Jg zpU$(mf@MMu>88t?j%~!36{)@D3lHJGYT}vF;WCVb(~Em@Qv<}KE{PLM%sRjHQG!Pj z^R(7eloJ%;2Ib54U}$pRy4Pr|hNQxbPnOU}TZH(ENg1hU%)AZV`L|@?#s1tvjw2_e zA@}aY2{b6c#M*W)gp1d0kbeiE)I_-JcO(+o3+p$Kp_4_EZ+9M)b)Jf(a>>2}zygYD z&+bg8usOBHX7RKg^~!}#Ugq&z{uUlzr$7+OgL5rJ1J0O?A@C&N^jhmhO-%KF!8eAQ z&uxt*?|!oCG%JFavD>V7_#MrsD8Qz!|7D~2dXcQxP0J(%$y}jtdQaeDL%Qt;cG0Y^ zPfj>(*q`CnyfeE*^k@3cTFRIHM%D3{r5=14ci~SL%!~nx@0_`xUGE(;qQ1v@F-4d4 ze8*~gy*ctMMtk09m#m{`;q{n@gCrAAyJB$8hrOcHeiT8^+s z%xtf&m^=)GKhex}&HJTS`$)O3-mjuu>tnE&bbsOeIBh(FMGy43icu665WiY^JF~nB6Km))RDoW7;0(UCZ%ouj&u^wz!&(T^pP5y@c zS&k0SO9)`GLUK!@+&bY!s=YHarqY-(AK7?!za)~f+m3l5HfXAIXPNm8Wj-1N2cJM+&-F%L%yWs#adTMn8tUJ*6_zaA_hY@Y&yB+XU28>zFQzX-jx0KAm;u(g0 zMw~yxtMpc7_!P{LeWj%)y1aa%7O>t_TB=#pF;ogn%aMb+5LT4{UgHkmtmG&B*9V79AXZc)ISB{LF2 zPl-SJ^7>t|_)w$%R@Y$F;nD^_Aj6o7nibtBq6hbN0|;9ci`-MO5?V^iBImleT2$>9 zNT7xwUiG1M_LQ;elYLhD&=p24sL^mwe83+dIS1jdt1J&~y3diT*_~o=(T-5k z)chmCqZ`Exk@`BbxTnH1dimMKHa@9PP@dkcamnD`pi>s#!zPO`T}3-J*)EahLi?Ah z;rNgi@It?s@{DY~CJxi{n2@GPz*zyqQL?K%X;6<6F#2khJmp&%RXmWp5p9rRc~&4r zeK_Q$)GSUpPdaG?w;V5ORV1`d%{*}QmgQ$S+?E&o=NOwSvq1|PH~o&qLB2*$Te z{0W!{Kajr=1nP=ZEx)34>;=?DmOUmWc!95o#`Zbx-5Znd-XY`~2R0JG4AkwI&>V^& z+_nYBxTn1sCQ22(EMv|rf>MHmDlCQ6KOv3)NYkYRzIX;+NI@J6mU6ghl$!~=dX-r^ zofcnm^bm0tUdM2j!YFEoiCiVqZ+JEIvL94Y+L}e=ide({A^%p)o-OJh$Gq{}9CmlB zLHWS+(*nNAGH64Rr=5yscW(%Qae)0{Tu?*Vs1#Bp*5bp)HJk6a$pWHD8p=r-Lv3u(X1iNM>LXjDJ za>O~Z*B<=T247{1*>$FuF{+ol5Op8zHOY>9qU-!;%7aX)Y?4{2X;pR0;X%jk#3W;1 zTbL_iVG|<3hW|FQ!Kd*7Oj>K{f4~sw+dKxyC0xmHbMiS^7btMp>&wcM%n7!(x{{83 zD#b3xE8E=d>!fO$8`M0_n8>%{+8J`2RgFN)o=nVw0LT}@!(Gl+?@=mx#`DynW5(1I zod7eXlK^v*VJBj%m3P>pk&3>XpExIz2hl zp=a-o6wQb~B9#EhjQ^d>z#5p40*MqJj}+ETe*{7qnBxH)h;YTd7yi5bfM+kRj{>%m z0q*>G3HXq?wXAtH#8=Zypnk=b)MM5%p`CYQ3t`jOaJGs_lWKiaq*;u6(d2lJo+&8$ z$5t+-B&Z5a9S`RD9$B5fomB6lGQ=Gw@a zHGH%nyny}ECgRrY9F_#7R!DX~JqqDIcNtS?V87@X6dPYbgWxKba2b!^LXDM$qJ{_Z z9o;LbOuV^?K8h|*v0@-URlq&3BjGD&6BjWTd9iws-a^n6CxB!Ef9a1Y_|stb;U@B! zwF7t5d1%rGR>}OTVzU@lyQpkpZ}Bukbf{ylp1=R>FS4fQQLzai(fB`Bg4|0ZZo%=f zM>#u~H}69^GFPP7*VD(IAR_3F@ig3t$WNBcY-i-FAsG4VmaQn{9j$s=Fhpv^rTxCb zQ@KITRCMJ9q0ZANfpGy{0`}hv zFqj`WkX2`3ICwOps>4Zef{&BFWp6GW#JGh=F zewl-|y+l>k_%hqLuVSa0&ju<2{V{2_qs>ifiCIF=t;dN+`B%)|_f@9C1#RS+$URgj zO?Z;7ra)7*BR`E7MUAS7{ztn(vJyb;_Dg#gM>vva780dC0M3RCxu}U_^rkm;{e9&b zDvG0R9Ef32qT*Pw6s(0!HVJK116$|c2`1fmwz{`VgPD!K9!`|m9GK8mJIftG9W&F6lAaLcH5aieI01LvB?5j zP;)!oGNTNgx`907A(M~*V8MS9P)GL2m3TnUh_+Xt`@^nNmL3^X_E&wr`Eue&`v0Q# zfXw=}$>&dKIgy=RE1`vf@ztoV-ZTtP54`*XKbh<6hJ_ceVJqx{eJ2ub8-I#ku;=FA zZ|{&Y*y<0Xo+ma(`W>-C_oz2p>-zPlVe4_NdcI z&B}rk8+fZQ=#GZ8#!z_`0=Kx8Ug6N`r#~oTLKa09w|*_m%k^Tbs)SmwO8P}F9yx{HW(lmEtl`iSj)*@5j3p^t^wYUl>13olz6rI zpQ&Pu1c^?>>-ZPLK3Tz2uLPY&x(u9W1{Snetig0tP}sV5wDot0`dS}N*)UH+UWcMw z?KJtqBm)yTI_i%K^U?#p(o+{;0W}GuW{e)R7Wh;Du%RuHu&Q+sw>yJD7m|>mk9sW; zlMr0PnKj{w^R~BxBTey3B)cUkA_9`aYEot@q#60}10gwo_&>y>S()D#`3WUXKO8pjrr3fKvBKo8x_}#6iM*?&Y7ZDWuH$gX<`%av z3W;px+`&JyA5IE3iM@6L9{4V2MGYX)D2N1~g{Vk9ac5E%7rLjw|_00H{B_D1+VWB5gL)NGlg9!F0+XyRu z^^C~G(Yp-(ppxlfD3yWvO zKd-tkv)f%;4|di86bP(%@@mJvDeH?V*N49q-R{Mw)9St@rrpcL-*Yc$y{6&6i%`we*yx!wI{Q*{S2WFwW z7M0#m_}0trJ{xDdmIQ%CE5E&H@^X$-{tk|P__f=1#ue=^T~qUBtM!P((tHM>C(JUg z$`z>fd~)%y@p5Bd!@Cn-6KWlX^#c8?0SUN3XnNVU9Qz!=?={dI+7da**zah zZfclSMf8QC|EOOP9Jdulr(Xjdk_g_H$z|6)S#081hrUbck8-!B#r`{dBh3%;D-*& zLRnY~;hF4E7%S)+to^}dw;chAvRK|SUB7{2$*e*Z@O2wv*|u^M-4-%<`SSG)P-Mv& zb7gz!fO}i<1VmI8D4tjvUBbiC<4R%gdby(+K4HZEg@4r%XWUs}G7MxTw2MyNbZ$Fq zFZQ@>Q^CsaPSwpic_I3$fd*NQ{C|p$2h<+6rknGdPn}t^6&ghUh~=1J8NBD_zV((g z4(>b-!&`+yZ(YM0;4iwR2Rqd*cK3bJmrEE=<}Ld;3m|@f);_c9kp#I{;iTn<<(OiC z8rjND+;P=Y^e^b=JZK^!%obnOA!^RF4Qm5Md*zQ7hltE@$Vk&RtVBAD$JYN3W4!kB zM;AV=P{~lcm*~U5;kR^5=DpuG#etjFOKksPTDdm-wu+bx83ynP zbTK$Eji9qszxdbv^-+6VeByVC>EfeUCQS=T%&W476(&E1Ym^PdK~6|RziiDARAI`> z#mWm13cBUc^x2b}QYSEQ-iAH*~U_J804ug6e$a{a?Wn!Sa;>(#C3nv3l#(y9(seO{@Yf z!P$lZ*3q8htwgUm^#GoCl?{8BvipKLbvjY?yKD=F&k~j+rVVHtd4-~;U3T_2i&gyx zXorNP{)lAbP3gfqVplSiPieWGWAPzME2{PFKrT+PBj(vkbN|KPK2xIRc-}gg5v5@b zPO2;gP)TVz5Cn5K29xTX+F9eZgt47x#hU8$6jKEy!d$SO^%pb=BRKN_M zBCb-Txm~dXA8uV#R|Wv%(~x9bx;a!ZlraYD{fl#tC|{~%>GE>{wnRDPMD+o~ zd7o&>cY@IiQ%(N;0JyNV6wb-P6{C)fSf7-pbMQQ2aUx7mD||ICy2+XVKGO>K5$9yg zSL11BuP5PK67(~)Nz9CFQTeeSdLsz$c)+3njq}8#oWaHk)T++vLM5DCopc zG$EG((r6*54zBj8F2XHb-Ji-CmhZam(MCrE-8>D0A1cx1;I#1b^phgiV{#Go!m3`w z{0s3X@G`U-F2)Bh4AUO<1LxbNdDW@tRi5R^p++Xv;nX7jTwNk?16w@E(1B$d4EC2{ z1qY#*&}}y37zW3hC3sf~D$RoN8m(vfW}<-gQm_Jns2*Nv+=~Q;X(D$OL zq{vDZoDW9kYyVD#bjX{~pXqoWWFr60`{(ow?fT#LM!Ve$0Q~3!GHS7)pmk+oAU&>S z1$E4pl^T$hECqPRTOdEG9T*~wvbS?G5i6D>xsZie<~VJn?7ab#q=Lz1&ppAwg+YmK zHYvy|68dw8&D~Ic*fZa>DQDgiX0df{%Aq7Qs2A~WJIXwzgT8-7en8drdWBB1oZ_GS zJp8=-3*)e`sTz*Cv~%D^ujlM9roy2M!d4m>ZP^#@ZNTe(H!s3s>C{>=)oIn=h%OI4 zI?E1dZW2P8CR!Fj6FD6_2bATRJ{pfyBfE?&rP-psz~^kv%>zI^@W-cd+G3;H2FMElT**9-1^_+!D;_mn(d-$S1h4Swm1e*w=&sQIY^=}Hgh(!#Exdh zw6~nhmO!dlaz8h4IAdH6B@b`TAMmPs4M;`%$`&bN-IU^mu{DE3&lZ9NKW) z+Gd=Zipzz-%W3$YOGYlPc4#2;{{r-VDT8-;G5ZTlfO#rh7inR78{YV$+wiY@MJ6xy z?sKWkS01NA=Pd5B=Zf*8KjbZuGMY~U5(Y*tp1UDVWG>6}mAWv4-bFop0aTzz_^n-q zDmmb6(|>G?<%SO(!9$+|nKUQONuPZuMp|s!_rO&2E+=S~G)C%>?XEMTGbptyPMCpb z=)~4J64eAw?1H0RUf`ob8Q8AtA5$>B@p3|hs69N_o-lNKwM?9sQsBkg(n*@vgLSQc zW)>dd7itjCe0_L&5y5w>b}HMadswK+NWQQ5#Nz^ zn_*YvbUBE&^ChFEDvAkU{ocG;E4|bl|4QeC9$QBn7C|2Ax%E_Q+^7xmp*Hs+D7Tgk zV7WDt+aE=u8w}MF)5bBdFDqKCn`j%%X6~@9I`QOYXo;Mi>d^bKyu!=q>jjRYy@IuJ(7= z4qU@I66ir}9T{SiDJOi~JCgpq>w{P#fttnC&xzu1m5by~*cR zoeZ3fPy=Z{e=1PQ9(D%|v|Z}lfV?gb1-G^fwCKT2;T-yG5yIGl#`B9zZH{^ihcQHu zi%$f1HJAn}KA9*EQQ1c``msD-DWsKR>)c`8S1qE_o-e{fSTNxdwRtJ)ursU4W~aZT zdWeHx7~s`%VkXDYj*W?%%&}!1fi&*ig{#Wz%d2u;GB8ckj7#dkVA7|{o^Js%hP zvjzT*&M$w+mgFxktYxJ5Yb(7=8!C+d zhO5f}lExL*{S^SR+U_a(qxrDgOp$>6Hft4mgJrB-rDm>gBME2fB0LK66*g=Phdx0M zW{``SOs}|_i6|f+u1#U1=}`HDXZ-$_bNEOqTTzwp_6aQ_l;F3DoFsP*uNd!i%`8sv^kz1cAnVUJ}hFbHQbK68to~s zxWyx~hpRg&T(3{l&nGBbFtKQlw>SwGCgOW=)57>|5MY{kc=a`q9@)&06_#e88b-t) z;K2&HVt831=IP*HJ?rgY7(#^=+-M#POaLc|(9T887edcq9YYaEwPXtK?}1bH7TY5@cw7sv$HQ zJ2!7qOA*AWQ&Wu745&mkIqmS0a$E1Z9s)G1Q3T9RoEBPRUSnhzMtZc4OaR@M)XNBEZ$4n!Uc4!dy9~^D94m4mZ z%RdoKQA2Cc)~L!eh{zxgV7R zXT89|#OJu3K|LS*BaA0`ylZ)A)@ofQ1a}GSsHqJdoq^GrPz$xb5wJve?5vFl_s+_~ zlG8C|udbH}hOUa0mtq3@2Cc9$$W|bh7YutXV@GGcqbS2xdEyv;`l|>)+90u|ui*;@ z#^tDaO-%g5DXb{rva^@#%>0Nxagf;!$lidhiJJ*=zg`bYXrHyBG5TV!e ztvK{`#0K+_8~5NVPV;mJ1>lQa4Rew72gWkiw$h4WtuK9UyhFsvle&MgI;X*D^^RE& zO02J%?d;RJq4+oJ8KgO>-~|m%tDN9BHR{;&F^0o~Da+ZpLzsD?aa|x|MnBcKycNA( zfTT*N#u|c33av&E%y(n87_^Ud#$9&wbm@4tq_?D^+$wUZo<1-T7oVF)h#3E!{o4|8 zDhDT{4$7TSRA$AX{?Tl=zzF|s>Yj%Bw~*ZpP8<;guWFIRhODvebg4#3*Wvh)!W_~) z9g1_%U(Y+A%mLtNpw=le0q&!c^3rMm~Iu%rgjOEu*YE zS*Em?KeUY%1_gKBBBBxBy~SgYZ@+Adrfgu%(u%&XXnJv&s{pB{80;jA)m1B+iypl) zsMt*v&_+=jwdB*nBk zoHR=?lkiuYz+OciWRr4064?zhj$>Yt=lNynr$T00THs77MuZ6zBohM-9?y@@QToyx zxQWibG&|YgibFJojf_s|1bvdjbBx7#ZgbIKC_{$q7B{_`ZP%YneMJlxKZ=tiIo{qn zv|R+mSMnRvDHbGkbia~JIngcd$sn%3(!-Uqki`yB*Z*isP_!h^*eEO~*8LjtFW+Dz z?6tk_sS-IHS_w0|2fBbgg$KE@8iFe1vaz82raTeuy8W`xPuWlsZ(+VexH@glwyniy zQ5V{};O5k^)Ei2%F3TxjXoNsQw;ENFqedZBoOZs2d;=Fedn|ui6{xIavs5Mo@q?k? zomz$f>`0!Q5>(`lxnx8gvi)pyUdS2MlOH}`DH<|d)EjnI^{q#!pjlgxKFJf|&ZUok zb9+@2918o9ZA?%eAcrXt5;+r0dw_bIt1DFV*b$Q3nm<>X-Yt=XTw*V@`eub8-VaQ{R6m8O##)Y#fWm32f@v)p6`;RPwSNu;u3lKso0hg2yR3cY ze0U&7-van1Xa?~Na{@|JcrA2ZI7MZM>f17B{m~G#rV|O6%*kP|8Zhh_KbG(P<2re$ z+gJ?EzqW2I*F;AI4{apK9WHZ*rY>s7CyE=`QZLLI(Nq+RD=Y30ouaDO8S^AVS{JYT zMHBiuvI#|ru+SU+e0Ge(dnKBwN{C#D0tCD}FTTb%rSk-YySPJX0Icz{C8QY-Asmd8 zlFu@bsjvlV;I7XT&40IP`^^IzRtFS-}2k|(3dQDO5Ivrn3Nqq@!uZ5V$2IIJdZD)`-Dg23qW_e4^y|s+w*zYRf&So?a`=Nrj#~ zTY5G6AqYn+?-OmrVPypRv6BuZpkVcPV}$iAsg#nQ7G463I9Gg5*JX^q+B(gmG~4`e z8xLABn#X;+WAGbC^N8v|h?C={q-Z62Bvd^)lIsTML|w3g7Pw1{ax@_$o4S*PTlkxE zP?AaimH8)urM@StgNsfEoh&$mQm%)WLtH!qi{BjLeuK_v3X0RQeCzDE66PD zhZ8|BNtrz6JEp8fEVd6yYo8#E704;r^#&hFHmk_kKyDM2Tyme

&7aBv@Ett7n^} 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

F!pKFOLU#XkgxQd-eMYAg(zL{1iV# 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 z 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

iyB;TL^0c(ScUZ9UYKsk(F zv3p^*aRlQ2Fyie*{S@0q1%-#dDXHN(DaLHX_NKp!l+o)E&t48M2%<-N-TK*$Hh){& zA^thQ_>E45fJQT|D1D^j+jRld^2kZ2I+IEqrX?snSNo@aUyS)ub&wvJ~G0Rb!tMqCO;h4+Lh? z<_|qt03T^$3`y2$_U+83y_YB3_!_0qyWi9cEsi&YOL3+&h|@6O(9HwBcE<0Ve?MBY z(TzWaJ_kG;1iKq*wpK^e`5t#w9>Bhd|61{J^kVp|W*XQ1jg93>&a1;<}9S_)Ju&@4BNMUL(h_gROi#+3**Q33rUpfp!@mzp7% z8l?KrkqJW+y)scfIi@v9KjI6*w8Q@;D>4jg2oiT&LK1}|EKszu9?iN7cA3ktl4ku5 ziKW%Tt1|0MjK&bJqYqefPOaw#2pMtbgAzsh<2_I`xuS@6C0qTm!Ht)d`i@cC;w zvB!N;$Q(A6ThzLFfOVWY#{U|5y_xo<)ci}+5{EA zsNFpa15Mu}_V;PJq_wzP%=s=<;Xr_p?UvE|_?JX_Ulx6f&;F_(M=KIt-52nPacXDs zC&y_H{DSI()PN^fTg8z)Flm2v8T4X_pPIZCB`APz=l99P6svWwn~1VEFO*~7VJir5 zRgFVhM*ay-gpJA8*vOlv@w8yf9G5@4vOWv8` zl8>$xA=c*JvD;4h^^*TQJ8l04IR*r@>AYk;@@-qJ2Xce0yf4p zScmC8F_{R=Bl65!T2wT-zI9Lo=Qe`C==s6$Jyj0|$l9Yv5Q}D(jL*%zp_`m3$Fq|9 zlxntDg&XwgkdF%#IBwoB=l<&E10kEMIlO8m?R8lwk$PqlbH9=Vfj;P5EmO?E1AeT* z20I%4H)$l6GfA21g|^%$Q_>y9yDk@Fiy$3ahIE7@ELIJt>T9_>G>7YYs3rpai5_4v zQ~5wxLa#13v0YDNo9O1q_5&>%GFZ{UAchORrK8cH?$;PS`&8U-qYZtM)wv z(O*l}`AGJKo~ZY$GX4mVOOV7JuDFY8Bb)|hEMm_QST^)BJcy=fE%9B#@yB#5(|h*> z5=fZ)cV=VGL@lPNN6j|>22*tpM6>M5Vv>`l@BkB586)09`OKG$7K9D>;LI>mPX@BY z0MG+Rywv&QV}}C>pjgk_E<1s`<#S~nWR+$Ufl%MvhaTmB6($I3hZ<|L`2iGr&F;eX zMz4W&e{#b^ufq*HR#(M`|HW}^k!KyOx)aZhzXQ{UR3YGUu3o?oo5NNh98+QA?|1dN z3a?yEArv#5bB)Qd-MTyflGw|^ zHrv%=M7cA6>|bu|IQrSF^?|YaGgNdjA@8q9dbza2TM$quF{LsH?;J)FX0}w*V2riv z#))al%v<>$F`xrm4nt1DN7~;zhfuv#aEiNYGcE9gBJBk|4j=_N{9(jwvTESP)lAFF z{Y}arjAB(V<}n(Cni~Uw6jAUqd)`E?n|S!Zma-M^2(_J2h^W!n*demg#m(*BvJ`q! zI&;)kv&=hsiX1%3dRs{MRaT(rm7Izd$z}#61iTNym#={B!RN`2}hv z9Aw>QvImI%dXa+G;8VQkD=TSK64aw(Mt@Q?$1Na-Z~@xp$W?LFnGg_buQT;K@UT%( z(-_}NYk5|3rv)dT@o1c_ENMnrB3gl{S(Z1?_7vBT%oA&``Y`%dLfz12#)#D9R6Sp#jqM=wo3XmHW87hcW!84Cbs^8`A;uiyf_T0rht^#Rh1u{V z@NeOdXQE3$3mC0#5vFrcX$Pi}C9j4@N6N3wDhdDOAUIyUu&I8nf*SBT)Aeb2#r|G;gbQ;-wDb;nP%V3f3;K93xC-w74-K-(Tzqpqaw(ugenCQQE3dn19Fug@zL-GBIkY8L8o!iSmPo?^If?2by}%kHE(qk%?L!a`~`?naNlhX zz2F05u|S6OC8#qso=A4s5;ycFxzem>7T3#XqhQ-;1M@G#s+p3%*--@Zb(-nJMWUk= zS>Zsck{N(q2<J5RkBow>&xF7L1pA}k3O{0p?`dCaLwAm(m5)vXZ;5B z;kC&G=ll`4m8kL`f5;s~w?^Bn1}^)7(EXW8Y0H3iME0W02a8tm1pqCP4lU@>TxZTci>>YYSsgJw3;A11rQ)W2? zsr!%P;8J1b0=Zh{6eItqO~*Qa;a+iwVKWzCv2S?sLO{4NDp!%|^mj08l9CBbe3YhB zm7?NS-TR+x;YbW)>h}5_UNfXM8SLkKW*N}zusm;sI~1}z_A#HIw(1K9NalIREit&S zOkz6@zl@sQ^)}=24nY^rxAJT|g?NdA{5S4|dRcl+{OS6G5yts+ZGz~zW5mGOtD|U) z@EQxtKs;I8em(URZot*%nn#fWBRC7ZgUg9~BcmC99iQFTsOy{NWk+4_$0ee0L8657DkB=exw3i4>-I6d@!Tmzf&;%>L_;lq!acXe4F ziK~3~p3&%BK<`cwQW90>ST1{5NkP;qLRdBYvUbGq$&t`&Vz)ot^3uR{OJJlOH!+O9 z%=z4iPJ3@00FHq`GMu^-fVbQFt;U4}ycwf)3FJBbfM&|bJNk`gzhEiw0%M-wT?w}= zF;w!DzU&fDSA_V6Cy=ga`$VE1&Iy>)bG#YT%(reK@LyuNuPo({rc<2!X3M=C*@!qG zKcZtE@;X|o(V9?+W!~28Gdjb$MueInQe_%goV;dcPAC-G_0Ri+5g7#wHQf{_rU z2aKz%5DkvysKrgNw{>Q4H<-)Ny3AjDU!k63JmGr$l&#EIP>W8(91rfYp_o_`XqJ*VdGd=;Q`6IZ5xm{xWl_z&djtuzEMLV7jHm} zX~yz)#B?Tn#?C{XX!b}u^@A&C$dEbJjdf(Fa$LGy*3hMiA>Jn#TV4NyA&;+$8&ksv zj*{3>I+%PEU-8Td2nUC5=_KJ_cWuHSDw0kcb&d_z7T76Lf>PM=_xzX;wFazc+N>vr zhGGy$Q<;0Y`3KFVBRjX;x$8r68sVj?35=x7FMq6;$>$kiA%SB52vh1us9~?~9odyg z$FXcVaV)0U0+bu(hTr7FaucV!OhH|)N=5(BHdh)Aw+KZ!{_VGG?0F^7(5Z``=bYM) zk7Ffm{H-rJ-nYxzbN#A8&4lR;W97I3ichG&2LPe_&kCyE9=qRn^hZh`2PT7Z6S}|> zEoA`fSH6o3;Z49cB=Q$Yd3`jDcX3POz{Bk=g^#P+Nza(VED!)$?TcQqaLAeLrI|bKyB0J zGDosx78!&9DD7;Edxaav(5}}mV6!R!rsSj5$IaeV%L%dIfHs5vWzP@3$#f{>`M<4I zP*yFZPqDr*#M#|kS{oJFC2)wWxsSn^kp7P8N||qw*vpOeQR2i3P`@vJ2`7M_wvZ5 z+#%4WNlZhff?Bwfevq>sWZCBss8O-&>TWBjcoH>oBlOx*?*bzipS@&!zd>tPxlbE2 zFo?Ru>{_1Dk0NGSc{rEY`FYjuL7R?8!z&0DiRlFw1!dexDB2iz^ME$l!D)TQC34r% z2$ko2=vazvJ5?TAC(`em&zB25iC$4!oAkI|oqdY6)iZu%HPy7fTT1C4E0f!Frp?0g z!sJQWf?{34l-`vK`+-adzy>M5EE5>=*TmGbyn;z1l~e?M8Ch5czTfU?Kugp&knR9w zqd{1cf%iR>jP#U5{tI~DZ&8miKwy(oNS_8NWkcm2vJLTM$$WgJDNl1JfJaAb+YSBn zQQKwp?7E?&DRXaXz0DI-Tsk8qc;2Lci3Ihn_S?s`X@rX)Rr!{vOqe?;ZYn29OS&4D zB`nM`ideFC)*XmL0}JewZ8L zUhkGf5A9=%^=n-<722+ueY>b%*Yv3sYQV`cui7vEtw_5A=suDMG09PoAZzMnIHiA> zRINu7au*598mC}V2cQB#XE%E^bFmE0f;M?Wo{?O<($`&ZL*dW)Xp*oey6b=hVY>4 zBtqgdgMfQ9Rr56!^43zlLFq+GKn1bW$NqrHLXK`*kEL4=QPsgUQy(?fxTf*VY%DVb z@cXV4QKpm4Ijb&UWtKDwJc*UIf?Q_xY!We79xV!zKTWLyuin`MH|)YX%crx*oE1+r z;Fz^7vADxE8DZF+7N-BBifbAJZT#sO(u5Tx9|r}8i%-E)U3XTTVxp7+mh^<|N+;G?E~|HyUWy+296NbmvJBrHQocrUwG0QnF=iIi z?W01e-u|d~Df0hhBi0zTUugQL?2>*#Pp>RS-RSm-Ht|`a?;NVL{00i`F72`G7#stZ zm4FrdthdTa7WQicCq!lR&_4=fEo%}Wr(_~$IU=`uw$_J^mE9C%$BDwfoCX~l5(u+Z z{uyHR*Xsp5;-nEC5(@GeFMou*zElrSQ_bWyvRZbr00P*9TK-kefaB94(72oX>@8oAAfD4y+Tj8ZXrWyWR^g`_5 zo&54(CY09v<fBZMwlvCVnuUAmm7s`L^G=^Q?llM-Bd9gM0?q zxcqjENb0o%H63gVeCtT{U@vM-Xp?^7iAiC}YgHcsA9=dh4CYSpdXr)ZQb^k{5v(KZ zVfsv2cK&G{KasSHrvTTvqi$BN0*D8g9LPJN4cc7aak|>#do0Xsu8-97R5C_SV|Mo| zJa3!N+vpWXSaWg_a{-k!VC`(B&qO~}=YHM1wcv2H-9|YJg=(7kW+b#6c9eCuE?WS@ zLNSrM083`nXI8L}*~iV2f?vxd$a)}W4thS8;?mK%9>1+MTMZ(16;^8*8`Nb38o{0n z{O0$YcIW?l-l!>JSNNQd$X%e(WKlY&l&@-dTJ{#l(|*Hv^{#F7FL7wMMw4Sh-v1SW z3`NV<@u6HlXQTWJJX8R2r{l@QZ+Q0Y?9#i+_uzq4F5qZWy7v3O24XD&x+VK3xqLW~ z@(yllLrUMbLAsHA7itD}&QuIW>q-7!E zzZEjmTi}PocqYF~o*85;)F+OqYvr+?JMNWg>=%+E)(6e7O~`2zcBi!m+95b*-`O%2 zt+>8hg??1Vu}8QSw2~EK-CXO_H{1v?qXsh<6$EEswJ}bLCu}>E!OI99H=H9qpC*ef z_M8Pu=8#0l?wzH}L~?7-$KJs{3gOnq>wO7@#t;>I6q&MKBF;GVo8HhiR^IlyL%4x0 zcX4o2VV!9T$G6z;E$%G-RV{Q|E1f!N!=VjHnC=uY!MN}}lX=DR7}@c8#+@HEfFZ>$ zNn_4N_7Wm5-0z64zJiYIu%7{?dic;oO(~<17a1)uvA~1YlB_0Z=n#5tzE$x)eZmK_ z&jM>iR9_(v<_Z#{nQ%35_|TU`jWZ^&8cL1K&CP}K7kS@5d^6%~-D&U?eXdJ3;5l1H zxFpI+G@xl}bIJN-w~-P;$~bdkdihd1 zx`y;_TprznG+!haCf-uLJqek{!PooP{xYqO=M{r**nbH>=V_WWhE6)OG$PEy zThbf<4B?MkKUDQv7a7Fl+pO6~4((4@(%CHIe?4lTfPm8F*q`cn0yW1KEhO@YcT(FW z{0npHMM&wgiK(Is^Qg=aZ6Aq;YsVFrZps#!Sf9nvw`;}e96TY>=>bGQ9osU3;9VVL z#KV>TSKqY>dXv5~A?W5H3ZBm3!aK*YmZnD<7yE^Jm~CBNUfXA{aR6uQ0!nG)wKiOL z0ODe_HLF>nj^dz&G+mHh#cYwNeTuVCM_OZKcK;Lu(X zw0z>h&c7{}%xeD;Q~-u?PMEy&>g`-nH$yy5)73B1!Jvkk^^7cJ{+Q>Fi52V;wf#nP zkFgtO`q$-C?>N;j9|XB&b}}eQL;aJwURGIA)FK{CqFVqS&S0*uHX{u63j-X0E+}&C zICdFqC)e3f2tZ5;&40zZCSX?hCB1pt`1eH#wCgHiz!bD02pkkbhmLZv^~#h5uK^3Q zf~Q(bvZF2;sdUo#o1@~3Ln}N|pTA7E1tQ6l8!JOFlMVq%?yuxN2%1LQk?$F(RZ^A` z*re(@=n$PU)5N2V)+a=lNb~^}(JwY0LrKaBc$ho(CLT?t|^t$kn0_+#a@Px+o-K>$^UJK`j3H7(!Q9wd3d1UxquaYU3SwGszpe(eanEkU1$o2u< zr|fx=xxqENdpc?hxY+1D0)M@sS-WJW-{9QiwStCLJ?gKpqo!!fk*l`+k#RUYJI@D{T50%@NRbtDuq*YsYS)qJQ zP2`b3ysEmycQz9Kj(+dJN?+4)Ux^3A$^))Janio@`LH%pUjr$1-)&d~&#p;?a%%=;QAwiB{Z{c$b`;wy(#m!Um0;j&v>Fp9mBM<-S_<-IgNRY9 zfDV4|;-O2$PL+kI&W0y))16wWWmQ5vwwA%ed79W3@;U$~~Z3Ix=Dvp#+DQI4@Unf*$zSvS_dH<@>uEEDJ=Lo{dlPwv1@h5*AH@&i+V3xf=lsheMgcxA{;o`3Y?ZAPo0pEw(%Vw6LDg`vE@1p$j zpA`rReUtkh=2())DSosh-|zbt=?cLhZ-hXFJu7owW#NM{BBV2-+i zE)Gz+JJkVjJi%$g<6iJmLri`?AC(vgU>ckShRKS-o?h+lnfD@zT@q0ZYvZJ=E{DAh z;!*cf)b}8Ig}G}}+y5zC_8Z)Eb@U>kiwLaGyOqyJnoSK;bC<+ey3lbQ>cCGNPa6#F*D#Py;N-hR*V!xv-)`tS<1U^!UElB=97c z4QN+j+-rLTi%>Ff5A3|jGXQnqwc6garHojVg)Ho6O$zT(xnxkEjC_I}t=W2r@%Vnj z`d*f`&Z}}s+JE)%rLdPs^%G#)D*K-tol(guhcChBB)I z)4Sx7Eh2o#3uKp7_~M!*fGgN5Q>sQQzAkZih#%l-XK}KjWBo-GTuE zoT$*4%lAa?Z?2GJX)yxHy$Yd*7OAQ*M70BC6;v`H)kmb>_q4)9g3A9|v{7V=8#i0o zSwo{-s>GEC7v_$r;n}QV1L0U^CamM67v+KB;K0^(DjZ{U%7b`d6wi*l=o5?AlE?v? zrr%hb9VyNLq_8#G#X3K0+Tt=>O83R82hrfqX}_L>$1YSCMt#nEk0=Ol!fVJn$n)cl zqc*8JD5+MnnFtnJS4fBsic4Swj1Ln&9%?bM*!kq^2zo}3%Gar}6i5bRDt-u-Vh0%` zCJldg3+HI=Kt!LGm@+GyB%*<3+OVM%mBD@G+)|-Mg|K*eSdD*N>)U68Tk*Q##`RhM z6{EhBVC}?uJkZlZ=Yc6$}z222oFv&Dsp}-uVep z<*U9$=ni99uTtDSC)yyL(KnoZIXwe;?n)zED6fmwcE|Y0%6%|>IHIp~E^MPEFrU9( zqcld|UEla>gF1VaFtFf3WkI;?yi~HhJZ{JoP@7}0G7JWP(#CVG9F*=!Qft|W9357S zqBB4mTF>^7WPx;$wLd7d+iS?Jv*lYt$~weGj4JTn4Sk4BhT<_YdI)^-HE>ES463Jr z5DoOsGevCGE8h~LnMC9BEkx@Pej_}7u!&SAk%4&0Dgyy|{LUYmn!+@L$)NLeMVF`A z(@CSqbVbrq^cm=2EJa63pA8%tpeu9l)F^>pteY3DY~wnDV%SN)jJqHT43Gdn#4M{Is6i{ z%wPqff@dyR=rQQJr@J|Y)1lJbYYzE}--`q|UG#s%9DJXcE@W_|A6;&=IDgu#Zcxqt z;G0$)%c9U#5aBJUBSeJJfh^HaU3AIe43F@v6p5b*a;sFD7U9O+&|Y&HlA6_LFR_fD zk;y|d>Ht~$577J!Yufxf&i7^dk40Ys2odSr~<)tv!cog?Y1d@b7C9&e%a4 zI+0<&TKzhj3>ym~bdWks<*`0R3NpmJ1@&esXNUwntgQpU&k5~1ruSp^fdEG;*T5&7 z6$MlB8&7!;+B=wD#b`&5v(;`Nn+sNz9?82W+2(~HnuPh$juc+2jy_IIlJQ?<=W`k} zXLZN8Ji$Y3E&Mp@Ev>dOw+R)o^84Nk*>3P3BPgM_9DYLyYbFuTh7Gr;%>`yfFMWLs zIuaS(`Z-;ieFV-b#7rT>lF>az(#Ql=iE4&Z&4#m74Kv`UW zxt-RW!0a%;%M#YTZOK{IU?Wms5v;Cfy6Z-><~BxQ2V!|o)@-Ekwl-zA8a8*X+_9k; z^xATEbKu-w>?n#6Xd^0IJ!hokPDUI<&zwAY$7q;w5Bu+CGZC}tWm_AKiF+TF%TbsJ z0C7Fi`n6xegi}6Opei-TAC%1ZhV(AW>W6IgDWXF!wHyt zCHWCKdEK;YIo}HPGCPeO|7Rik0Cv{RFj#v2tRYiDrS5;(C^)AcT8nd%W9_n*#Y~y- z``V-y>mmv^LE#q3FK5rzd{KcyVuXJ_uB|F^ zHLdk&@l10nK)`lazTQt@r&8;=v_-r&E)owo{uCuBPsGzZXOOg|!2csW|L-jtG_LE8 zFVl~^LOOcSK=1Zq2CLF85QsHa!;^tK^KgzvvbGEuvd|v7OPeazld)}0M&&~!cd^4BOEJ)gg0^idYURus!`{@jV^?|sn{cmV#ky(BVnkw zaMMvwOlRfR*R5(CXg3L@>sm7qT(%?%mQ74y zT(?fd>fi0LT$ZJGBl+6B;EX9H2k*5>sb02q#kjp>-4%FH3=vj0$mly*ACLio`o{+7 zqWn9f0iHKca0`(jzzpm-nJ}kJ_yF@@kDD#|lT10}V#E`(xz)U=Ur^5aB31S;?qMS! z$s>+tG`inHTx)yvu0bTZ_T4w=>BCZbH@r#yidkO)Ylp<>kv<<)y42u+(*XN*8G1h0V$`Jhz4ETgDdugzr zONuWt_zsqj*?;K67cu^R#6-%Jg^Y*IK5Za8bvyCPJu`8{gGV46E#DBklBCNnY6?JVxty`sT(4UT834u7`;b4|e+>_{| zDbf-r;8MC{^RU^*r?w7GP}c~HPn?67>I@;vEh5vX~&2NFVeT^GWKzLAG%-}(Qh7P^J#P56pH~WT zl^dF+jw(HS;V$AepTwKdyY9v-*44ZGQCr++Lq9f&_MJQ8r<#!n%f$XKKO~#$jpl`AB+!84fTg0)zp@>M5 z!)@!Oi#bj{k}O5DY_V0-$=VXy&L^ZM=QU2;Em+n_aq4?6`?vcPbo$QlJR~X3)fW>U zghZQVmsZ@hdZN5mf_k153sL!Z*>|W|TrdM^m5S|u#*D2yWax;aiSpya(0v+}1yncA z;GQ#ly4L)8*B*f;Sf!z?-SZR+mn5GG2jJC`tca`_sI07*c$zYF;*hTs;9R7LQU zgZf=FHFVlQT~jjxvSZrNlaG9@bTPo)^VG~`rnyU~Y{5jvkqxhVLO<-OaX>-th{fvO zNldrkJ}VvqGDPxlpGyb2);9|1eDvifhq?U8R!+!cF9UPUy;nkDi7|y{&QX2GDGIp9TXDIKrgd3j!~8k9mXLbQ{@DHfE$aZtTAuSoleOe z_ysrMnX>PaHOc5zPZA0MnIr{8|MOm+xlJ2{1ScagH9EqoYFU{c>tB4Xw>@iqc-8cb zynW6#?vg}-X-!9YMxNIvc^L9SjEe66OFOls9;c{4orA6Zhs4pk_@RpB7Ap>X8NHRm z6__0<1>-rmt!FL}-3zQJh3g=OE-c$1{}Ok#|4)PR|GaA!i)^t4*HUdrr79+{%E-x%jjj#q}(h; zS)rSHwI>3OO+jEIOm7lgYU$;05f3YDswi2+Dx3!)L;^iHsJPI7rRO?eRa08T@s9Ba z;^6i=66{os5y94_Zn(5Up*VdKBWsty!MBt^i2A>&3SS>p1BD&C@l(l-zA|i8aA7FD z{bkETxfso0j<{24B5#d@7A_{*&sK-Ylv%@d>VL-NSd;R6(<~-LLL00qG=n`ob6(j3 zoUl?g-JyNtQ~KZ36W>X_T1m~?8Mei}Tj}Xpb%Bp!Cyy$qDkCL6ngt*IU^9uf| zc`Ic+jS8plHaLdd4h(-wpenU3Q=%OSR&WIX)SP{UD@mq&fvl)DKTd-WlDv`L&2g;~ zNdRaSx4NvJU&RCK+6pJ-J+HnbVxaK3H3wQ#y_BpgOPGUN9$muG1KE?Od2dcn)IIW8 zJqB4%sT^9Jn}1~M;-}czu2xknwC(|$zK_=H)ZNE_CoPaUb7x=!o=>kRQ!H(+zjn5< zgIJ1O=vF}G9AyxY@tyv%mMb;Nyo~)dXFn7JoHM~+H_~d3%v6}Of^aXo0+-EO4yP%4(^7-N^~_{#wl4=u6Dulg^!D`o$CLvtkRD3_m+D_})!+#yxzQ5j z>1?HwEu4~i?zGw+%YG305wW34>!TH^=&q-24#*@x8 z6UQNgjV~MPW2v}sip*i9B$8^(J2;UloZbyZUey7nmPe`*W%{fn!9dz0TT!fs%O{G;)qSne4Hwjp-fbVk3z8 zVl$!(iCM41y=0Ay4@niPl?D_!U_P>4n497Q@SV*56@tyrUFw<$fB6^zouAEvC3tkd ztTUdXN9M;y6*G{N@tA}Ij-4VNr|WZo#Uzgto%OanqlwGGW;T75> z%iSO`B!Ftft_58qAG3}mmK5kZSnagI zL(}h5aaBJHd)x+EMtn7@fcMD_2%s-BJ0q(!%O^lK`v;NpzrLn?vl3Dlc2OUF!M3&& zcv-JW{)--PFfp{hn}*u@t4O0B9+-`W0D6xF|2N6HkY-4{-e4L+&bXuJ(Ij+x6K@4f z=KewuO)Z2YNJ)+d9+P8Eu!-)7P7Bu;*><~zC>ejKRlVCsC|vHHbFD3RmLaVVKy+4S7^@gv}Gr)x^Q z-#mK`Zyeit(M13_$$K+q$g5eVJkfHY2!{+~mg4X9g9AR=ryAVCv zLJDEM`5<8Q<%AeC^z@W^_)gJN)Q9k~i5f5+%-D*ee!TusA|lM#p!YJUBom1>!m4?h z5m_JX$u5c(uvV{^Fm$1`sb$?0O3F0DO+#1$i>j2bRfA!hV>H-VW~DMJxmqw0;|MGN zE?6Y4tGOXNpun`{q6b;x;+drSKIm%)ICxo;Ieo^Ap1dv2?V-(snFuzD0hsxjYXg=Z zh#!MaO+8!c&69khXU<_;uR@VT_ccNQQH5k?!|OeX0JRKRH(9o494jK=mFM4fHI@{m zU-=sP!3FvR2hLI3eG*aONxf&i!=4=+yF%S$8no98-O{?HA;RqHKU(5JKaP6de- z*8DZvxMSlu2~}ViX-v--#ld$T6JmZ~*Qn9Yw;~=JD{jNJTi>GW*pzUl zKnv*<#;P7>D_FvAWHqG`cMbtl#<0S&-wCIl4S|WhSVL%1%_;eNYTHPP?1Rwm_;H^R z-Kx&l5sFThF^8QZ^U>80o_(CF$pAltsAKt4o z+TKW<64(SxJP{DMxnC-j`r-v)i7UW=`$GD`f&!{Uf&@-?!6-}YXU42*WcMVYECX&} z^rLq7KEECOQbjGT7+SpDLbajWA=^0J2=;z@ZFu{GG$!p|KBixOYs;~T(4zsBNePY* zR!o*B8{l3YIx_bRPTnEh4wF6GXLPDKd8R%`_m6CO)FELAo z^&>A|h&Fpruty(90BTbVkyy+A+#S<0cc9war1P&qKkInn51xjf{E-n*iya)Eu?shw zVhj``CqT69_LpsY^uEGT-LgBz^mMU5hZ#ZR*ih2cPX6Np+AA{{Y{s8|OfxXQkO8ID zEvOkhV%F7eWFQmcM4ht9?AeRev)T{=&FqU%tTEh3t6)ZuNT^C++pU1jehN9xfS*g` zI+V@exn(g%=_^FfGDNXL=|atsHP1k|64)LR(#3i&s%{z*xeO0BlCal@4Py~Df>q;A z2zSv2_?qYJxS45sci|}V(-rB$uW>kl#&AsOI>~KkwCT7(;9lGU{|hOpq<-SH+JS&R zcNB1fjs9Gf@AO6d=>;DCmeei<6mTutsTu{LKMFF}q&g}{EHEAo2mj=J+%z7Y@aQdZ z;}2v3{VzV7iXxp`LwGzMaMJiN!l4P=-dc9WItZ=K6tFF&1K1pj2=xh|g)jF#doPAD z*3(X|Td&`Zf+}UtYq&o!4iup}$71m;xaaFipc-z^w4d%~u;FAfPA%+SGSAv*K=}TK z7NEW!rN1Rv?!ITlsh9pBeLYF7Et{7#bH^GdiS%-NlEK%F?~3%GGA~L;sA^5DNqo#0 z%bp)lRhvV`R#1-0He@P6lDojx2^6f1zH-gs=`l)v@#gJ9gxOPooeycs9r;A=v`CbL z-fqRR95@CRb&i%_@gBuJNvA{EY$%A)sH$l`{?`Lj?N4gP23aU&JG;5lE2%`)9lA^{#Dxz4E@BZI(&~i`Jww zDGq>S3@sV4P!3D-8rI&LpUniygwd|QbzHkqF5GshT@foCp);P3ryGCLu?&@2e&5>G z42vRGIGL@RXRfxHN;S(3zA!e&D?+-GsoLjYk~00+)bP;3K81T@=LbB%A-!&r@4*@a z95*;NAs|W^NE~P+(4Jh=dWanKVx-d8!3B*=dppTT$=bi})bQH+jv1gY_wgFO!|bZj z0;}A1H;X_hF0XgIB=pH*rTc$aUEo%p4b{8SX!dRMso$Oj=S{QqjY&{h@2h(!k4j1; zNF4`#N2JFt)dO}uO2G7QMm(Z8Ra{8S3*Wk2QW*ttzurOgKwHS-~=Tx|0c}tq#_YZ zmVPcy&dCLd!u*-V3n&tifz|rD?s)b9EIlpSX!;C_R|B^6Y))H|s*qxnnk;=PS`6tr z)PR-OqCn#X{k?N){Sm_Dn>P$0q7@;(pbJ~}AGs|<>+pYHunAP^hv|WJQ8MWnbyW29 zTj*^AkNz0Lo!wN{YyzwQ3^S^IzFy$EM9O9g&PS#RrWdM=7j80L=4Ae+XOxy}UtW;= z5<^Tc_pr2GwS9N#%@*RK3qPj{$32?dzht^FL?t=y+I9Hc^V@)U@}=-A)OF_~7hs>V zxb%Pd_|K79n*OukY=C~>F`U?Ngp!!x-On~f#wu7ils5u^>=7@&o^zAQvc;(Vo0gsP zaN6g>TLsVO$)=T;JxDat0PrJ~KopFyGKsJS+EKZEB;tu4%jqS~VEXYUi(Z*>vQ-cT zlo9TqSlf_4WFKkqzLyoIyNllr$D-J+{+~)c6E97g!#vZ8(-lwa3ugD^n!q!9m)HY_ zw1_KpdBYnF?U;rM6S|=HqyolBCUJtU0x_3 ziU8kb4;xCu7x?-vz}!MNBBJd+745N_GyS=Fc~W#_%ySDUwtpuIS@itj^Sbadv;I z!3Lw1qd#iyO3}E#{oX1%9lP8n#Huy;|3t20?yK3B*-0BaHJX=p^jlP+A9#EGV?=~+ z^pg2Mf+z`ykg6)(;2O%LP(~;Xr@nedKHq+Ovz@md&wx>-2f z)JIjrj@_sYY7g#;K?Izj@NWIHEc+zmz6^OXGG&B(A8uqt1Z<5$x-sXxZTVx?h2^+e z1%qXdIo&gwAVPM9j-UmzTV@SNYxy19wc%!LldmFd?=>?K$lEWZj;Wc}n8A6-DL`Wc z>1O?o33-cfQKg2uI!`xCqIPKYvnnSghEqUyqf^DFIql~8b*XsFGLHtKdnfL)g7R{KRgli~A*8zsZ zH0HKdk2I1w$8^PaqZ@(ZF_x&yQ{nbj!hwlKtu*5wW|y)$wvS#WDUKHoS6phd&C{9m}=OW*yXshUiTt zczwl&YxF(G<+Atot7oLsdJ1TR!93#lRHdyGMTbSf^XyBu1u;S$(tw9?TyO9&mlzB= z_)kF>n?KA7r^nUgs+1Rjjx_u|17Dr44cbTdb$&4(Zv`C;H))1m37!N04xfu`9oCP; zMromP-a(^g?p1nT!vCRXA_mE2v{^8Fa6|^N)or(Z4~;wW{vfp=s)t4o5q$ry6@nK} zm__RN>NZ^8p_}AA)Bm0NtB$HAdhwZBKIwxyJ$mAhdj1tZmbJ)q520EI{`I>?h4h#$ zHr^d0I3+-!k~qR&su&$VWtb<6ao&sLi3gVcYFs*xc_Qutw|84_c|eWrG3W@`kS1lv z_8-_4weJ#+%MLjeCVP|v82^vgv6p3^T#$^gT>ipAi$ehPy>#Xv>mCv}y44dUkA8!0 z?8Cer><>>^*())@=RNFbU0#gOP;&YxVGGD*{pg#XI5ktxbO%nWh+i4-Fiz~TxN|*U zx6$k3Sq@BADp>0C6amSv4Q?nl#aR5x?_8KHCA~pSXTS1RhT=K6e5A(eY+|u!+`%IH zT^8FLRm((-4e{KCz&-qNod0C!6~2h5tjrSuIw}5n!`1V5J@A8UJeRw$e+3m*(Z{*P z2A^@DgEZG7RRB=~a9Z<~^kl#}6eRlNRWY$HtZ8}oVj~#EEgbRly_Io;lbPF0Q!HZp z7B*MePU4VAEqH_#?0J~C`CS=qE=-eiIZ=D>!v4`6kQ$czA;yn?$k!UT8eO@KX=u(r zU-;`B$%DoQX$Y@HC%Dt05KF6}8SOC=s?&UATe@(?E|+ z8L2OWh3LiHnA|V|E$A7O01K=eIw2gsH#9yq);f?n&2zyT;Y@_&-< z&ug$|yJMzG6L*6ApkZ%3+$uZUz@||ltX756)RQ_HN>%VaaTxGH;_fj?i3WhO{wXF1W5 z(aIb{xBb^!<Q>i|Mu7_NK`zi&`EGH3LU&vi6<@o1L-lA?}IRk{Dm9OPcroSzvFADt*3ld&FS)k;;qZ9Q9jshfKG_X*Kx!t|4Gly?ZR#t*-(;sn-_WoDs?FH59QC(;#&p3tI z*QpRjZy&#A-=@$jFhV?Tt!0M)nbVx*Um5y;D4+YlRWx|f8Z`!hGJM8@#L+dD4xKXXP zL=9`>gHsax>b$zm$FJA`Q{#d^YqM2#;coos0uvwg<|eCr-h+Xqsr)aUjY@?$1@(F| zJ!Ly*?ZXku@ZdA_U9bTw#&MK00fiBUz0~F zC^ZqL3y;0xJwYvS24M@Wc}!__Zc5r&CN6>=!Uii&WDPfVSb-g~<|WsE21(kOpXZ1dw#2PXBGk8M`ojP0_qz~M^FW0g0BG5dOe z2C6YSQ%HkzB|(4>_$01g#WZQMVnH6vzik||o7d}Snh01tVYA*-QQ23s3V7;X^wEFU zuhWbKlCKu&oU?aBZ;Z+ZHtT0I3|m@#OO5T^dj3^Q>)VR||ebUV$02mwGcndz~A%Hvi$pHP$u-7kuMOCgSP zOl+AB?VjHkFn62c4S^)k2cwiH`T!d50vO5DKB4LbCx(QEi^Nzg^K6J;-0}sz_)6d~ z^~AQHatkg6Yz;&K10eIzcYmp4i6x6Bh-)Kks`M&Vi1#FmIl>f#Ovi21X;sC=s#NCwB?@@Qfph92%L z8afHuR-f7O1&bhSWkyWUKn8q=3b%GdKM#Mew|3p6x3j`omw12MYLDp$wiT|fU$n1C z#q5|ouBUZh;+RGw+PU@cC#-k3?(4mO6eq~x3dI0Lllkcwx;%}ScE~#Op;PeLaFftK z0CViDsU-K|tFr(aQRmPmIt3ZXqNv^>E1f|gfjV`)U#$O(`~!y|DReD|Fy)505=~?% zD^3a;%fhpb4t4xaH_fi|4Y3U2IH#L{PJXWzeZ6$*%#yp-&>t>~c96_|P0{cmD+Xy7 zR%LVCM71iv*_G!uELiFc6Q0HjDK@YABtV5q@fI<+|FBL$Hf@EArcs%Hy*K80&8>EZ ze+`&BM%tHa>1aDglG0k6>y3}x?>FS6(kA>1#x_|<4jB0Mk80}Rn6o8euQ=tx(Ps${ zlrDZ^XA_`OrK1(9VvOJjJhH%2+U3k2RWZgFMwpV9w#WscN9-*zs%i|Fe3aRtTDVM3X+ch zPiZhh>4`)ezx|@-O1#}7l^ySLjdCOSjOC%=US&`|2G3)q;zBY#Ts8K8RCVDO?nD}O zE8gXW^(yhd{b!rp{byK#cjQ7I4N5W@#U)oZ>d5aP)?OgeAf?JK)%nnd>H$d`je=Gw z<5%};5R1=cLN|)o#t6)~xcLgX1#6Pz0c_u{;WQp1aM6CWk|=BC`$?M|#C(_jl?cCX zg{}~9YS*t6A2$g;<}_0i4cvcEM%W3^%a-FGG0yt$pJ&x^8xBxm#koNQ55eF>tQaax zO2Y|DbUx$;8`zp#)?)J1PHw5E1s?dywDYN{sA5>r5`-T2x*zw0NLeTc4`wPB2=ZH&}(ooeGktTT?#Os}Jx_5KNi_W<<6 zE*E=wrC%qNg!^t-h@#3U`ra$+VFB;)4MmVeljR**nlg7kb5Z+3i#&kh#^&O@95BTH z)}h-6#3BB&m`Bq6xrL_kxo|GlU+~$-E8*&VS*0l{fO_r7u}x|WDr|**wA7((tdv|Q zvAa?-r7wm1d4ztgrKGzPJ9A&A9hMlC>Rj(;UB~6!L#*WoJD(0>OiA?Wfyead^|w5@ z2$s2A9w6};Ek1`}>w|dBTogYd_2N=Rc)hg)*83z!`NM2PEO)UQ?PAJZCcADoSj(67tdZnMFNi%Y3@VarRs`uSt<>KKdufgI?FWXEXR*^L0r%`7)M`v zt=KAQ2X?+9jD8R&}39-qdL0bqFT@mljE>Ix9{NIxI~w1vRzk_d43xk%lQImoPrK2wU= zgEI9^apQ*W)@7O%8QBn=Ws7?~Xl;<-2;tQE5&S@70G2JJn3|+eVs&Yv!sJ+o5yb4m z`=$w$NgB9%3bS}Fqc%l35Y^Y7)imtoZ0AA|&$h+g2Gh1)zc#j}qKR$zscb#4_mz$$ z14$!}WoQVFZVrnrye*PMdIkVWf|zKH1&57zMp5$+YWiAWePygo;B@Tp!Tl0jGE?vb zJY)vvhq^6H!SVfYc?@E+{N^`y@70ihTP4GS1@tojuW=YEL3*;Q-inu1`sC0IgCW}C z@QvlmlKx(hS1B4xDUJoXGUDkuKT?6c%bVU5+zhW`rcVXJL%P6Np0I-O+2mU=dfCT{ zrNA@p?b01TbzeDP^&-S8`uDK3udy%gHg4_nK* z?k^Z}pzlnEVw>JT(M$9CZqtmM15qgKIFjHDr#+OH;Ay4s_-vEz@rk3&PxMaW~4sfiSv`8_gw(e#uVBR%j>Rs_G6%bzcZb&Fe z3p|r;PJr?6kJY)_F|#1V{4k#H|GCE~N1vfBgcsbQEd1w{m+n&k`zKcC~wJ8(F+{XCaJhe^zG(<=aJn=(jnifR`B1BO{byuhk)TFvKcc|N8{u-?6}MD0M`08g1+Jq+#~@3}^W+Fj-b`}89QZ_5Ww zYGdIQ=)%pZ%}N6hFQ?ZI8>jY(@o*#V;EX8{3)v{VPp4m%EV?eaBGwikEIthIt+0yp zaTXmq@uGHgxZxIS(DfC3^AGC@pUfo>_cSu9u0LMY=V%n|;n=(0&FXYfFG$fBvC?C{ z>TDsq?NXg4kyBcL{Yyz@T+!Dc^sNKj!dLF=p!Fp4S<9>tPfHVpJtGAzk{X z-a1rABUGc6bUp@gE)W-#%slHPuW6by#8g_4bHcebD^L^w1EJLq(xL31K2~#^5^zLm$`K zowRbR#LfO4VR0IQ%i8~Qh{bbk>6>AXiK1rdS?`h+Xb9s01&xgun|6tF;8zby2MECT z;s_@CyE3oX9p#&}fWJ^P47UtqiXrfmAK*%$LvIhY!lq??Gl;Z0H+DsPl4p$gYN7!s zwKGlgnTg5(#4$HVnaO4PpO6xC>q$E5-t(kkLL;Ev+FhGE2Dyha zSP12%^3ipLH9#OLhpr-&J5nLd9DgrVhRGvRkbeI6lQZ)JWMr`b64tlNK;UZdBaC{CBMGtc|0N?TUMZU=rp`4Lx7&BxY(K zqRn$TO-s5n*rZZSV69lEV64Ym>FF3lU@kb6fld{#-(3^S71YFrOXEySOzX`(Rmy#m znSN&O^WeSjKjrl4l*QJTD^^DdS~yNUF|WU9Ok$P%oHBdj0PiLVS3@fU>`Zv(oib8v zf)Q}npGY|No`?fPw7XTn3whfhOvp_f;vt~zMzA_1K_k;hE`vvDRtz@%Q3fV=Pfl=n zl9I6PJ!oLDxEci?{6_ZuPxeJ92d6RWkW-t+2be8G_t!uNIYO$25QUX?#PEozD zShF`Q)323+sk2U*HK3l>Ca!X1g4))1()3DA06ucuP@}w?GAsA6lEXw-ZBYOF-z#XqE*;&s!Ib5h{?p=S-oolfKMm`Umsy$__g>En zoin=IOkYkgnw)S{TmnPT+~^z=h;;&4)CH1`b1LJUZite8$8B*X*R$n!@H(5o-~o$z zm}?{JZtwM>!JNjEQ#OA`>8wl(S7OEO9=PKfQbA=tpv1{k3lzQLyC;hBT_8)jZRIBM zZt1QnDP=`;BoA;l^`80E58q#Ys%Ayk?u9Tml$>%`*4`Fy)m~KWN$Ft5<&w?6sKF2> zk|GQ`RVn|h#+ia&OyO7=hq#KfCLc9m{vBTXM?!rA>Q}O!V!SSKAYC+agLE z>H9W`GJ`f=KEiHHpzWsCOj)^b21L@mNd9~4JZiOenRH7{0Vt+g@&wqaMixE0ayZ`jTuvE%3b)I zrmkYHah#6u^DH-q{^ttc54JLdNg_5Qw$0eG&J{w;d?wQ0(qm`^3R9(d^{6Zo4S{nL zR;)e9CgpZn9^9fMLpR?AcT?A#;Vh<76gUh}7um$-%Q<3q5GY3KpjANtv0y+Bg?3%D zl2J1A`a7Gsy$9lz`d0u2$HXJqaXI;t|0K(nPtmV7EMWnaN)p(ZG8y!8a@@X4M#Pi( zCLj|RrOV)nJzZ51kSH%kpf2|5IgUqXB50vGQGU&I;6LUMtTBH@P|~Y3(cI{iek(j7 z+-B)R1k9kep94le-`nKlB;S60#zaep)!(Q9eEBva(<#c}!2$ArGtcV~Ogr3EQF@f| zD8I84Sal%l{d!J5^+V7kJS-StcF#p44=?@|Z37R{jWR)vZgLsxz1X=);$GgHHA9Q? zSRIneG2uYNfQIc_Gde4y!G4JT^5vQk%YcNL%F4UDR(eptHe!WGAb#!h-%5dT0MJx9 zIkqsZc*wlo?vEoe|DqQx@1|g4)YT;O!9^3SI4sEH69HP+_UZNZX(P@dV!OUlgXq>-z#w2 z7q1TCJ-T!j%P=QRu1H>Pz% zBdVFg7dUp1oddmrjg5w&t=@YrPR8a9^7hjbi%&$&*}J>;n8!L(0a|(LLIU1nyr_5D z7_MkT^$Ch&x)a_5`N%kQY)kpIk_5aH%{4TAIhY*FqiezIp(INv4*>t`kMK(!`~%y; zc?LWDY=Vp(4f1j|P&VdEKb4D~?S`}k_gg0(ess`xRq)vUnRTewtN-)o?|vp)UEhb^jEe>$$F&+mIK#wB0%X6g3B|3K_d_rHqoznal!Dmy6TQ)5hNhLG57&Gd{s68V)Y1q0x*BM+ ze?`@4-YFkb6M!yVzheBoa;m=6)ccFhl1*vosOcXsnybvGp&VdNjJ1mfgz~`P5kxrf zZFrT3q&9VN>K`-+&EK}^(=hd8Wz^5!5rnOsr;q1om`WbSVyD{dF^OPfzBm7*3M?t) zG*DZyRPvXf(m-$lp5o7zb8Vr^@R#^0)%uCZWdJTb)|D2>3*IYyH~5PgL+*1UFJdt{ z3F93|=MH+`M1y4$m3boMGe%SlF3!u|MV@HOKoA*I%=D;*w&F`^D&9&-c6ZME(cG)Z zdWV(2^!UE*tzsMQa9fF--XLB8zIJ<@bc#<^6#&*`$tZ$ax4tKZp=3OZ2tg!)1=isZTw9yhb2<1kEHXHeT;7$+r(E)+$VFNH*N zez8Bcs5i)I@5Thjicaq`M3W5;+oxU`#am#ZrU>`|XtAlC#?M2K+bzgeel36Pj%OfT zo#WD5*~xg30uSf9pDWWAku2E14Anh~A1POz7Lyoh%g% zg&auW|C0K8d}nt-hC(q40dFH( zn-g#aUoOX?Tt5TBkh}JO5_?!^Sr7FnA~=Uj36bRUW6JXxRLolyS5q@P)=*V+*;mCN z$USuh(y7Wed%h@+@O}q~eih!yAE~v8Hm0laMjq0;$J>F7%1>c2$w{9lkLv1NC@W6w z=B}%K+p5bcrrKKQug@V8FoqV(T*REHI>(*Y&D zV8mWIykDe5``Z?oj7;Fyep*80J_k{4PxLfMxUyUW1^SX1*5ga5(8cyjn{Lb{lJgf9A&*n;(ES*&m+^!39Uqx2{RVR1f`9t1 zUWbzMm6fh5_T+%A`C>!^vzk}O7AeQZ78PONZfzB(T&1HULcsOKnnq#nX5Zl&5wBIB z+OHjs8DZ3hWxPjsn&c%+b;jA?gu7m)nmfR+my{cVcLHEk2rr2hY*i1rY@aM&OV_+Z zKt1Tcn*VP5Ptf-_U^1HcKT)#|NjA@5T<)vG2N`2xxkS{BY8-Z?9)laXuklCy!WizS zM%NUgU?Vf-`kgR)P8(YZDD@)lEdp%J9T}*=okZ9aXyvN%2ik{%t>`ue6bG@kWOi_& zr4USPTerQF*o0WgN8`<9*ovPjzD}ZlfnhR!g%YG7_J94KRpqEnKJ~E_&S@pnl|=c8 zYXO5!Y|0Q4ynFl}a(~=y-0_4h`5MLt-~2RM^RsX|Z+$(glgO>6(57q(d{Vqc(sH9i zslN1`CdEB#r`MwG^t$Cx0Y7zM7GB2lv+ZJA3zbh|ZQ=9%W1KnLh18}}&XY*DU{^L~ zvC*L)=C~S_T#B$Izn@VR;B;2VwaV^mx=qfX^Djl(e3hz7HcJ` zKMB#4j}8gkGVEb7O|-l(w+@NAllgrjiNV)qdLTRmU42Ruy~=P2G+QrW?3_*uABw~f zyZS)`oEZ`B`rk<9n%Fsk_xAm?S-}zt;5_V+*tcv<(9mL~4m8-o#oB97 zQtpN=Yf{_*NfuEy5grm5-fi>in_MJ6iB!D78$0HF^gSiIv8ces2O@3xuF1|lIt=lu z55;Y`q*6#1wZk=nZjIO@H=6_x4(qf`3XQ(l^&fvafxfYM&%2lrvwydA5PQ}f%m;C2 zaHYyn&|ALIi^L`~*2ofshC`ha5(mTVk@#6SopCBhtR3?gC7B33MTYA3+=5}j!R?D+ zPz)q1MH4`x5{O8#{~H4%;ih+{jc|hdpmQG_$!@c_IfV;mrSS#C%y!}ljbiCk63rQG z`?4y>*z;l-uyACMQ~_a#v1@d2NFw7AHGND~$B(yLng|5vTIM=iT*oF_ch6xpN2!VV zGK~^8hh3GeXHJW2e&m^}4>k#ym1a=1ss2D63Q`*zewB{UjYWh+kU{DJ7osoY^uD;0grc^o}@W0 zaya~CPtKtp@hiG5zo3}?tJMoGqcVCBMvG3=F48hluos{H$|^Ho zeZC~{?X&6koTG-!ag!!UQYgG(8JSpwdUF?Z=?z}uCX@8uGl-_kV^X)Sap<#!srE0g!cCUyZ3E}})5EUSKq^*w8-2qd zuEoBX=HHcL9dJme_RAO^a-Lc@{rRpH0%k7X2ze67ZPgJf#q%`|2mOOWVhoyGvfGhB zb+Z?%C9#+w(-B6_&x_mt-NG~j_#54J(g)8D<+~|rnVhC{tZ_M9kC~Nm+9{ccv95S_ zxD2lw`5a_F1-nzo$GJYK2LN>G?`5(g?7OnTB^617SvMuak-Q5g-NLL;GC?tn=epFU zwQgKO`0f`n|Mqbs^juE6RO-{w^t*4&)*PpEFkt}BF6ql}&@*z3rc^9GS@VR5(Rmi^ z2>e_7!MUIVGJrLKSn3w?W@35E_H_SOd}<_#_r{FMTw!?sEtK;H6n3(l+!#-RoV6=( zE&-IHWIw34tW|o=SuC-dYcrY>cdVjYX(D}sxa&h>hgrY z74$FT%1U@r<7q@u{H8TELQa>>;Gc%dWw5#BP8LVDZ^$4Fz%SY{itA!7x{lh(tcJtk z)~(z<88lGKv2I4K=E*a~;s+F$&IL6RoTy%PX%rxdl4562s>I(?&*!>pQ>g=<xZlNXDFzKV0ja--*lU9A)bJ!Bl?qoOk1P zH=wVU73b8eq~%>Rpg=rR$q#A{b8_b5KWu)kBNkI93OFp@i&m~f${IQpDRFmw6JxjU?O`fy6BgumG8fbrkL?GfI|F*1`%#6x>#KU1zP(Bc(EUV@^roc~ zX(Dn^dBTBk6*^#aBm zXM?$mjB(UkYwU!=+9f>b7{(;>hn&5ob`XLO#ZFS0Ph|>F26X)-0GM)+E71Spz z6Asua8WJYi`b(q7d>!~*l=9P`+SMUwvP$CIq3fYhacf zNtGb?QS}*2e=@2_r??jTmQ6|E>oJynrk-;1SWyJWO0v>cIY+?dwX1wHKs{tE!{NJjz77HWu*9&!5OfU_ctwmjD~n z@O26IVrxNe+=3)tRn`SLt=*C=HKh?ywmHM#+#2GIw;N zST08mz@(C`8soCDtol7SNp5*2*gSH%l}WzPeZkLW@U^ZLl`FbAGs%?VNLaRCl;z(4|9Hk#VSi;+Hct;TKimBgp!S zfx(5{bm>TzUu6Dlv_n>2e|VDHxir5rX%U)IQOg9LN$Buf5S|jVG4mf~HB+cIN5OX8 ztz#|@nIj|uU5$uK*u6dDbs2nFB~=eUjJ8WP7Z3lF8UFDPbAMMJ3Nd8a?d?VPa81=``%q(kmB+>&@NQH(^s_KPSy~RFP zX)cnmKsQhW_UAQB>gZd?8)hoBwa&kC6y2WJ4h4!YN z?OlYmnpX~4LcQ21&PTI)g$|1C%esX(=#}k zgW^eBAwoSuFeHqE$yv|3b`;w}zcqLKCemmL}7&yR|4TR_?>)#!0(!1?KQGR!d5 zSL*8mMD$4xSWwrnJAq>#b1%?c&iFw=Ilm#IdM`k|SIb2GS^(`J@$51q#j_;UYd=)t zN{!vnLaV2Q?OYt)W~bycdh?;KkMqp?H#jq;SSSa!#NSZ8)m3>9VT4Z|&drU_0Z&KE z=#{l98OYS@1WLWR)_KOsD8l(I0V!<=nq1gkAmt*<+q1I($DSl=R%udpuRgksmg<(c zgkFHG0h*!#))gR@75xSeMMXO=w0n_^jk)VbN28$LC!<+)2 zRc_j^<*_=d&}>JzcP?F1o;b$3e{4C871A)l)S5^gN6Xi?K%ckW96#Cp98D)Gek7}=;ejH`gr)Y}Yf&0RduS?Fdr&xQ;$SY^+sf<9U; zeY9g|uuAUA2HB6{He1%g`aQ;+!P2N6-{5XdL{G#Zv%R7iCZMpS`+!5A$6$XlI%76H zFW(~~Y)b8=SZtBZQxyU~=vH#awZ4?+>;?(n$b^^&5!8h#H-!m>k(8 zi%DU|i2Lv>Iz)Y(oA2txVErFE$q9ETk32ZJ zP<#aPS+9FdHV}F!a&!bhd?2x1ulA7qs*^leO5EynoJ%0ZI6az1B3Bd%=qc?^nGL*sQ-59fil$t)vHna-3`*xxoIHQLAYv@(=1P{0MTNY4B>VBMnF1uvEV zLR_S}|5Bz&jTUDt2pE+VI^I`;i6xv8Rl{R~Q#ik9*yGBGoh6-PR$R4lAH$Fq2ZWgL z(q8(SIpb6@5UPz}b1QRxvVGfO*R6*3fb}VFL-L5lG+cxVPYz_Ujgo1u^64-klaHX$vjKVPM28 zo>l;a%(TYjg565&YA;q-)|#~1j3J)()Qzd&o_U6iK(<Q}T;2nf3-i1O{u0jNh+z z7i{Z4gv9K+yxEdmQd}R%7@Jta<9_YfCGQY4RzNdw$P8ReWVo>Sr3;I5D=)rXMoY<% zEs23IpO3X_g!F{&wd2O*fQ$?bpjpZTwE{mx%Ky&}BPWSTv)fUHY&dwytcaI%Gbs4J4<5HXWy< z78@TbTO_`&4K-h$;*njIs#0AvlllvN;g>xQYGld!KYJe!F05JY;c2d(f1Dj&xjK7w z=RMWsVu^(2qj+w4e2pRl?V7dZf&-|{ zD2r+&@KFlHI7-p=^{1}W&@JSrkBd&lq575Q-ih)0Y{BCcjbrcM5I`>_Y`bhZT)hQr z5MjU*6jjt>#_}KkwJZw3TX;BU1K;9VPG4@qzRd89+LxI zG`3YF@Af2{xn+N`d7X^C`c6-k)87mT(P%2E30Ew{^N|&m3?WjN!6;w~A8X{V%7|nH zdpObkjfMxNts5}~h)~JdD8wPO(+Kh_A2y&$Z3U>dw2x`*jzyRPHUFu*sEYe9eo=W0cHQ}9o?6E{+bI)};5EO;HV7cO*quWF<;>fBLYdX{#}-U}_r*aO>~Yr0Qk-%2RNfv?rH!W&*CpY9$l z9HP}QU-Y|JLgm#{x#+P%rVxcEU!q(QL%a8 zL%QOAC#4~0X;MSBRIH6&`&IXDbkKZ}6^@NkFRB%tF%-mWecT>Jc(j4?u9i{8ytw9F`HU*^LBV)YuXsap!@BQg;bZLRtf{nLYh8PeiBt|eU6c&uD&Chk0^B> z{$N+a2>_2b)b0oV4DYP35wS!M+9NakC!T2^`Y!P=(8NMeD>+U8@Z=UKGv8_pEinRJ zaS8w_!#2*eWcUyN7rLps%|6~Z7_+~4AFQ$-94eeW0 zet=s$tEATgUs@oTdz^SK_OygU4w!=Y-DmB*ZY2b;;n7NJIkYjk?FdXk*JU*bR1Us2NmT9afCx)ALXR@Rq_(33UNJ5V~^M&PIiGwETGIPd+oo=%6#GqdyGk8pgnL^mc{86#7?i5%a?|xfhauKa*!qIhkON^fs&d zfR@<6aU%r$plDK)_kG-i)Dgb1+6p9tpso9I)#P_FlHH3tk<8^Z$)^^y5hLs6;B6@$<5F0?!M;0^^x;q_5Or{{)z_DDLyF!Xdinv%%|hc z_r6t7mZz&z-03cD#<7d|SDZj6VdC%u-j?Oc^!7(@Sh^>c`lL)OE5vP_*>&ve3=@oW z!gn@8F=3*kQ|O?Cx$Y@2x4wCxOzoJgQ@W6JIUj3uZpujsifzFB@s##QrhBRTZ_CdPek9!dmzGG_L7?;2CH%KOpMAVC zkc^NM(l^@rWV}XbTWFE%+;gQ1y}%q5GLI~6#A(66bjFvitHXYOb3m`kinq6jDBbl; z<|QlQ$XLHs$iC^Fd>ZF+x*q~)`L_HSN+J`tfAnCp+B@y4j2I;QOIo3ukd_-M&w*!d zgHhD*jj^@Z-Pp$H`mZhL^uhpUGsH=W)21qKw<1^~ zNJBlDZJ*o=$~J}W9SjP>g3a zt{O_RB6<7T@2OF53cOMu5B8u-+n1d#Ctrz#9UwyZZkrlIHos{G+e5R1!c1b8Y^ujj zUhhDjTyKipMSAS}(O$FQ)WH=%U@K~#Ws`C53J|rnHwl!hc`!a*CPaZl2s)N)1FY6)ZRAYiLOSfLXF&Yj=lTY|?fARf6-IM`$@ZyEwwQ@dN3-W__mDPJadwq5pt+c}i}?#<4@a#rw#fn2W((#h@AEl(H+@!8@2@`S{R!QoWZAL#D26Z&W! z7%}2bzvk|uWS(gO0AT?I`ed$8pajj?H|0JM$pd|;(Xb#rH-mh4q$r9 zF=A_Dn;=nawI!3drM-1$5t>r7btf7 z0k4*uvw$0cl?0_E*Her4JZ5TE^uF0a9n!m0wqlA6zm0EI73j)_ydLut901s6EhMvm z?RSU>(&yz4L`gQfZrm|hWc6)%Eat}D*JOV(z-8~5AD)y}$A;oJzI{qh&-$v)14%2-s}`!O>{Gzmqs)X2ETK zQPStDJaOXKe*8%_K6H=Wp~Y==Z2C&)IfX=QuQmk4j1mY)Xjf_P#txBbRAuVjH7myB zSSY+my1`D9`XdeZ1GLm?gy~Ri2BXUi^_}kotCv34w9{9=*zlBr+*L6u# z+FejKnf7B-(p>3v9JDkhYX_K1ET+Y?hBBpq__adijT}BctA5Zj!`oKJyhmO<#xT+z z`PyW|(6x+*+cLDM9&O5S2)QAjGdymHH$*Kk6Hy3|lXCxW9~B0is8c8Wyg^Iu7p*QI zoSL-Y7u{M%m%WwyXbtgLM0>+XE>~77gcpKnl%>i3mkqT6_9_6jQuN@N9kr2{iatD!S zV*LSGm0pYhzk4>#RMKP3n8#$=G1wO(F!^IN=$CoXlojloL6?0GO)ok>=g&GQPct>! zqHbC!h_k<9aR1%Mi!UhvsI=u4z00000000000002P zB*MB8*s!ZDwJCOj4qw9JE?~0=b@k93_3u6FpfJ2J05i)PNErft=D&<=wuMh08{YRE zkqXWBj+)r|oX_{Ft)>e08!fQS&r=*50Fvk;czu)Ya+NHN(Jg`e^u|^}>&FoxO4+gBD!qAHcZbQ81@BL zJWn*iA4N+GM}+sq?k|S>vW33IIx)wsphXOy^Dlui+(Czu>WQDC*k&EQU_0o#B2+fF zIPyE$t$0c<(FcmCej69R#w|%>O(HdEz`xDf65kyeExLAJP7Y9%oRZK>wJ1Ba*lTSz4Fh4WtSyv-rLJR-W>?3HR;LKyM<2cUaG3Q7(UNXj+Mz{E z0gPVXLDBR%Be*=nGxr;{VoQrKNhYutL*06Ak}R;%=sngwaW!OQT9~%UJ5gjSQ*}9 z&*a5K_M?Ey0vjTwhY+C28x<8kZH@LhfDk;8)CkY35|=I`wSVjLun8QGTzqv^D3#qL zAatgoIt(!!aoH+Ngi53mu6H^NR$n-SRd$s-`mM$G-sxdE8!ts!S!2(&Y`NZa1?I!Q zc)Q$O_%B7|$=5o$WkpRGhlXiM$;j`?`Yq|1lI;w2up}o#&)DtBGHFsryr$yND;jJL zEI942dF@XWu2QY=qw&nTM06?YO#?J0Bjm)R${JQXr^Odo1Bm8m3(40Tt!W6!@6eP~ zI`=-w7AZ+TSnt6MqV{b3fZwrWi`Bco{ZIIuxoq#n!bxyIEcQX^JBU}Hn^BSjrw?|< z@l!7P6C*x*CA&xhoGlnK3UVyG4EKB;6KoO@gl;AT?iB>QrbP)dTM>tMjkdx<=;**4 zWDFTmb0}Z+e=OKzqyTKmeu~_=3cwV*Zx2&LEy0Iz4TXeT+UMkw|JtA5$U$cwVCP4o z_1r1ea95qW8~_(&eoBa6U;7UT^@8oUKO}~G=e9&6W<^eb@Ry{nx=5^qzi#7jw-3IK zM>;(~Zty~}>m~V4dAKW>Ak_LhHtnO4Xly9lyXWKlZ&FnzNqUdxyK z#}%kv;VV0qr%-{y)3-SPAE2U!1a;>0r3U*UTO(b+619%ko6vT$FP3SZcmQBXE$#gV zl89;udTHo@VkHl{Sd;qSu+{lnw=_rpN=wMLw)Wj^FlIH}e*!G53u-4g0ADxpdm!o#4>UL!&O+%}w)s{Y} zJevF<1a9E0i7wrG{v6-82&$u=xiz63<^sSX6^R5r>@qsIbJt{~OGY7j-G=b2y>|U1e6O0G}t+C;3Yft!EItg2EUSAo`;DRmLRC^Poc9B8NgyEP1qbZ5f zh|PBqd9g6gl2ET|cHxkW=*NJIbQ;JS=W&K!U5~JSqmOxo7YKwJli{qjV#n(gGAO1e z*U67N6kY0bpd(Xc6lmL~w~>_L5pfApW{?c4Ne+gvtB1;-#DH{>Ev$B1>&sHzSrkz# z@&kKx8v7qj0yh1L&1ta5Uy)LCU8w zEJzCxW6qGgLVDp~MFKK&o^+mPBtRwA7FFH!@u0w{f<4r3-xq6>m-qPSZj!7+)fU+@ zV9Xt|C6FPdn%yzcx$CY;3zZ{FPLonL6O2=YwzhvrJOMj>%gXSL%x_pSKl+tJqJ7ux zdd{ISjpZG2l^=)}E?kojNZG0_W~xHp!qDB7YrT4{tu)K|eEOy=wOeewL-^?T`JL_w zfTO&8+9wM5Fzbfly4=!fn>{591r`)Wd-!4+XSMthA`^@jgvFx}xU<`xAW(XDA!>7TYW!Vw7kIZfAJXCO2?7ejRj8hX2zr&f&mfr2vHso|IwJ{Vl;ro52Z8=A5C z<481k*zpXsjBSTZci=syuCWG}Lbzf4S{PW~r1?`zNFJH*pi4zqG+pDEgV@u3I zpnX8xLwD{BDC}0uY5Ry|plX8i`PcDhc|n(RC0C~}_=HXMl?{43AO;cibI5|zTkOg1 z9Uwt46~UCsi^O@(>vZbiGc+KEY#}$^u?cxyDw+0emeb~e zKuTAtx{cU?t?-3|oOZdj8urpOjFvF^xL;=DHSb!T7`;}VV~tDX=tI-F)&YORD-|Xa zID4J-tDZ@zRkf5+$(>7O=-|Fzp(_quyr2% zO=SYCvR0FN*_FY52%M2NaRq_C;L+bzstW)|G`p%17}jck(bUn6&@Gli9V0w#rvwoy z%g?38hje6<%C*0iS97{ zqSh@Uhc3+5l#;%Bcq}9?J*BPea@-+&a?fV@ULe0 zW6N7y(f+<71Tcr9*b@onRoqFm@ z%1J!3NiZRA_tZjm!8%siCOPz-_2ZezArxVtorc)dF}Q*ZFTyk@z|uUlgrOm3SCah} zdFG{$*XG}ID?Wa2iFv;xNxUSTX6bTkp=SZ4(*s??2f0kt^*neb&S*?>y+Iy+ogikI%UJ z_OS}PE{G`$EAt1;k^tIfKFvURD8=4S(qLQ9ru_Ng8A2r}`JvQNR?cFfc()}6bC#Qx z;kTR!peLOrp)rKmrro@ujaJUo=)(UF&e16N4QbKE@8T5~|DV(8zZQ(C=W+}J*4~I; zJSyz2{AnHvx|3=YRUu$1yLEIr6^427yTl33!}3~~!xlv=+M|lB);FC*0P`QG#=BO7 z5ouDl3;L;xrB2&u9}PAN8uA+pH=nwB%*+eeKIMGmlDS&`Aan``c_Vg#@yxouM?BSIg)(y`}o|2nYln6P^jOtNK0#2ofGL)M2_PPFf! z%yhqOcpF^@>d`&^777)*A5X*qgK!z+FIwZTgRb|f1yBWEx zn*ADQ0?lWF4RejZileWjw4+74_cOtVTrYnAR&W$*Nykqq?sY-7dSim!Q-JXfTO0aP zap!BOM9oSiDT|xaqm{8yJwu@h`4y;G(R_Ptrl$(@uZ4>=&)X;F*&lJ326U~E$J9``v*6>C6@8fd`C;x&|Mk)uU8KD zyxm1Wn3`%~dqQR4#~h#Op2A0osjpiW3(L{EToXYNM9FaO-|YDhjjtF5c$1( zDG}0vv6wq{2Z{bEr^9h5^YA8s&r7AG90umed;w48h0n?%jK8|*H`-)hYL1VR!(9s8 zz?o>3vy;&DGtb(QB=XD5J}pV}_o#;19ln;ww;lH&j!E>e0R7^v^)~uK1}4@1^Q1ZW z30S?bT++PlyrX*j4PRm)&v;#1>LjmwCuvumt%OE2UAwa3)w)t9ilRA0p_C$C z2Y_2LD=v|fEV1y?1(4;Dj0Jk!6QSVvwE*n|POevw?zQbIaGuFLdE%#XWxK+30enGz zQ<@GPKn>obANC8oTJ&nR+BYo4mP$`X{P$+ru?SS(B;FbCv+D(Yhr_F z@07AFn;fg1rQ?x>(T;3LnpLqnCoOM!_q1)mx78bILiPSj1wO z2RWMq2daIYQj4EUiqwcpvAgcEtrVqljW;Z;fk1VEPd&N!iuT4%ePk)bJ0J0#Y`NrX z*JH63gI3#jzt%KO-GD!ydR2!0oo*MiBk(NvC3mADg zozl>nnb&Fk+SX%5wz~}bjHWrSU*-fE3S)bfMzv3gB;XmgaNJ?-JdNQT;;tmt^7P*} z;NwP98oHE;ghhdf^;MynEl96V!?4z7I5$tS5}LESlP0~yB`)IQ=Eh_-0E>ks**a4>i`C0{_ zgR7}M4rY8V3F&{C5S%$~5-ZChOz37*?T)bZscsoZ2Opppc>ggbev0R1Esba<+5K4y z1Y33jCt?2jJK*+TzAn21-U~vfe;pQkiZxywSPcDSn!Wn=&*Wak1>>mh7UEyTs^B$S zQl~|O+t35NyoX?$g}yR*ez+x{mB_VTwMwPo(bt>pKh%T?xP_d&s*mgQU#{SPQiX=1 zCkXU~vZeo25leQ-f3NihP$XX*!#HChxw%-{4)R(K5j7_l48AKi%KrP)3jSDvnL=p8 zb!Wpn6Wg`T%N4~kIRga-Qslud`wdVJN65fW57fRgDU{sFVhhcQ{A`cl(YAq38j)_q zINYQcZBZ1P<;KLSDMay4s_XD;FXN~@t$Bq!Wqgz47-K^_KhYf%f^cM^jwL_+=57oN zl#=@J(U@Bx_V$GS+`ye0^)4*UP?;|XbyqV>3s44$_7)9HaAOgKbyN{ZMt0s~?ta)m z{Dfu2!BZ7J?wf_x`n=V0Gj|uAl*?K|W_40@>>)HcrY$(-CinC&9PFw0Rk*{P96YQg zpC6SFOBthd=YW;G$Lf-g?9>SFPjN)*xXF*pO)rZd(hEJk{J^TuiRcgnT@et`)Dd@V_s~<$T&}NL zfXvYE0)fs7xbhZ`{VEj!s<9Q{*E{yv7=~&@EwnGtNbv^;Iu{0ymca<>3v|!7{^WY9 z??K9?e*k!DfwJtdI05D$$S!F`7StExKB7j8@ZGj#>pfefAQ7vd1Xltqhjnsx#{Y0r6bvI z3CLk7DC;A4Lor2!_t{$Sz-4`@FD-a&ER;N3lZrw{O;1QlNXVWGBFEej2@IK84LlLc zl-@K~_^%y7SpBC;-*eoNXBGahO4gdZ0=!qTR|zl`YM9#p&2MYKUOAzW@FE*QAZk=B zO6uHY&_fA>!;Nu8Li6}HpL%Bg4@7_BE0@%MXw!l{wWTYe-G8F!x9^wHjMBA=i^n9i>cg-k8v|xP z5(jV7^tiFAbC%DTc{>MicZr{*AasU=8PAD)C2e&Prf&JY4y| z(i40hb-`_haLCL65`+C}skES%Ejt4JSL7XRe{uf74({BRZSb8I0 zw1}7#dBpOAdLp=#&GEY22qQeur%XVi5^`I7%gDDjVQPRIF_xZPlW`Tdy_DBEZ+oh2 zcvkWgVFxQvX<$ql27)2yZ`!`|Dy0&XRn{H_;ZVz^>Y=FVcGgQO;q|*@%Ra(dA`dN> zDITN1GC)^TBl@mRs z1)|{;99R=q`DdwX;4NHQXU`5^Vc+OV3Q9UA{b&szYxenh1oqa!Ih$!!v>KAdZYTBCu<=>OP==A8<|ND=K?AhxwpBSWb9CljZS2~NG^il1AtbyhJdsgVMIonSm9VqC zaahlVqB;SMsfxjy^u6ap=Ovy)w2t-)%DlwVHZacB4ZIs>v9>ETuUuJJ6OH?589Lx+ z15aIF>u$va7~bpA{q?ARSN-p^JI!0`fZCqK@h3&RJf&V2PxDu3(Z#m&HJ7Qq*bjU*~nsP zz?7WtRYYq`_k9E>1kRus9&jsSHI&$vs|_by?rQGaHA!~#(!)SZvPmxGu1U7Ur7bu{ z-z6rn1@Tq9NxgY*J(|011$cJF&LUec#*u7w^lSz=G*Xt!ka_Yf0 zuc)F2XLC^0lUu-R+;#_53*!* zwLJ%*rA)TS$+R&7$X7msmC*9)Q4{;M)A)ru`i3F*Z2+5#^{{TItMq;y_GIW`9sdiU z1T;GU@Ez!Ccpb4|9V$H+7uxK<=ucK4^tQ|%oBYoMNP5A)2EtKp3{m%8ncywq)=)?y zdDu{fZ&=k=o)~E%W*$Il{~~?Nc~}44?25k8XBo{dPL`Idc_S}!Zpc$p{$(%@vF;P? z$hfd;=ThIeWoh$_q=hk#eIMYLJ%>mFI>Eg7BIwi8#v$5^V$=V#KSFQW4UBCs!;j~fe z!mS#ttE~JIXfl@2TY&57z>=@SFNB9nVx8VL2X{ulx|)kVNq3Ut+z~TP^)-C{LjTBE z9i%hC8T}y^eEpIpa1&5E`?hcWi$>V`BrK_KQTDO< z?SC2N*68zGZNq;gy>KMQd)UJMX8m0=QEJ!<6Y-ZEc2l#M}k?b`(J`YFvY(v8gyF#u~!uh>>^2{Mp7ex zDlKy%rgW!VXxpc(Z#<+2L)s&pW^0Q_bh+Y;D3~5>(G?&f2tO8BQ7eYE`^!n!#s(t# zX!C!-5t7YRR@qJ=enlH`$BrtAzPPI#ZNbNF?EX;xNdWks1seVh&p|UEr&C6 z73qn(G-L7eC=}YE3M^x?{iXGxAx_Gt=h1MW)zd1c?sGzxC6>J*7i}04!$`#Wadp!F zupge*)N-P|DHuK>YQ6YPQW*%A2ZLN}C|pdpY0_-7@;E$Asn*r91VB0lyrUzlz0rc7 z+q8mw&2wFbQO{NC(J0c2dFt0Lv_*>ZZL2(K6ydXG%Bv)=4{likZ~RHftdT7OfbBo9iQf1xvbEoXIpO)t_AC#jVqFAr8n@AMQSl5l2kfvpw7djlx z_#k!>jsm%l1e(k7eF4*_&&py=5=H@##|HFj@b$8NfkG?LnM4GK9u4HUnK7UC_5l#_ zzknB1%wRof_&Gq0il+0Zqw?MzxpWJ%TIuTn3DT=U5`v-z1e=FFx^Jtn7q(~Uo~%Sa z9KfnHIWVXH*epJa!jiQ(ZZN(R^1h95y?U#XJKnsUb#A~y1AH+5D>dxN7dst+F&ZEL zNZxGhlFF`5rkE}5P1)8HrR7QzO>Y5wj~jDGVX0J2I;aIG|09+_S1mM~w$-$d zj@e9aUhh51mk0XCZ9a^PPVoEh=ix_2G*>VzY8`Pf*Jf3QfTh?aMR5}Bi@r5FF+gCI zgTRoIe28m8S(uut-ap*_Tceywt+InUhs>XrhFw4M10jz~dJD+(UXC4tW=$Uy$Jzfj zoFA+bYSk&mUR&7KFR!Q^?@~p=X>-8_cPc1W!_*dBJgyC9FYL3i%$U-z&5b}*)gdGt zpu%`?b*_zItWU@>i0?Bp2*tRi;V;Jmho^t0anyhbU`N;+VhD^Z<`3k zeO^-{?Vzch)ybjLc@7^qn3y+5b=lm%etB&}e} zKO%>%f|I>lS7s!4jFIGICr)m$)12-7Hsdb38oR||IY+Pc>I+ILjE<2(X#F-5xGV8q z)WyKNd=8?MymRUUmgC5mtFKL|FW zORbr-kRfV~Z@b=dUA9gP39%gts~TjC4#SOhpQjt175sWm+(lTL^N6?rp-A$rQ{XQ6 zA(|JS4&r_GN#Hz!MR&2@y4aMoseJpJN^GJBfMu@I(NM$j{~c1YSCgCt+Lm2ydt{B)=a5kagLgzCd9uho29oA zx4%xw+?i%pirFsJNlMXvRazjSg!k9US?gcjQF;Sn>7V^J-AE@nTBZ;FSPa8nc}Nkw zfjawIL7|d#5l_e$HJ#VPo2FKASuym#ULghi1_X`pPDgux1tAFgGN033 ztsC+JBeoH6$Y(0G!z02PB$6CcFr3haAR@@^CUa6r91keCA9Cx$thS0}TAjU$j&;Ov ztbI+Yh*#2q((h~W_|4h8-LDE|r_PUs5$$WW zl~{lQk!!j4qfeYxY={5x(OsIt3wl3qpq6L0Is5F&X2@aS4!1y}ZG2G-h$DYA_8@qf z&^>jfG4Xu#qgD1GTA`Dc-dbW*3_l!RAdJBqwCe7FLsYNoh3u#@lT^`CMvG-js8X+& zTj#Hj=Z$tY8w=k|PY|X{^zi0Xd;n*LgDgIY?{h`n#)zH_p#*tR9jn9- zKoi&vGnsxOb+=&M^oin0=J&O!?sCKAxrDUw?ZLx6hpEsKtOladPzih7jJi@-ZA%mu z1wgs0AuZ-L*mPb+tlO5NC@+9*CklM@6q+Qn!t|3VOwqJ{RKtxZvNOh}tJTSMGh2 zy_NCF$%IpW78YU9KCk;xVHliF^B;{{hF|OPYxugFSA7YRB)BuxgjyD(H(aD_>mCcsP+J}fNugjJx=Bq@FT-q2G#hin5KK9cBD z^4g-pZS0wo%^+fSmc>MVhV|ELygCGw3i5%Lg?SG$PO;QF1FcE4o}e+YDH8cI?dc}1 zUai%bj%sDbpYWx6

}Rba7Q5#whsm0WzO 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⪅9+Js6*pvz#XWt-0Tte}Q_XVW4 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

>nt`MZ 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�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

8z?&37cjhfKy58bmQ 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�Gq%z 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 -c`hpmOGqf+eizZd?h6nKxySt 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 z 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

g&{@Ni<*Y{b8 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 literal 0 HcmV?d00001 diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index ce4d4d2c5..2061498c3 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -154,12 +154,16 @@ git clone https://$github/sbwml/package_firmware_linux-firmware package/firmware # mt76 rm -rf package/kernel/mt76 -mkdir -p package/kernel/mt76/patches +mkdir -p package/kernel/mt76/patches package/kernel/mt76/src/firmware/mt7927 curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile pushd package/kernel/mt76/patches curl -Os $mirror/openwrt/patch/mt76/patches/100-fix-build-with-linux-6.12rc2.patch curl -Os $mirror/openwrt/patch/mt76/patches/102-use-hrtimer_setup-in-mt76x02u-beacon-init.patch popd +pushd package/kernel/mt76/src/firmware/mt7927 + curl -Os $mirror/openwrt/patch/mt76/src/firmware/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin + curl -Os $mirror/openwrt/patch/mt76/src/firmware/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin +popd # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch From 9fa94ebbc5f1dd8571708c4dd78ef86e6fa6a72e Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 30 Apr 2026 21:33:35 +0800 Subject: [PATCH 395/425] config: x86: add mt7925e & mt7927e Signed-off-by: sbwml --- openwrt/25-config-musl-x86 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openwrt/25-config-musl-x86 b/openwrt/25-config-musl-x86 index 09eee43fb..387e8c6f5 100644 --- a/openwrt/25-config-musl-x86 +++ b/openwrt/25-config-musl-x86 @@ -33,6 +33,8 @@ CONFIG_PACKAGE_kmod-mt76x2=y CONFIG_PACKAGE_kmod-mt7921e=y CONFIG_PACKAGE_kmod-mt7921u=y CONFIG_PACKAGE_kmod-mt7922-firmware=y +CONFIG_PACKAGE_kmod-mt7925-firmware=y +CONFIG_PACKAGE_kmod-mt7927-firmware=y CONFIG_PACKAGE_kmod-ngbe=y CONFIG_PACKAGE_kmod-nvme=y CONFIG_PACKAGE_kmod-r8101=y From b05dafd0103794ec9b3e5a06db1959dbc7bfd218 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 30 Apr 2026 21:36:23 +0800 Subject: [PATCH 396/425] script: mt76: add mt7927 patches Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 2061498c3..5ef7f7c4b 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -157,8 +157,18 @@ rm -rf package/kernel/mt76 mkdir -p package/kernel/mt76/patches package/kernel/mt76/src/firmware/mt7927 curl -s $mirror/openwrt/patch/mt76/Makefile > package/kernel/mt76/Makefile pushd package/kernel/mt76/patches + curl -Os $mirror/openwrt/patch/mt76/patches/003-pass-LED-define-via-ccflags-y.patch curl -Os $mirror/openwrt/patch/mt76/patches/100-fix-build-with-linux-6.12rc2.patch curl -Os $mirror/openwrt/patch/mt76/patches/102-use-hrtimer_setup-in-mt76x02u-beacon-init.patch + curl -Os $mirror/openwrt/patch/mt76/patches/201-mt76-mt7925-fix-stale-pointer-comparisons-in-change_.patch + curl -Os $mirror/openwrt/patch/mt76/patches/202-mt76-mt7925-add-320MHz-bandwidth-to-bss_rlm_tlv.patch + curl -Os $mirror/openwrt/patch/mt76/patches/203-mt76-mt7925-handle-320MHz-bandwidth-in-RXV-and-TXS.patch + curl -Os $mirror/openwrt/patch/mt76/patches/204-mt76-mt7925-populate-EHT-320MHz-MCS-map-in-sta_rec.patch + curl -Os $mirror/openwrt/patch/mt76/patches/205-mt76-mt7925-advertise-EHT-320MHz-capabilities-for-6G.patch + curl -Os $mirror/openwrt/patch/mt76/patches/206-mt76-mt7925-add-MT7927-chip-ID-helpers.patch + curl -Os $mirror/openwrt/patch/mt76/patches/207-mt76-mt7925-add-MT7927-firmware-paths.patch + curl -Os $mirror/openwrt/patch/mt76/patches/208-mt76-mt7925-use-irq_map-for-chip-specific-interrupt-.patch + curl -Os $mirror/openwrt/patch/mt76/patches/209-mt76-mt7925-disable-ASPM-and-runtime-PM-for-MT7927.patch popd pushd package/kernel/mt76/src/firmware/mt7927 curl -Os $mirror/openwrt/patch/mt76/src/firmware/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin From 95251d3bb43504d81f6285874b01568488df0d23 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 30 Apr 2026 21:54:12 +0800 Subject: [PATCH 397/425] build.sh: fix typo Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 7c480584f..aeeb116aa 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -403,7 +403,7 @@ echo -e "CONFIG_GCC_USE_VERSION_${gcc_version}=y\n" >> .config [ "$OPENWRT_CORE" = "y" ] && curl -s $mirror/openwrt/generic/config-wwan >> .config # build mt7927-firmware pkgs for openwrt_core -[ "$OPENWRT_CORE" = "y" ] && echo 'CONFIG_PACKAGE_kmod-mt7927-firmware=m' >> +[ "$OPENWRT_CORE" = "y" ] && echo 'CONFIG_PACKAGE_kmod-mt7927-firmware=m' >> .config # ccache if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then From a6c0ae21f52bb741ba8438c1b6d2ee8a072e35d4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 May 2026 18:47:09 +0800 Subject: [PATCH 398/425] config: remove all lua-based applications Signed-off-by: sbwml --- openwrt/25-config-common | 32 ++++---------------------------- openwrt/25-config-minimal-common | 5 ----- openwrt/25-config-std-common | 10 ++-------- 3 files changed, 6 insertions(+), 41 deletions(-) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index 68b675fec..2343b0a9f 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -47,11 +47,6 @@ CONFIG_PACKAGE_luci-app-dockerman=y ### Luci CONFIG_PACKAGE_luci=y -CONFIG_PACKAGE_luci-lib-base=y -CONFIG_PACKAGE_luci-lib-ip=y -CONFIG_PACKAGE_luci-lib-ipkg=y -CONFIG_PACKAGE_luci-lib-jsonc=y -CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_luci-proto-wireguard=y CONFIG_PACKAGE_luci-theme-argon=y @@ -90,12 +85,13 @@ CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-frpc=y +CONFIG_PACKAGE_luci-app-homeproxy=y CONFIG_PACKAGE_luci-app-mentohust=y CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y -CONFIG_PACKAGE_luci-app-oaf=y +# CONFIG_PACKAGE_luci-app-oaf is not set CONFIG_PACKAGE_luci-app-openlist2=y CONFIG_PACKAGE_luci-app-qbittorrent=y CONFIG_PACKAGE_luci-app-ramfree=y @@ -106,32 +102,12 @@ CONFIG_PACKAGE_luci-app-sqm=y CONFIG_PACKAGE_luci-app-ttyd=y # CONFIG_PACKAGE_luci-app-unblockneteasemusic is not set CONFIG_PACKAGE_luci-app-upnp=y -CONFIG_PACKAGE_luci-app-usb-printer=y CONFIG_PACKAGE_luci-app-vlmcsd=y CONFIG_PACKAGE_luci-app-watchcat=y CONFIG_PACKAGE_luci-app-webdav=y -CONFIG_PACKAGE_luci-app-wolplus=y +CONFIG_PACKAGE_luci-app-wol=y CONFIG_PACKAGE_luci-app-zerotier=y - -### ImmortalWrt Proxy - nft -CONFIG_PACKAGE_luci-app-homeproxy=y - -### Passwall -CONFIG_PACKAGE_luci-app-passwall=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_NaiveProxy=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Libev_Client=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Rust_Client=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Rust_Server=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_ShadowsocksR_Libev_Client=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_SingBox=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_V2ray_Geodata=y -CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Xray_Plugin=y -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Hysteria is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Shadowsocks_Libev_Server is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_tuic_client is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Trojan_GO is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Trojan_Plus is not set -# CONFIG_PACKAGE_luci-app-passwall_INCLUDE_V2ray_Plugin is not set +CONFIG_PACKAGE_mihomo-meta=y ### DDNS Scripts CONFIG_PACKAGE_ddns-scripts=y diff --git a/openwrt/25-config-minimal-common b/openwrt/25-config-minimal-common index 7e5378248..ce81c8c6f 100644 --- a/openwrt/25-config-minimal-common +++ b/openwrt/25-config-minimal-common @@ -36,11 +36,6 @@ CONFIG_PACKAGE_dnsmasq-full=y ### Luci CONFIG_PACKAGE_luci=y -CONFIG_PACKAGE_luci-lib-base=y -CONFIG_PACKAGE_luci-lib-ip=y -CONFIG_PACKAGE_luci-lib-ipkg=y -CONFIG_PACKAGE_luci-lib-jsonc=y -CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index b18d07a46..b5f0bc705 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -36,11 +36,6 @@ CONFIG_PACKAGE_dnsmasq-full=y ### Luci CONFIG_PACKAGE_luci=y -CONFIG_PACKAGE_luci-lib-base=y -CONFIG_PACKAGE_luci-lib-ip=y -CONFIG_PACKAGE_luci-lib-ipkg=y -CONFIG_PACKAGE_luci-lib-jsonc=y -CONFIG_PACKAGE_luci-lib-nixio=y CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_luci-proto-wireguard=y CONFIG_PACKAGE_luci-theme-argon=y @@ -82,16 +77,15 @@ CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y -CONFIG_PACKAGE_luci-app-oaf=y +# CONFIG_PACKAGE_luci-app-oaf is not set CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-socat=y CONFIG_PACKAGE_luci-app-sqm=y CONFIG_PACKAGE_luci-app-ttyd=y CONFIG_PACKAGE_luci-app-upnp=y -CONFIG_PACKAGE_luci-app-usb-printer=y CONFIG_PACKAGE_luci-app-vlmcsd=y CONFIG_PACKAGE_luci-app-webdav=y -CONFIG_PACKAGE_luci-app-wolplus=y +CONFIG_PACKAGE_luci-app-wol=y CONFIG_PACKAGE_luci-app-zerotier=y ### ImmortalWrt Proxy - nft From e6f69c39569e838f002586d1de9c63367a216c29 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 May 2026 19:47:49 +0800 Subject: [PATCH 399/425] shortcut-fe: fixed build for linux 6.18 now Signed-off-by: sbwml --- openwrt/6.18-disable-config | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openwrt/6.18-disable-config b/openwrt/6.18-disable-config index a6b200469..3767b380c 100644 --- a/openwrt/6.18-disable-config +++ b/openwrt/6.18-disable-config @@ -1,10 +1,3 @@ -# package/new/shortcut-fe/shortcut-fe -# CONFIG_PACKAGE_kmod-shortcut-fe is not set -# CONFIG_PACKAGE_kmod-shortcut-fe-cm is not set - -# package/new/shortcut-fe/fast-classifier -# CONFIG_PACKAGE_kmod-fast-classifier is not set - # package/feeds/routing/batman-adv # CONFIG_PACKAGE_kmod-batman-adv is not set From df51b51b9d6ce4b067640153f126c49a891b77d2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 May 2026 19:57:41 +0800 Subject: [PATCH 400/425] batman-adv: fix build for linux 6.18 Signed-off-by: sbwml --- openwrt/6.18-disable-config | 3 --- openwrt/build.sh | 3 --- openwrt/scripts/04-fix_kmod.sh | 7 +++++++ 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 openwrt/6.18-disable-config diff --git a/openwrt/6.18-disable-config b/openwrt/6.18-disable-config deleted file mode 100644 index 3767b380c..000000000 --- a/openwrt/6.18-disable-config +++ /dev/null @@ -1,3 +0,0 @@ - -# package/feeds/routing/batman-adv -# CONFIG_PACKAGE_kmod-batman-adv is not set diff --git a/openwrt/build.sh b/openwrt/build.sh index aeeb116aa..764afd5aa 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -327,9 +327,6 @@ else [ "$platform" = "armv8" ] && sed -i '/DOCKER/Id' .config fi -# waiting fix -curl -s $mirror/openwrt/6.18-disable-config >> .config - # ota [ "$ENABLE_OTA" = "y" ] && [ "$version" = "rc2" ] && echo 'CONFIG_PACKAGE_luci-app-ota=y' >> .config diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index f74846ae9..f9399906f 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -67,6 +67,13 @@ pushd feeds/telephony git clone https://$github/sbwml/feeds_telephony_libs_dahdi-linux libs/dahdi-linux -b v6.18 popd +# routing +pushd feeds/routing + # batman-adv + rm -rf batman-adv + git clone https://$github/sbwml/feeds_routing_batman-adv batman-adv +popd + # clang if [ "$KERNEL_CLANG_LTO" = "y" ]; then # xtables-addons module From 58d04c2611996b3601465298f870bb975c90b34b Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 2 May 2026 20:02:22 +0800 Subject: [PATCH 401/425] config: add `luci-app-nikki` Signed-off-by: sbwml --- openwrt/25-config-common | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index 2343b0a9f..ba2c45539 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -85,7 +85,6 @@ CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-frpc=y -CONFIG_PACKAGE_luci-app-homeproxy=y CONFIG_PACKAGE_luci-app-mentohust=y CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y @@ -107,6 +106,10 @@ CONFIG_PACKAGE_luci-app-watchcat=y CONFIG_PACKAGE_luci-app-webdav=y CONFIG_PACKAGE_luci-app-wol=y CONFIG_PACKAGE_luci-app-zerotier=y + +### Proxy +CONFIG_PACKAGE_luci-app-homeproxy=y +CONFIG_PACKAGE_luci-app-nikki=y CONFIG_PACKAGE_mihomo-meta=y ### DDNS Scripts From 0e06d5de8c28cc4d394f110608b2b6b6b33b1936 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 3 May 2026 23:11:05 +0800 Subject: [PATCH 402/425] firewall4: refactor fullcone6 logic to sync with NAT4 and restrict to zone[1] Signed-off-by: sbwml --- ...wall4-add-custom-nft-command-support.patch | 8 ++--- ...0-fw4-add-custom-nft-command-support.patch | 30 ------------------- ...99-01-firewall4-add-fullcone-support.patch | 4 +-- ...irewall4-add-bcm-fullconenat-support.patch | 4 +-- ...l-add-nft-fullcone-and-bcm-fullcone-.patch | 4 +-- ...-app-firewall-add-shortcut-fe-option.patch | 4 +-- ...uci-app-firewall-add-ipv6-nat-option.patch | 4 +-- ...firewall-add-custom-nft-rule-support.patch | 8 ++--- ...firewall-add-natflow-offload-support.patch | 4 +-- ...l-enable-hardware-offload-only-on-de.patch | 4 +-- ...l-add-fullcone6-option-for-nftables-.patch | 29 +++++++++--------- openwrt/scripts/00-prepare_base.sh | 3 +- 12 files changed, 38 insertions(+), 68 deletions(-) delete mode 100644 openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch diff --git a/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch b/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch index 424e2b28e..a9d983807 100644 --- a/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch +++ b/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch @@ -1,4 +1,4 @@ -From 16eb81b40f5b5f6a6200ec584d9aa6aacdbafa54 Mon Sep 17 00:00:00 2001 +From fc404ac0cc99efbd174cd6ef2a531913e26734a6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 14 Mar 2024 12:16:11 +0800 Subject: [PATCH] firewall4: add custom nft command support @@ -11,10 +11,10 @@ Signed-off-by: sbwml create mode 100644 package/network/config/firewall4/patches/100-fw4-add-custom-nft-command-support.patch diff --git a/package/network/config/firewall4/Makefile b/package/network/config/firewall4/Makefile -index 8764f5a..0cde6a6 100644 +index 6ae34ea..3b56e66 100644 --- a/package/network/config/firewall4/Makefile +++ b/package/network/config/firewall4/Makefile -@@ -38,6 +38,7 @@ endef +@@ -39,6 +39,7 @@ endef define Package/firewall4/conffiles /etc/config/firewall /etc/nftables.d/ @@ -59,5 +59,5 @@ index 0000000..6030936 + ACTION=includes \ + utpl -S $MAIN -- -2.42.0 +2.43.5 diff --git a/openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch b/openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch deleted file mode 100644 index 6030936b3..000000000 --- a/openwrt/patch/firewall4/firewall4_patches/100-fw4-add-custom-nft-command-support.patch +++ /dev/null @@ -1,30 +0,0 @@ -From c359ce4457ac48bb65767ae5415f296e3d25a51d Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Thu, 14 Mar 2024 12:10:03 +0800 -Subject: [PATCH] fw4: add custom nft command support - -Signed-off-by: sbwml ---- - root/etc/firewall4.user | 3 +++ - root/sbin/fw4 | 3 ++- - 2 files changed, 5 insertions(+), 1 deletion(-) - create mode 100644 root/etc/firewall4.user - ---- /dev/null -+++ b/root/etc/firewall4.user -@@ -0,0 +1,3 @@ -+# This file is interpreted as shell script. -+# Put your custom nft rules here, they will -+# be executed with each firewall (re-)start. ---- a/root/sbin/fw4 -+++ b/root/sbin/fw4 -@@ -33,7 +33,8 @@ start() { - esac - - ACTION=start \ -- utpl -S $MAIN | nft $VERBOSE -f $STDIN -+ utpl -S $MAIN | nft $VERBOSE -f $STDIN \ -+ ; /bin/sh /etc/firewall4.user - - ACTION=includes \ - utpl -S $MAIN diff --git a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch index ace8764a0..4b840173c 100644 --- a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch +++ b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch @@ -40,7 +40,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. option src lan --- a/root/usr/share/firewall4/templates/ruleset.uc +++ b/root/usr/share/firewall4/templates/ruleset.uc -@@ -323,6 +323,12 @@ table inet fw4 { +@@ -327,6 +327,12 @@ table inet fw4 { {% for (let redirect in fw4.redirects(`dstnat_${zone.name}`)): %} {%+ include("redirect.uc", { fw4, zone, redirect }) %} {% endfor %} @@ -53,7 +53,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. {% fw4.includes('chain-append', `dstnat_${zone.name}`) %} } -@@ -333,20 +339,26 @@ table inet fw4 { +@@ -337,20 +343,26 @@ table inet fw4 { {% for (let redirect in fw4.redirects(`srcnat_${zone.name}`)): %} {%+ include("redirect.uc", { fw4, zone, redirect }) %} {% endfor %} diff --git a/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch b/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch index f8ad58671..7176299a3 100644 --- a/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch +++ b/openwrt/patch/firewall4/firewall4_patches/999-02-firewall4-add-bcm-fullconenat-support.patch @@ -12,7 +12,7 @@ option name lan --- a/root/usr/share/firewall4/templates/ruleset.uc +++ b/root/usr/share/firewall4/templates/ruleset.uc -@@ -323,11 +323,13 @@ table inet fw4 { +@@ -327,11 +327,13 @@ table inet fw4 { {% for (let redirect in fw4.redirects(`dstnat_${zone.name}`)): %} {%+ include("redirect.uc", { fw4, zone, redirect }) %} {% endfor %} @@ -29,7 +29,7 @@ {% endif %} {% fw4.includes('chain-append', `dstnat_${zone.name}`) %} } -@@ -353,11 +355,18 @@ table inet fw4 { +@@ -357,11 +359,18 @@ table inet fw4 { {% endfor %} {% endfor %} {% endif %} diff --git a/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch b/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch index f7be1f925..3a25dbea1 100644 --- a/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch +++ b/openwrt/patch/firewall4/luci-25.12/0001-luci-app-firewall-add-nft-fullcone-and-bcm-fullcone-.patch @@ -1,4 +1,4 @@ -From 0cfeaf969c9b000f6de383d111b8b923d6d05fed Mon Sep 17 00:00:00 2001 +From 6f3aa7ebe51fa2ab1629740d502c109ef68c7077 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 03:35:05 +0800 Subject: [PATCH 1/7] luci-app-firewall: add nft-fullcone and bcm-fullcone @@ -10,7 +10,7 @@ Signed-off-by: sbwml 1 file changed, 21 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 129d290e5c..4675a44efd 100644 +index 129d290..4675a44 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -56,6 +56,27 @@ return view.extend({ diff --git a/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch b/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch index e32fc6a53..847ef4935 100644 --- a/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch +++ b/openwrt/patch/firewall4/luci-25.12/0002-luci-app-firewall-add-shortcut-fe-option.patch @@ -1,4 +1,4 @@ -From 76323fe8dfaf8b241a36b22056781fcdf6f449cc Mon Sep 17 00:00:00 2001 +From b048a9d3fdaa1a51481ef1b4fa2025359785351b Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 17:40:35 +0800 Subject: [PATCH 2/7] luci-app-firewall: add shortcut-fe option @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 4675a44efd..98334c9165 100644 +index 4675a44..98334c9 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -102,18 +102,39 @@ return view.extend({ diff --git a/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch b/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch index 842e2b652..678179cdc 100644 --- a/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch +++ b/openwrt/patch/firewall4/luci-25.12/0003-luci-app-firewall-add-ipv6-nat-option.patch @@ -1,4 +1,4 @@ -From 4e4415c040b8405121be9cc7d25e6e252dbb6316 Mon Sep 17 00:00:00 2001 +From 6b3ff020f1a194684d1f3555a95e6da691a457fc Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 26 Oct 2024 03:37:02 +0800 Subject: [PATCH 3/7] luci-app-firewall: add ipv6 nat option @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 6 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 98334c9165..8417eb2bdc 100644 +index 98334c9..8417eb2 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -77,6 +77,12 @@ return view.extend({ diff --git a/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch b/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch index 4394e76bb..9896eb799 100644 --- a/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch +++ b/openwrt/patch/firewall4/luci-25.12/0004-luci-add-firewall-add-custom-nft-rule-support.patch @@ -1,4 +1,4 @@ -From a7812445e8f7dbf63c04996ed35dbb4869de26a7 Mon Sep 17 00:00:00 2001 +From f025e3b7b999e9375079b0afb1d060038cd146a2 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 4 Sep 2024 12:36:11 +0800 Subject: [PATCH 4/7] luci-add-firewall: add custom nft rule support @@ -11,7 +11,7 @@ Signed-off-by: sbwml 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js -index b273db4704..9bb4d3affa 100644 +index b273db4..9bb4d3a 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js @@ -5,13 +5,13 @@ @@ -40,7 +40,7 @@ index b273db4704..9bb4d3affa 100644 ]); }, diff --git a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json -index f024dcfe25..8aea702c53 100644 +index f024dcf..8aea702 100644 --- a/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json +++ b/applications/luci-app-firewall/root/usr/share/luci/menu.d/luci-app-firewall.json @@ -64,9 +64,6 @@ @@ -54,7 +54,7 @@ index f024dcfe25..8aea702c53 100644 } } diff --git a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json -index 17d1fbab12..7e06de7022 100644 +index 17d1fba..7e06de7 100644 --- a/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json +++ b/applications/luci-app-firewall/root/usr/share/rpcd/acl.d/luci-app-firewall.json @@ -3,7 +3,8 @@ diff --git a/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch b/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch index b1adce45f..99b85f42e 100644 --- a/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch +++ b/openwrt/patch/firewall4/luci-25.12/0005-luci-app-firewall-add-natflow-offload-support.patch @@ -1,4 +1,4 @@ -From e19842ac20e07e2031558daa8c6d3c1811441b57 Mon Sep 17 00:00:00 2001 +From 62a17b33b8ae6ad05234c7ffdc76801b5eba735b Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 17:58:57 +0800 Subject: [PATCH 5/7] luci-app-firewall: add natflow offload support @@ -9,7 +9,7 @@ Signed-off-by: sbwml 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 8417eb2bdc..5ad81a4530 100644 +index 8417eb2..5ad81a4 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -111,25 +111,38 @@ return view.extend({ diff --git a/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch b/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch index ece9047b0..1e2664029 100644 --- a/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch +++ b/openwrt/patch/firewall4/luci-25.12/0006-luci-app-firewall-enable-hardware-offload-only-on-de.patch @@ -1,4 +1,4 @@ -From 18fa3af2cf740557475bfcbdfd6a5aa909724b8a Mon Sep 17 00:00:00 2001 +From 1c7faac708c5c28bf3764d07502e3d9e8b555801 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 25 Oct 2024 21:04:10 +0800 Subject: [PATCH 6/7] luci-app-firewall: enable hardware offload only on @@ -10,7 +10,7 @@ Signed-off-by: sbwml 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index 5ad81a4530..df2f6d69a8 100644 +index 5ad81a4..df2f6d6 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -107,7 +107,9 @@ return view.extend({ diff --git a/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch b/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch index 4e40aa565..5764c8424 100644 --- a/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch +++ b/openwrt/patch/firewall4/luci-25.12/0007-luci-app-firewall-add-fullcone6-option-for-nftables-.patch @@ -1,4 +1,4 @@ -From ff0f5e454d80e392f2985071ad9c0a3fd2fa01c6 Mon Sep 17 00:00:00 2001 +From 4cd5c39d1dfef115e81e148ceb5f821cf8a30aa7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 18 Dec 2024 23:38:26 +0800 Subject: [PATCH 7/7] luci-app-firewall: add fullcone6 option for nftables @@ -6,17 +6,22 @@ Subject: [PATCH 7/7] luci-app-firewall: add fullcone6 option for nftables Signed-off-by: sbwml --- - .../resources/view/firewall/zones.js | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) + .../resources/view/firewall/zones.js | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -index df2f6d69a8..0a1646594d 100644 +index df2f6d6..45351b3 100644 --- a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js -@@ -75,6 +75,25 @@ return view.extend({ +@@ -74,6 +74,24 @@ return view.extend({ + o.write = function(section_id, value) { uci.set('firewall', section_id, 'fullcone', value === '0' ? null : '1'); uci.set('firewall', section_id, 'brcmfullcone', value === '2' ? '1' : null); - }; ++ ++ if (value === '0') { ++ uci.set('firewall', '@zone[1]', 'fullcone6', '0'); ++ } ++ }; + + /* nft-fullcone 6 */ + o = s.option(form.RichListValue, "fullcone6", _("Full Cone NAT6")); @@ -25,20 +30,14 @@ index df2f6d69a8..0a1646594d 100644 + o.optional = false; + o.depends('fullcone_type', '1'); + o.load = function (section_id) { -+ var fullcone6 = uci.get('firewall', section_id, 'fullcone6'); -+ if (fullcone6 === '1') { -+ return '1'; -+ } else { -+ return '0'; -+ } ++ var fullcone6 = uci.get('firewall', '@zone[1]', 'fullcone6'); ++ return (fullcone6 === '1') ? '1' : '0'; + }; + o.write = function(section_id, value) { -+ uci.set('firewall', section_id, 'fullcone6', value === '1' ? '1' : '0'); + uci.set('firewall', '@zone[1]', 'fullcone6', value === '1' ? '1' : '0'); -+ }; + }; } - if (L.hasSystemFeature('ipv6')) { -- 2.43.5 diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 9bdcfc90a..c8d48cd67 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -125,7 +125,6 @@ git clone https://$gitea/sbwml/shortcut-fe package/new/shortcut-fe # Patch FireWall 4 if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then # firewall4 - sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/network/config/firewall4/Makefile mkdir -p package/network/config/firewall4/patches # fullcone curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch > package/network/config/firewall4/patches/999-01-firewall4-add-fullcone-support.patch @@ -135,6 +134,8 @@ if [ "$version" = "dev" ] || [ "$version" = "rc2" ]; then curl -s $mirror/openwrt/patch/firewall4/firewall4_patches/001-fix-fw4-flow-offload.patch > package/network/config/firewall4/patches/001-fix-fw4-flow-offload.patch # add custom nft command support curl -s $mirror/openwrt/patch/firewall4/100-openwrt-firewall4-add-custom-nft-command-support.patch | patch -p1 + # fw4 - github mirror + sed -i 's|$(PROJECT_GIT)/project|https://github.com/openwrt|g' package/network/config/firewall4/Makefile # libnftnl mkdir -p package/libs/libnftnl/patches curl -s $mirror/openwrt/patch/firewall4/libnftnl/0001-libnftnl-add-fullcone-expression-support.patch > package/libs/libnftnl/patches/0001-libnftnl-add-fullcone-expression-support.patch From 23ed6b3143df44a8597c86a5898b016b75fd4dc4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 6 May 2026 22:25:58 +0800 Subject: [PATCH 403/425] OpenWrt v25.12.3 Signed-off-by: sbwml --- .../999-01-firewall4-add-fullcone-support.patch | 2 +- ...-app-natmap-add-default-STUN-server-lists.patch | 3 +++ ...ckage-manager-support-installing-uploaded.patch | 14 +++++++------- .../patch/target-modify_for_aarch64_x86_64.patch | 6 +++--- tags/v25 | 2 +- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch index 4b840173c..42e5d6670 100644 --- a/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch +++ b/openwrt/patch/firewall4/firewall4_patches/999-01-firewall4-add-fullcone-support.patch @@ -34,7 +34,7 @@ IPv6 traffic do NOT need this FullCone NAT functionality. option masq 1 option mtu_fix 1 + option fullcone4 1 -+ option fullcone6 1 ++ option fullcone6 0 config forwarding option src lan diff --git a/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch b/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch index f67ecad46..3355bd53f 100644 --- a/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch +++ b/openwrt/patch/luci/applications/luci-app-natmap/0001-luci-app-natmap-add-default-STUN-server-lists.patch @@ -39,3 +39,6 @@ index 6c01d88..f64e4ed 100644 o.datatype = 'string'; o.modalonly = true; o.rmempty = false; +-- +2.43.5 + diff --git a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch index 4798610cc..0b8ff3cf9 100644 --- a/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch +++ b/openwrt/patch/luci/applications/luci-app-package-manager/0001-luci-app-package-manager-support-installing-uploaded.patch @@ -8,14 +8,14 @@ Signed-off-by: sbwml --- .../htdocs/luci-static/resources/view/package-manager.js | 2 +- .../root/usr/libexec/package-manager-call | 5 ++++- - .../root/usr/share/rpcd/acl.d/luci-app-package-manager.json | 1 + - 3 files changed, 6 insertions(+), 2 deletions(-) + .../root/usr/share/rpcd/acl.d/luci-app-package-manager.json | 2 ++ + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js -index 48476db..6afa589 100644 +index e6b1a45..4d62fcc 100644 --- a/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js +++ b/applications/luci-app-package-manager/htdocs/luci-static/resources/view/package-manager.js -@@ -1086,7 +1086,7 @@ function handleUpload(ev) +@@ -1122,7 +1122,7 @@ function handleUpload(ev) }, _('Cancel')), ' ', E('div', { 'class': 'btn cbi-button-action', @@ -25,7 +25,7 @@ index 48476db..6afa589 100644 'click': function(ev) { handlePkg(ev).finally(function() { diff --git a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call -index 3a41757..7fa58f9 100755 +index b641483..82fa58c 100755 --- a/applications/luci-app-package-manager/root/usr/libexec/package-manager-call +++ b/applications/luci-app-package-manager/root/usr/libexec/package-manager-call @@ -27,7 +27,7 @@ case "$action" in @@ -44,8 +44,8 @@ index 3a41757..7fa58f9 100755 + install-upload) + action="add --allow-untrusted" + ;; - update) - action="update" + remove) + action="del" ;; diff --git a/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json b/applications/luci-app-package-manager/root/usr/share/rpcd/acl.d/luci-app-package-manager.json index 8d55186..6ec7947 100644 diff --git a/openwrt/patch/target-modify_for_aarch64_x86_64.patch b/openwrt/patch/target-modify_for_aarch64_x86_64.patch index 17d6e1630..af99426e4 100644 --- a/openwrt/patch/target-modify_for_aarch64_x86_64.patch +++ b/openwrt/patch/target-modify_for_aarch64_x86_64.patch @@ -5,7 +5,7 @@ BuildTarget=$(BuildTargets/DumpCurrent) - CPU_CFLAGS = -Os -pipe -+ CPU_CFLAGS = -O3 -mtune=generic -pipe ++ CPU_CFLAGS = -O2 -mtune=generic -pipe ifneq ($(findstring mips,$(ARCH)),) ifneq ($(findstring mips64,$(ARCH)),) CPU_TYPE ?= mips64 @@ -14,11 +14,11 @@ CPU_CFLAGS_generic:=-march=loongarch64 endif + ifeq ($(BOARD),armsr) -+ CPU_CFLAGS = -O3 -pipe ++ CPU_CFLAGS = -O2 -pipe + CPU_CFLAGS_generic = -march=armv8-a+crc+crypto + endif + ifeq ($(BOARD),rockchip) -+ CPU_CFLAGS = -O3 -Wl,--gc-sections -pipe ++ CPU_CFLAGS = -O2 -Wl,--gc-sections -pipe + CPU_CFLAGS_generic = -march=armv8-a+crc+crypto + endif ifneq ($(CPU_TYPE),) diff --git a/tags/v25 b/tags/v25 index e055000e0..4b66be7c3 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.2 +25.12.3 From 1cc8447b4093d9c2948e75cdf985b38f80e47906 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 10 May 2026 00:58:14 +0800 Subject: [PATCH 404/425] linux-6.18: bump to 6.18.28 Signed-off-by: sbwml --- ...r-update-kernel-config-options-for-l.patch | 34 ------------------- ...hrink-delivered_mstamp-first_tx_msta.patch | 4 +-- ...napshot-packets-in-flight-at-transmi.patch | 6 ++-- ...ount-packets-lost-over-TCP-rate-samp.patch | 4 +-- ...xport-FLAG_ECE-in-rate_sample.is_ece.patch | 2 +- ...ntroduce-ca_ops-skb_marked_lost-CC-m.patch | 2 +- ...djust-skb-tx.in_flight-upon-split-in.patch | 2 +- ...ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 4 +-- ...alize-TSO-sizing-in-TCP-CC-module-AP.patch | 2 +- ..._ack_mode-1-skip-rwin-check-in-tcp_f.patch | 4 +-- ...nform-CC-module-of-losses-repaired-b.patch | 2 +- ...ntroduce-is_acking_tlp_retrans_seq-i.patch | 2 +- ...r-route-feature-RTAX_FEATURE_ECN_LOW.patch | 4 +-- ...pdate-TCP-bbr-congestion-control-mod.patch | 4 +-- ...nsure-ECN-enabled-BBR-flows-set-ECT-.patch | 2 +- ...OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 2 +- ...-silence-btf-module-warning-messages.patch | 2 +- ...ter-export-udp_get_timeouts-function.patch | 2 +- ...k-events-support-multiple-registrant.patch | 8 ++--- ...-linux-kernel-to-support-shortcut-fe.patch | 12 +++---- ...83-add-bcm-fullcone-nft_masq-support.patch | 2 +- .../patch/openwrt-6.x/modules/netfilter.mk | 19 +++++++++++ openwrt/scripts/00-prepare_base.sh | 1 - tags/kernel-6.18 | 4 +-- 24 files changed, 57 insertions(+), 73 deletions(-) delete mode 100644 openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch diff --git a/openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch b/openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch deleted file mode 100644 index de8fe5f01..000000000 --- a/openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 431c5f546692b996a40500aea48eea9c1412af36 Mon Sep 17 00:00:00 2001 -From: sbwml -Date: Fri, 31 Oct 2025 12:32:08 +0800 -Subject: [PATCH 13/13] include: netfilter: update kernel config options for - legacy iptables and ebtables - -Signed-off-by: sbwml ---- - include/netfilter.mk | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/include/netfilter.mk b/include/netfilter.mk -index 255e478..afe9d4d 100644 ---- a/include/netfilter.mk -+++ b/include/netfilter.mk -@@ -30,6 +30,7 @@ endef - $(eval $(if $(NF_KMOD),$(call nf_add,NF_REJECT,CONFIG_NF_REJECT_IPV4, $(P_V4)nf_reject_ipv4),)) - - $(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES, $(P_V4)ip_tables),)) -+$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES_LEGACY, $(P_V4)ip_tables),)) - $(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_NETFILTER_XTABLES, $(P_XT)x_tables),)) - - $(eval $(if $(NF_KMOD),$(call nf_add,IPT_CORE,CONFIG_NETFILTER_XTABLES, $(P_XT)xt_tcpudp),)) -@@ -283,6 +284,7 @@ $(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNCOUNT,CONFIG_NETFILTER_CONNCOUNT, $( - # - - $(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES, $(P_EBT)ebtables),)) -+$(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES_LEGACY, $(P_EBT)ebtables),)) - - # ebtables: tables - $(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_BROUTE, $(P_EBT)ebtable_broute)) --- -2.43.5 - diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch index 336406daa..6def0c575 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -943,6 +943,11 @@ static inline u32 tcp_stamp_us_delta(u64 +@@ -946,6 +946,11 @@ static inline u32 tcp_stamp_us_delta(u64 return max_t(s64, t1 - t0, 0); } @@ -37,7 +37,7 @@ Signed-off-by: Alexandre Frade /* provide the departure time in us unit */ static inline u64 tcp_skb_timestamp_us(const struct sk_buff *skb) { -@@ -1053,9 +1058,9 @@ struct tcp_skb_cb { +@@ -1056,9 +1061,9 @@ struct tcp_skb_cb { /* pkts S/ACKed so far upon tx of skb, incl retrans: */ __u32 delivered; /* start of send pipeline phase */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index 70be17ed8..65c97f9d1 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1061,6 +1061,10 @@ struct tcp_skb_cb { +@@ -1064,6 +1064,10 @@ struct tcp_skb_cb { u32 first_tx_mstamp; /* when we reached the "delivered" count */ u32 delivered_mstamp; @@ -38,7 +38,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1225,6 +1229,7 @@ struct rate_sample { +@@ -1228,6 +1232,7 @@ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ @@ -46,7 +46,7 @@ Signed-off-by: Alexandre Frade s32 delivered; /* number of packets delivered over interval */ s32 delivered_ce; /* number of packets delivered w/ CE marks*/ long interval_us; /* time for tp->delivered to incr "delivered" */ -@@ -1368,6 +1373,7 @@ static inline void tcp_ca_event(struct s +@@ -1371,6 +1376,7 @@ static inline void tcp_ca_event(struct s void tcp_set_ca_state(struct sock *sk, const u8 ca_state); /* From tcp_rate.c */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch index 4e7898bec..ceac09fba 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch @@ -19,7 +19,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1065,6 +1065,7 @@ struct tcp_skb_cb { +@@ -1068,6 +1068,7 @@ struct tcp_skb_cb { #define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) u32 in_flight:20, /* packets in flight at transmit */ unused2:12; @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1227,11 +1228,13 @@ struct ack_sample { +@@ -1230,11 +1231,13 @@ struct ack_sample { */ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index 64bed7e5b..fde30ff41 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -18,7 +18,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1246,6 +1246,7 @@ struct rate_sample { +@@ -1249,6 +1249,7 @@ struct rate_sample { bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ bool is_ack_delayed; /* is this (likely) a delayed ACK? */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index a34b6e5d7..972ea9630 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -30,7 +30,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1273,6 +1273,9 @@ struct tcp_congestion_ops { +@@ -1276,6 +1276,9 @@ struct tcp_congestion_ops { /* override sysctl_tcp_min_tso_segs */ u32 (*min_tso_segs)(struct sock *sk); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch index f6b6059df..7419d1310 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1393,6 +1393,21 @@ static inline bool tcp_skb_sent_after(u6 +@@ -1396,6 +1396,21 @@ static inline bool tcp_skb_sent_after(u6 return t1 > t2 || (t1 == t2 && after(seq1, seq2)); } diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch index 29748a6d6..a18e66738 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch @@ -23,7 +23,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1206,9 +1206,11 @@ enum tcp_ca_ack_event_flags { +@@ -1209,9 +1209,11 @@ enum tcp_ca_ack_event_flags { #define TCP_CONG_ECT_1_NEGOTIATION BIT(3) /* Cannot fallback to RFC3168 during AccECN negotiation */ #define TCP_CONG_NO_FALLBACK_RFC3168 BIT(4) @@ -36,7 +36,7 @@ Signed-off-by: Alexandre Frade union tcp_cc_info; -@@ -1340,6 +1342,14 @@ static inline char *tcp_ca_get_name_by_k +@@ -1343,6 +1345,14 @@ static inline char *tcp_ca_get_name_by_k } #endif diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch index 7ed2df88b..87ccc3266 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1272,8 +1272,8 @@ struct tcp_congestion_ops { +@@ -1275,8 +1275,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 990a657e8..7af965997 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade /* RX read-mostly hotpath cache lines */ --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -3470,6 +3470,7 @@ int tcp_disconnect(struct sock *sk, int +@@ -3471,6 +3471,7 @@ int tcp_disconnect(struct sock *sk, int tp->rx_opt.dsack = 0; tp->rx_opt.num_sacks = 0; tp->rcv_ooopack = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5909,13 +5909,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5906,13 +5906,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index 204395fff..c560e1daf 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1178,6 +1178,7 @@ enum tcp_ca_event { +@@ -1181,6 +1181,7 @@ enum tcp_ca_event { CA_EVENT_LOSS, /* loss timeout */ CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index 0cc31447e..bb410c8b1 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -21,7 +21,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1248,6 +1248,7 @@ struct rate_sample { +@@ -1251,6 +1251,7 @@ struct rate_sample { u32 last_end_seq; /* end_seq of most recently ACKed packet */ bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch index 81a3b27d4..3523ebbc9 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -403,6 +403,7 @@ static inline void tcp_dec_quickack_mode +@@ -404,6 +404,7 @@ static inline void tcp_dec_quickack_mode #define TCP_ECN_DEMAND_CWR BIT(2) #define TCP_ECN_SEEN BIT(3) #define TCP_ECN_MODE_ACCECN BIT(4) @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade #define TCP_ECN_DISABLED 0 #define TCP_ECN_MODE_PENDING (TCP_ECN_MODE_RFC3168 | TCP_ECN_MODE_ACCECN) -@@ -836,6 +837,15 @@ static inline u32 __tcp_set_rto(const st +@@ -839,6 +840,15 @@ static inline u32 __tcp_set_rto(const st return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us); } diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch index 5d20ed5b2..198da7d4f 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -140,7 +140,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h -@@ -132,8 +132,8 @@ struct inet_connection_sock { +@@ -134,8 +134,8 @@ struct inet_connection_sock { u32 icsk_probes_tstamp; u32 icsk_user_timeout; @@ -153,7 +153,7 @@ Signed-off-by: Alexandre Frade #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -2615,7 +2615,7 @@ struct tcp_plb_state { +@@ -2619,7 +2619,7 @@ struct tcp_plb_state { u8 consec_cong_rounds:5, /* consecutive congested rounds */ unused:3; u32 pause_until; /* jiffies32 when PLB can resume rerouting */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch index b253a9ce0..db73b98b2 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -404,6 +404,7 @@ static inline void tcp_dec_quickack_mode +@@ -405,6 +405,7 @@ static inline void tcp_dec_quickack_mode #define TCP_ECN_SEEN BIT(3) #define TCP_ECN_MODE_ACCECN BIT(4) #define TCP_ECN_LOW BIT(5) diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch index f59dd8091..c01bc6661 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade * Sender's congestion state indicating normal or abnormal situations --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -4228,6 +4228,8 @@ void tcp_get_info(struct sock *sk, struc +@@ -4229,6 +4229,8 @@ void tcp_get_info(struct sock *sk, struc info->tcpi_options |= TCPI_OPT_ECN; if (tp->ecn_flags & TCP_ECN_SEEN) info->tcpi_options |= TCPI_OPT_ECN_SEEN; diff --git a/openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch b/openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch index d154bb792..a327fef3b 100644 --- a/openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch +++ b/openwrt/patch/kernel-6.18/btf/990-btf-silence-btf-module-warning-messages.patch @@ -10,7 +10,7 @@ Signed-off-by: sbwml --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c -@@ -8199,8 +8199,6 @@ static int btf_module_notify(struct noti +@@ -8208,8 +8208,6 @@ static int btf_module_notify(struct noti pr_warn("failed to validate module [%s] BTF: %ld\n", mod->name, PTR_ERR(btf)); err = PTR_ERR(btf); diff --git a/openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeouts-function.patch b/openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeouts-function.patch index d741cb7c3..9b13a744c 100644 --- a/openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeouts-function.patch +++ b/openwrt/patch/kernel-6.18/net/601-netfilter-export-udp_get_timeouts-function.patch @@ -14,7 +14,7 @@ Change-Id: Ibca4f402735764e7e6fb3ce2678e670753c6ef9c --- a/include/net/netfilter/nf_conntrack_timeout.h +++ b/include/net/netfilter/nf_conntrack_timeout.h -@@ -107,5 +107,6 @@ struct nf_ct_timeout_hooks { +@@ -108,5 +108,6 @@ struct nf_ct_timeout_hooks { extern const struct nf_ct_timeout_hooks __rcu *nf_ct_timeout_hook; #endif diff --git a/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch b/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch index e6be120e3..5acc321a1 100644 --- a/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch +++ b/openwrt/patch/kernel-6.18/net/952-net-conntrack-events-support-multiple-registrant.patch @@ -243,7 +243,7 @@ Signed-off-by: Zhi Chen EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, -@@ -268,20 +343,43 @@ out_unlock: +@@ -270,20 +345,43 @@ out_unlock: rcu_read_unlock(); } @@ -289,7 +289,7 @@ Signed-off-by: Zhi Chen void nf_conntrack_unregister_notifier(struct net *net) { mutex_lock(&nf_ct_ecache_mutex); -@@ -289,6 +387,7 @@ void nf_conntrack_unregister_notifier(st +@@ -291,6 +389,7 @@ void nf_conntrack_unregister_notifier(st mutex_unlock(&nf_ct_ecache_mutex); /* synchronize_rcu() is called after netns pre_exit */ } @@ -319,7 +319,7 @@ Signed-off-by: Zhi Chen struct nf_conn *ct = item->ct; struct sk_buff *skb; unsigned int type; -@@ -3754,11 +3761,17 @@ static int ctnetlink_stat_exp_cpu(struct +@@ -3753,11 +3760,17 @@ static int ctnetlink_stat_exp_cpu(struct } #ifdef CONFIG_NF_CONNTRACK_EVENTS @@ -337,7 +337,7 @@ Signed-off-by: Zhi Chen static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { [IPCTNL_MSG_CT_NEW] = { -@@ -3857,8 +3870,12 @@ static int __net_init ctnetlink_net_init +@@ -3856,8 +3869,12 @@ static int __net_init ctnetlink_net_init static void ctnetlink_net_pre_exit(struct net *net) { #ifdef CONFIG_NF_CONNTRACK_EVENTS diff --git a/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch index 8bc7cac0f..5db4c5eb1 100644 --- a/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch +++ b/openwrt/patch/kernel-6.18/net/953-net-patch-linux-kernel-to-support-shortcut-fe.patch @@ -93,7 +93,7 @@ Signed-off-by: Xiaoping Fan struct net_bridge_port *p; --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -3850,8 +3850,17 @@ static int xmit_one(struct sk_buff *skb, +@@ -3867,8 +3867,17 @@ static int xmit_one(struct sk_buff *skb, unsigned int len; int rc; @@ -111,7 +111,7 @@ Signed-off-by: Xiaoping Fan #ifdef CONFIG_ETHERNET_PACKET_MANGLE if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) -@@ -5827,6 +5836,11 @@ void netdev_rx_handler_unregister(struct +@@ -5852,6 +5861,11 @@ void netdev_rx_handler_unregister(struct } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -123,7 +123,7 @@ Signed-off-by: Xiaoping Fan /* * Limit the use of PFMEMALLOC reserves to those protocols that implement * the special handling of PFMEMALLOC skbs. -@@ -5876,6 +5890,10 @@ static int __netif_receive_skb_core(stru +@@ -5901,6 +5915,10 @@ static int __netif_receive_skb_core(stru int ret = NET_RX_DROP; __be16 type; @@ -134,7 +134,7 @@ Signed-off-by: Xiaoping Fan net_timestamp_check(!READ_ONCE(net_hotdata.tstamp_prequeue), skb); trace_netif_receive_skb(skb); -@@ -5920,6 +5938,16 @@ another_round: +@@ -5945,6 +5963,16 @@ another_round: goto out; } @@ -179,7 +179,7 @@ Signed-off-by: Xiaoping Fan rcu_read_unlock(); if (likely(ret >= 0 && missed == 0)) -@@ -349,6 +361,11 @@ int nf_conntrack_register_notifier(struc +@@ -351,6 +363,11 @@ int nf_conntrack_register_notifier(struc { return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb); } @@ -191,7 +191,7 @@ Signed-off-by: Xiaoping Fan #else int nf_conntrack_register_notifier(struct net *net, const struct nf_ct_event_notifier *new) -@@ -379,6 +396,11 @@ int nf_conntrack_unregister_notifier(str +@@ -381,6 +398,11 @@ int nf_conntrack_unregister_notifier(str { return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb); } diff --git a/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch b/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch index e9b3418e7..65596dae4 100644 --- a/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch +++ b/openwrt/patch/kernel-6.18/net/983-add-bcm-fullcone-nft_masq-support.patch @@ -30,7 +30,7 @@ #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -11716,6 +11716,24 @@ static int nft_validate_register_load(en +@@ -11708,6 +11708,24 @@ static int nft_validate_register_load(en return 0; } diff --git a/openwrt/patch/openwrt-6.x/modules/netfilter.mk b/openwrt/patch/openwrt-6.x/modules/netfilter.mk index 64e3e3482..24ca52ad3 100644 --- a/openwrt/patch/openwrt-6.x/modules/netfilter.mk +++ b/openwrt/patch/openwrt-6.x/modules/netfilter.mk @@ -51,6 +51,25 @@ endef $(eval $(call KernelPackage,nf-conncount)) + +define KernelPackage/iptables + SUBMENU:=$(NF_MENU) + TITLE:=Iptables legacy + KCONFIG:= \ + CONFIG_IP_NF_IPTABLES_LEGACY \ + CONFIG_NETFILTER_XTABLES \ + CONFIG_NETFILTER_XTABLES_LEGACY=y \ + CONFIG_IP6_NF_IPTABLES_LEGACY \ + CONFIG_BRIDGE_NF_EBTABLES_LEGACY + FILES:= \ + $(LINUX_DIR)/net/ipv4/netfilter/ip_tables.ko \ + $(LINUX_DIR)/net/netfilter/x_tables.ko + AUTOLOAD:=$(call AutoProbe,$(notdir ip_tables x_tables)) +endef + +$(eval $(call KernelPackage,iptables)) + + define KernelPackage/nf-ipt SUBMENU:=$(NF_MENU) TITLE:=Iptables core diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index c8d48cd67..5b1cfb5b7 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -26,7 +26,6 @@ curl -s $mirror/openwrt/patch/generic-25.12/0009-tools-squashfs4-enable-lz4-zstd curl -s $mirror/openwrt/patch/generic-25.12/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-25.12/0011-config-include-image-add-support-for-squashfs-zstd-c.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-25.12/0012-include-kernel-Always-collect-module-symvers.patch | patch -p1 -curl -s $mirror/openwrt/patch/generic-25.12/0013-include-netfilter-update-kernel-config-options-for-l.patch | patch -p1 # add source mirror #sed -i '/"@OPENWRT": \[/a\\t\t"https://sources-cdn-openwrt.cooluc.com",' scripts/projectsmirrors.json diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index f6c69e798..05250b0fd 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .26 -LINUX_KERNEL_HASH-6.18.26 = 53772f5d3776e043767c8d81a32240d1f3eb64e822a5d7a510b55ca40707b0ec +LINUX_VERSION-6.18 = .28 +LINUX_KERNEL_HASH-6.18.28 = f360789483586cf8a20b4ab2bffe76ead6b62c0db1eeb0d917294456c4d77b74 From f0b37650ee4319b8d62542b9268d1ad700ef2890 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 10 May 2026 01:00:13 +0800 Subject: [PATCH 405/425] mac80211: update to linux 7.0.5 Signed-off-by: sbwml --- openwrt/scripts/01-prepare_base-mainline.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openwrt/scripts/01-prepare_base-mainline.sh b/openwrt/scripts/01-prepare_base-mainline.sh index 5ef7f7c4b..718070cb7 100644 --- a/openwrt/scripts/01-prepare_base-mainline.sh +++ b/openwrt/scripts/01-prepare_base-mainline.sh @@ -178,9 +178,9 @@ popd # wireless-regdb curl -s $mirror/openwrt/patch/openwrt-6.x/500-world-regd-5GHz.patch > package/firmware/wireless-regdb/patches/500-world-regd-5GHz.patch -# mac80211 - 6.18 +# mac80211 - linux 7.x rm -rf package/kernel/mac80211 -git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v6.18 +git clone https://$github/sbwml/package_kernel_mac80211 package/kernel/mac80211 -b v7.0.5 # ath10k-ct rm -rf package/kernel/ath10k-ct From 5fc4b5bb2ee1a84189f3c82800391b8615feebbc Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 11 May 2026 00:30:59 +0800 Subject: [PATCH 406/425] modules: add `kmod-adc-keys` modules Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/input.mk | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openwrt/patch/openwrt-6.x/modules/input.mk b/openwrt/patch/openwrt-6.x/modules/input.mk index b780c1c4b..3b3df6962 100644 --- a/openwrt/patch/openwrt-6.x/modules/input.mk +++ b/openwrt/patch/openwrt-6.x/modules/input.mk @@ -54,6 +54,24 @@ endef $(eval $(call KernelPackage,hid-alps)) +define KernelPackage/input-adc-keys + SUBMENU:=$(INPUT_MODULES_MENU) + TITLE:=ADC Ladder Buttons support + DEPENDS:=+kmod-input-core +kmod-iio-core + KCONFIG:= \ + CONFIG_KEYBOARD_ADC \ + CONFIG_INPUT_KEYBOARD=y + FILES:=$(LINUX_DIR)/drivers/input/keyboard/adc-keys.ko + AUTOLOAD:=$(call AutoProbe,adc-keys,1) +endef + +define KernelPackage/input-adc-keys/description + Buttons/keys input driver for resistor ladder connected on ADC +endef + +$(eval $(call KernelPackage,input-adc-keys)) + + define KernelPackage/input-core SUBMENU:=$(INPUT_MODULES_MENU) TITLE:=Input device core From 75d56c50c8b0bcc553c685812388adf66808251a Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 11 May 2026 03:30:18 +0800 Subject: [PATCH 407/425] script: update rust/node feeds Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 264e95010..9611ecc58 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -4,9 +4,13 @@ rm -rf feeds/packages/lang/golang git clone https://$github/sbwml/packages_lang_golang -b 26.x feeds/packages/lang/golang +# rust +rm -rf feeds/packages/lang/rust +git clone https://$github/sbwml/packages_lang_rust feeds/packages/lang/rust + # node - prebuilt rm -rf feeds/packages/lang/node -git clone https://$github/sbwml/feeds_packages_lang_node-prebuilt feeds/packages/lang/node -b packages-24.10 +git clone https://$github/sbwml/feeds_packages_lang_node feeds/packages/lang/node -b openwrt-25.12 # default settings git clone https://$github/sbwml/default-settings package/new/default-settings -b openwrt-25.12 From b0aefe808caa478636aad2f07bf60097974a6a76 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 11 May 2026 11:35:47 +0800 Subject: [PATCH 408/425] node: fix source branche Signed-off-by: sbwml --- openwrt/scripts/02-prepare_package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index 9611ecc58..a9a3179e4 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -10,7 +10,7 @@ git clone https://$github/sbwml/packages_lang_rust feeds/packages/lang/rust # node - prebuilt rm -rf feeds/packages/lang/node -git clone https://$github/sbwml/feeds_packages_lang_node feeds/packages/lang/node -b openwrt-25.12 +git clone https://$github/sbwml/feeds_packages_lang_node feeds/packages/lang/node -b packages-25.12 # default settings git clone https://$github/sbwml/default-settings package/new/default-settings -b openwrt-25.12 From ddb3dc21c0efae8180348d094ca985c440bf7eda Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 12 May 2026 11:01:10 +0800 Subject: [PATCH 409/425] toolchain: gcc: add support for GCC-16 Signed-off-by: sbwml --- README.md | 11 +- openwrt/build.sh | 6 +- ...toolchain-gcc-add-support-for-GCC-16.patch | 887 ++++++++++++++++++ .../0014-tools-mold-update-to-2.41.0.patch | 33 + .../0015-tools-build-lz4-by-default.patch | 52 + ...-fix-gcc16-null-dereference-with-lto.patch | 11 + .../900-fix-build-for-gcc-16.patch | 29 + openwrt/scripts/00-prepare_base.sh | 3 + openwrt/scripts/04-fix_kmod.sh | 3 - openwrt/scripts/05-fix-source.sh | 65 +- 10 files changed, 1039 insertions(+), 61 deletions(-) create mode 100644 openwrt/patch/generic-25.12/0013-toolchain-gcc-add-support-for-GCC-16.patch create mode 100644 openwrt/patch/generic-25.12/0014-tools-mold-update-to-2.41.0.patch create mode 100644 openwrt/patch/generic-25.12/0015-tools-build-lz4-by-default.patch create mode 100644 openwrt/patch/packages-patches_gcc16/elfutils/900-fix-gcc16-null-dereference-with-lto.patch create mode 100644 openwrt/patch/packages-patches_gcc16/libwebsockets/900-fix-build-for-gcc-16.patch diff --git a/README.md b/README.md index 2b2ea05f6..52c352c0c 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ export git_name=账户名 git_password=密码 export KERNEL_CLANG_LTO=y ``` -### 启用 [GCC13](https://gcc.gnu.org/gcc-13/)/[GCC14](https://gcc.gnu.org/gcc-14/)/[GCC15](https://gcc.gnu.org/gcc-15/) 工具链编译 -##### 只需在构建固件前执行以下命令即可启用 GCC13/GCC14/GCC15 交叉工具链 +### 启用 [GCC13](https://gcc.gnu.org/gcc-13/)/[GCC14](https://gcc.gnu.org/gcc-14/)/[GCC15](https://gcc.gnu.org/gcc-15/)/[GCC16](https://gcc.gnu.org/gcc-16/) 工具链编译 +##### 只需在构建固件前执行以下命令即可启用对应交叉工具链版本 ``` # GCC13 @@ -64,6 +64,11 @@ export USE_GCC14=y export USE_GCC15=y ``` +``` +# GCC16 +export USE_GCC16=y +``` + ### 启用 [LTO](https://gcc.gnu.org/onlinedocs/gccint/LTO-Overview.html) 优化 ##### 只需在构建固件前执行以下命令即可启用编译器 LTO 优化 @@ -71,7 +76,7 @@ export USE_GCC15=y export ENABLE_LTO=y ``` -### 启用 [MOLD](https://github.com/rui314/mold) 现代链接器(需要启用 `USE_GCC13=y` 或 `USE_GCC14=y` 或 `USE_GCC15=y`) +### 启用 [MOLD](https://github.com/rui314/mold) 现代链接器 ##### 只需在构建固件前执行以下命令即可启用 MOLD 链接,如果使用它建议同时启用 LTO 优化 ``` diff --git a/openwrt/build.sh b/openwrt/build.sh index 764afd5aa..65fbcf330 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -131,6 +131,8 @@ elif [ "$USE_GCC14" = y ]; then export USE_GCC14=y gcc_version=14 elif [ "$USE_GCC15" = y ]; then export USE_GCC15=y gcc_version=15 +elif [ "$USE_GCC16" = y ]; then + export USE_GCC16=y gcc_version=16 else export USE_GCC15=y gcc_version=15 fi @@ -361,7 +363,7 @@ export ENABLE_LTO=$ENABLE_LTO # kernel - CLANG + LTO; Allow CONFIG_KERNEL_CC=clang / clang-18 / clang-xx if [ "$KERNEL_CLANG_LTO" = "y" ]; then echo '# Kernel - CLANG LTO' >> .config - if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then + if [ "$USE_GCC15" = "y" ] || [ "$USE_GCC16" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then echo 'CONFIG_KERNEL_CC="ccache clang"' >> .config else echo 'CONFIG_KERNEL_CC="clang"' >> .config @@ -403,7 +405,7 @@ echo -e "CONFIG_GCC_USE_VERSION_${gcc_version}=y\n" >> .config [ "$OPENWRT_CORE" = "y" ] && echo 'CONFIG_PACKAGE_kmod-mt7927-firmware=m' >> .config # ccache -if [ "$USE_GCC15" = "y" ] && [ "$ENABLE_CCACHE" = "y" ]; then +if [ "$ENABLE_CCACHE" = "y" ]; then echo "CONFIG_CCACHE=y" >> .config [ "$(whoami)" = "runner" ] && echo "CONFIG_CCACHE_DIR=\"/builder/.ccache\"" >> .config [ "$(whoami)" = "sbwml" ] && echo "CONFIG_CCACHE_DIR=\"/home/sbwml/.ccache\"" >> .config diff --git a/openwrt/patch/generic-25.12/0013-toolchain-gcc-add-support-for-GCC-16.patch b/openwrt/patch/generic-25.12/0013-toolchain-gcc-add-support-for-GCC-16.patch new file mode 100644 index 000000000..98f61f52c --- /dev/null +++ b/openwrt/patch/generic-25.12/0013-toolchain-gcc-add-support-for-GCC-16.patch @@ -0,0 +1,887 @@ +From a9d317aa12af81e7c829ce9a01abcd29cb9f8cc1 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Mon, 11 May 2026 15:40:54 +0800 +Subject: [PATCH 1/2] toolchain: gcc: add support for GCC-16 + +Signed-off-by: sbwml +--- + toolchain/gcc/Config.in | 3 + + toolchain/gcc/Config.version | 5 + + toolchain/gcc/common.mk | 4 + + .../patches-16.x/002-case_insensitive.patch | 24 +++ + ...t-choke-when-building-32bit-on-64bit.patch | 13 ++ + .../gcc/patches-16.x/010-documentation.patch | 35 +++++ + .../patches-16.x/110-Fix-MIPS-PR-84790.patch | 20 +++ + .../gcc/patches-16.x/230-musl_libssp.patch | 13 ++ + .../300-mips_Os_cpu_rtx_cost_model.patch | 21 +++ + .../800-arm_v5te_no_ldrd_strd.patch | 11 ++ + .../810-arm-softfloat-libgcc.patch | 33 ++++ + .../gcc/patches-16.x/820-libgcc_pic.patch | 44 ++++++ + .../patches-16.x/830-aarch64-libatomic.patch | 32 ++++ + .../840-armv4_pass_fix-v4bx_to_ld.patch | 28 ++++ + .../patches-16.x/850-use_shared_libgcc.patch | 54 +++++++ + .../patches-16.x/851-libgcc_no_compat.patch | 22 +++ + .../patches-16.x/870-ppc_no_crtsavres.patch | 11 ++ + .../gcc/patches-16.x/881-no_tm_section.patch | 11 ++ + .../gcc/patches-16.x/900-bad-mips16-crt.patch | 9 ++ + .../gcc/patches-16.x/910-mbsd_multi.patch | 146 ++++++++++++++++++ + .../920-specs_nonfatal_getenv.patch | 22 +++ + ...mpilation-when-making-cross-compiler.patch | 67 ++++++++ + .../970-macos_arm64-building-fix.patch | 45 ++++++ + 23 files changed, 673 insertions(+) + create mode 100644 toolchain/gcc/patches-16.x/002-case_insensitive.patch + create mode 100644 toolchain/gcc/patches-16.x/003-dont-choke-when-building-32bit-on-64bit.patch + create mode 100644 toolchain/gcc/patches-16.x/010-documentation.patch + create mode 100644 toolchain/gcc/patches-16.x/110-Fix-MIPS-PR-84790.patch + create mode 100644 toolchain/gcc/patches-16.x/230-musl_libssp.patch + create mode 100644 toolchain/gcc/patches-16.x/300-mips_Os_cpu_rtx_cost_model.patch + create mode 100644 toolchain/gcc/patches-16.x/800-arm_v5te_no_ldrd_strd.patch + create mode 100644 toolchain/gcc/patches-16.x/810-arm-softfloat-libgcc.patch + create mode 100644 toolchain/gcc/patches-16.x/820-libgcc_pic.patch + create mode 100644 toolchain/gcc/patches-16.x/830-aarch64-libatomic.patch + create mode 100644 toolchain/gcc/patches-16.x/840-armv4_pass_fix-v4bx_to_ld.patch + create mode 100644 toolchain/gcc/patches-16.x/850-use_shared_libgcc.patch + create mode 100644 toolchain/gcc/patches-16.x/851-libgcc_no_compat.patch + create mode 100644 toolchain/gcc/patches-16.x/870-ppc_no_crtsavres.patch + create mode 100644 toolchain/gcc/patches-16.x/881-no_tm_section.patch + create mode 100644 toolchain/gcc/patches-16.x/900-bad-mips16-crt.patch + create mode 100644 toolchain/gcc/patches-16.x/910-mbsd_multi.patch + create mode 100644 toolchain/gcc/patches-16.x/920-specs_nonfatal_getenv.patch + create mode 100644 toolchain/gcc/patches-16.x/960-gotools-fix-compilation-when-making-cross-compiler.patch + create mode 100644 toolchain/gcc/patches-16.x/970-macos_arm64-building-fix.patch + +diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in +index d296249..68c91c1 100644 +--- a/toolchain/gcc/Config.in ++++ b/toolchain/gcc/Config.in +@@ -17,6 +17,9 @@ choice + + config GCC_USE_VERSION_15 + bool "gcc 15.x" ++ ++ config GCC_USE_VERSION_16 ++ bool "gcc 16.x" + endchoice + + config GCC_USE_GRAPHITE +diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version +index 5960fe3..4f94ac7 100644 +--- a/toolchain/gcc/Config.version ++++ b/toolchain/gcc/Config.version +@@ -10,12 +10,17 @@ config GCC_VERSION_15 + default y if GCC_USE_VERSION_15 + bool + ++config GCC_VERSION_16 ++ default y if GCC_USE_VERSION_16 ++ bool ++ + config GCC_VERSION + string + default EXTERNAL_GCC_VERSION if EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN + default "12.3.0" if GCC_VERSION_12 + default "13.4.0" if GCC_VERSION_13 + default "15.2.0" if GCC_VERSION_15 ++ default "16.1.0" if GCC_VERSION_16 + default "14.3.0" + + config GCC_USE_DEFAULT_VERSION +diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk +index 8bd898e..9928e1f 100644 +--- a/toolchain/gcc/common.mk ++++ b/toolchain/gcc/common.mk +@@ -50,6 +50,10 @@ ifeq ($(PKG_VERSION),15.2.0) + PKG_HASH:=438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e + endif + ++ifeq ($(PKG_VERSION),16.1.0) ++ PKG_HASH:=50efb4d94c3397aff3b0d61a5abd748b4dd31d9d3f2ab7be05b171d36a510f79 ++endif ++ + PATCH_DIR=../patches-$(GCC_MAJOR_VERSION).x + + BUGURL=http://bugs.openwrt.org/ +diff --git a/toolchain/gcc/patches-16.x/002-case_insensitive.patch b/toolchain/gcc/patches-16.x/002-case_insensitive.patch +new file mode 100644 +index 0000000..409497e +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/002-case_insensitive.patch +@@ -0,0 +1,24 @@ ++commit 81cc26c706b2bc8c8c1eb1a322e5c5157900836e ++Author: Felix Fietkau ++Date: Sun Oct 19 21:45:51 2014 +0000 ++ ++ gcc: do not assume that the Mac OS X filesystem is case insensitive ++ ++ Signed-off-by: Felix Fietkau ++ ++ SVN-Revision: 42973 ++ ++--- a/include/filenames.h +++++ b/include/filenames.h ++@@ -44,11 +44,6 @@ extern "C" { ++ # define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c) ++ # define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f) ++ #else /* not DOSish */ ++-# if defined(__APPLE__) ++-# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM ++-# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 ++-# endif ++-# endif /* __APPLE__ */ ++ # define HAS_DRIVE_SPEC(f) (0) ++ # define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c) ++ # define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f) +diff --git a/toolchain/gcc/patches-16.x/003-dont-choke-when-building-32bit-on-64bit.patch b/toolchain/gcc/patches-16.x/003-dont-choke-when-building-32bit-on-64bit.patch +new file mode 100644 +index 0000000..c41f35e +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/003-dont-choke-when-building-32bit-on-64bit.patch +@@ -0,0 +1,13 @@ ++--- a/gcc/real.h +++++ b/gcc/real.h ++@@ -77,8 +77,10 @@ struct GTY(()) real_value { ++ + (REAL_VALUE_TYPE_SIZE%HOST_BITS_PER_WIDE_INT ? 1 : 0)) /* round up */ ++ ++ /* Verify the guess. */ +++#ifndef __LP64__ ++ extern char test_real_width ++ [sizeof (REAL_VALUE_TYPE) <= REAL_WIDTH * sizeof (HOST_WIDE_INT) ? 1 : -1]; +++#endif ++ ++ /* Calculate the format for CONST_DOUBLE. We need as many slots as ++ are necessary to overlay a REAL_VALUE_TYPE on them. This could be +diff --git a/toolchain/gcc/patches-16.x/010-documentation.patch b/toolchain/gcc/patches-16.x/010-documentation.patch +new file mode 100644 +index 0000000..34d9f41 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/010-documentation.patch +@@ -0,0 +1,35 @@ ++commit 098bd91f5eae625c7d2ee621e10930fc4434e5e2 ++Author: Luka Perkov ++Date: Tue Feb 26 16:16:33 2013 +0000 ++ ++ gcc: don't build documentation ++ ++ This closes #13039. ++ ++ Signed-off-by: Luka Perkov ++ ++ SVN-Revision: 35807 ++ ++--- a/gcc/Makefile.in +++++ b/gcc/Makefile.in ++@@ -3846,18 +3846,10 @@ doc/gcc.info: $(TEXI_GCC_FILES) ++ doc/gccint.info: $(TEXI_GCCINT_FILES) ++ doc/cppinternals.info: $(TEXI_CPPINT_FILES) ++ ++-doc/%.info: %.texi ++- if [ x$(BUILD_INFO) = xinfo ]; then \ ++- $(MAKEINFO) $(MAKEINFOFLAGS) -I . -I $(gcc_docdir) \ ++- -I $(gcc_docdir)/include -o $@ $<; \ ++- fi +++doc/%.info: ++ ++ # Duplicate entry to handle renaming of gccinstall.info ++-doc/gccinstall.info: $(TEXI_GCCINSTALL_FILES) ++- if [ x$(BUILD_INFO) = xinfo ]; then \ ++- $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \ ++- -I $(gcc_docdir)/include -o $@ $<; \ ++- fi +++doc/gccinstall.info: ++ ++ doc/cpp.dvi: $(TEXI_CPP_FILES) ++ doc/gcc.dvi: $(TEXI_GCC_FILES) +diff --git a/toolchain/gcc/patches-16.x/110-Fix-MIPS-PR-84790.patch b/toolchain/gcc/patches-16.x/110-Fix-MIPS-PR-84790.patch +new file mode 100644 +index 0000000..7d2b4a1 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/110-Fix-MIPS-PR-84790.patch +@@ -0,0 +1,20 @@ ++Fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84790. ++MIPS16 functions have a static assembler prologue which clobbers ++registers v0 and v1. Add these register clobbers to function call ++instructions. ++ ++--- a/gcc/config/mips/mips.cc +++++ b/gcc/config/mips/mips.cc ++@@ -3307,6 +3307,12 @@ mips_emit_call_insn (rtx pattern, rtx or ++ emit_insn (gen_update_got_version ()); ++ } ++ +++ if (TARGET_MIPS16 && TARGET_USE_GOT) +++ { +++ clobber_reg (&CALL_INSN_FUNCTION_USAGE (insn), MIPS16_PIC_TEMP); +++ clobber_reg (&CALL_INSN_FUNCTION_USAGE (insn), MIPS_PROLOGUE_TEMP (word_mode)); +++ } +++ ++ if (TARGET_MIPS16 ++ && TARGET_EXPLICIT_RELOCS ++ && TARGET_CALL_CLOBBERED_GP) +diff --git a/toolchain/gcc/patches-16.x/230-musl_libssp.patch b/toolchain/gcc/patches-16.x/230-musl_libssp.patch +new file mode 100644 +index 0000000..ec14131 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/230-musl_libssp.patch +@@ -0,0 +1,13 @@ ++--- a/gcc/gcc.cc +++++ b/gcc/gcc.cc ++@@ -1018,7 +1018,9 @@ proper position among the other output f ++ #endif ++ ++ #ifndef LINK_SSP_SPEC ++-#ifdef TARGET_LIBC_PROVIDES_SSP +++#if DEFAULT_LIBC == LIBC_MUSL +++#define LINK_SSP_SPEC "-lssp_nonshared" +++#elif defined(TARGET_LIBC_PROVIDES_SSP) ++ #define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \ ++ "|fstack-protector-strong|fstack-protector-explicit:}" ++ #else +diff --git a/toolchain/gcc/patches-16.x/300-mips_Os_cpu_rtx_cost_model.patch b/toolchain/gcc/patches-16.x/300-mips_Os_cpu_rtx_cost_model.patch +new file mode 100644 +index 0000000..1048cfd +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/300-mips_Os_cpu_rtx_cost_model.patch +@@ -0,0 +1,21 @@ ++commit ecf7671b769fe96f7b5134be442089f8bdba55d2 ++Author: Felix Fietkau ++Date: Thu Aug 4 20:29:45 2016 +0200 ++ ++gcc: add a patch to generate better code with Os on mips ++ ++Also happens to reduce compressed code size a bit ++ ++Signed-off-by: Felix Fietkau ++ ++--- a/gcc/config/mips/mips.cc +++++ b/gcc/config/mips/mips.cc ++@@ -20626,7 +20626,7 @@ mips_option_override (void) ++ flag_pcc_struct_return = 0; ++ ++ /* Decide which rtx_costs structure to use. */ ++- if (optimize_size) +++ if (0 && optimize_size) ++ mips_cost = &mips_rtx_cost_optimize_size; ++ else ++ mips_cost = &mips_rtx_cost_data[mips_tune]; +diff --git a/toolchain/gcc/patches-16.x/800-arm_v5te_no_ldrd_strd.patch b/toolchain/gcc/patches-16.x/800-arm_v5te_no_ldrd_strd.patch +new file mode 100644 +index 0000000..bae244c +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/800-arm_v5te_no_ldrd_strd.patch +@@ -0,0 +1,11 @@ ++--- a/gcc/config/arm/arm.h +++++ b/gcc/config/arm/arm.h ++@@ -158,7 +158,7 @@ emission of floating point pcs attribute ++ /* Thumb-1 only. */ ++ #define TARGET_THUMB1_ONLY (TARGET_THUMB1 && !arm_arch_notm) ++ ++-#define TARGET_LDRD (arm_arch5te && ARM_DOUBLEWORD_ALIGN \ +++#define TARGET_LDRD (arm_arch6 && ARM_DOUBLEWORD_ALIGN \ ++ && !TARGET_THUMB1) ++ ++ #define TARGET_CRC32 (arm_arch_crc) +diff --git a/toolchain/gcc/patches-16.x/810-arm-softfloat-libgcc.patch b/toolchain/gcc/patches-16.x/810-arm-softfloat-libgcc.patch +new file mode 100644 +index 0000000..5c9d86a +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/810-arm-softfloat-libgcc.patch +@@ -0,0 +1,33 @@ ++commit 8570c4be394cff7282f332f97da2ff569a927ddb ++Author: Imre Kaloz ++Date: Wed Feb 2 20:06:12 2011 +0000 ++ ++ fixup arm soft-float symbols ++ ++ SVN-Revision: 25325 ++ ++--- a/libgcc/config/arm/t-linux +++++ b/libgcc/config/arm/t-linux ++@@ -1,6 +1,10 @@ ++ LIB1ASMSRC = arm/lib1funcs.S ++ LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \ ++- _ctzsi2 _arm_addsubdf3 _arm_addsubsf3 +++ _ctzsi2 _arm_addsubdf3 _arm_addsubsf3 \ +++ _arm_negdf2 _arm_muldivdf3 _arm_cmpdf2 _arm_unorddf2 \ +++ _arm_fixdfsi _arm_fixunsdfsi _arm_truncdfsf2 \ +++ _arm_negsf2 _arm_muldivsf3 _arm_cmpsf2 _arm_unordsf2 \ +++ _arm_fixsfsi _arm_fixunssfsi ++ ++ # Just for these, we omit the frame pointer since it makes such a big ++ # difference. ++--- a/gcc/config/arm/linux-elf.h +++++ b/gcc/config/arm/linux-elf.h ++@@ -58,8 +58,6 @@ ++ %{shared:-lc} \ ++ %{!shared:%{profile:-lc_p}%{!profile:-lc}}" ++ ++-#define LIBGCC_SPEC "%{mfloat-abi=soft*:-lfloat} -lgcc" ++- ++ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2" ++ ++ #define LINUX_TARGET_LINK_SPEC "%{h*} \ +diff --git a/toolchain/gcc/patches-16.x/820-libgcc_pic.patch b/toolchain/gcc/patches-16.x/820-libgcc_pic.patch +new file mode 100644 +index 0000000..f6aa204 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/820-libgcc_pic.patch +@@ -0,0 +1,44 @@ ++commit c96312958c0621e72c9b32da5bc224ffe2161384 ++Author: Felix Fietkau ++Date: Mon Oct 19 23:26:09 2009 +0000 ++ ++ gcc: create a proper libgcc_pic.a static library for relinking (4.3.3+ for now, backport will follow) ++ ++ SVN-Revision: 18086 ++ ++--- a/libgcc/Makefile.in +++++ b/libgcc/Makefile.in ++@@ -946,11 +946,12 @@ $(libgcov-driver-objects): %$(objext): $ ++ ++ # Static libraries. ++ libgcc.a: $(libgcc-objects) +++libgcc_pic.a: $(libgcc-s-objects) ++ libgcov.a: $(libgcov-objects) ++ libunwind.a: $(libunwind-objects) ++ libgcc_eh.a: $(libgcc-eh-objects) ++ ++-libgcc.a libgcov.a libunwind.a libgcc_eh.a: +++libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a: ++ -rm -f $@ ++ ++ objects="$(objects)"; \ ++@@ -974,7 +975,7 @@ all: libunwind.a ++ endif ++ ++ ifeq ($(enable_shared),yes) ++-all: libgcc_eh.a libgcc_s$(SHLIB_EXT) +++all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT) ++ ifneq ($(LIBUNWIND),) ++ all: libunwind$(SHLIB_EXT) ++ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_EXT) ++@@ -1183,6 +1184,10 @@ install-shared: ++ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a ++ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a ++ +++ $(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/ +++ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a +++ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a +++ ++ $(subst @multilib_dir@,$(MULTIDIR),$(subst \ ++ @shlib_base_name@,libgcc_s,$(subst \ ++ @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL)))) +diff --git a/toolchain/gcc/patches-16.x/830-aarch64-libatomic.patch b/toolchain/gcc/patches-16.x/830-aarch64-libatomic.patch +new file mode 100644 +index 0000000..4779ef8 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/830-aarch64-libatomic.patch +@@ -0,0 +1,32 @@ ++libatomic: Do not enforce march on aarch64 ++ ++Inspired by The Yocto Project [1]. ++ ++[1] https://github.com/yoctoproject/poky/blob/51192a79f1717786dda42776f916c3d97ada7971/meta/recipes-devtools/gcc/gcc/0022-libatomic-Do-not-enforce-march-on-aarch64.patch ++ ++Signed-off-by: Konstantin Demin ++ ++ libatomic/Makefile.am | 1 - ++ libatomic/Makefile.in | 1 - ++ 2 files changed, 2 deletions(-) ++ ++--- a/libatomic/Makefile.am +++++ b/libatomic/Makefile.am ++@@ -133,7 +133,6 @@ libatomic_la_LIBADD = $(foreach s,$(SIZE ++ ## On a target-specific basis, include alternates to be selected by IFUNC. ++ if HAVE_IFUNC ++ if ARCH_AARCH64_LINUX ++-IFUNC_OPTIONS = -march=armv8-a+lse ++ libatomic_la_LIBADD += $(foreach s,$(SIZES),$(addsuffix _$(s)_1_.lo,$(SIZEOBJS))) ++ ++ endif ++--- a/libatomic/Makefile.in +++++ b/libatomic/Makefile.in ++@@ -470,7 +470,6 @@ libatomic_la_LDFLAGS = $(libatomic_versi ++ @PARTIAL_VXWORKS_FALSE@ _$(s)_.lo,$(SIZEOBJS))) $(am__append_1) \ ++ @PARTIAL_VXWORKS_FALSE@ $(am__append_2) $(am__append_3) \ ++ @PARTIAL_VXWORKS_FALSE@ $(am__append_4) $(am__append_5) ++-@ARCH_AARCH64_LINUX_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -march=armv8-a+lse ++ @ARCH_ARM_LINUX_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -march=armv7-a+fp -DHAVE_KERNEL64 ++ @ARCH_I386_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -march=i586 ++ @ARCH_LOONGARCH_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -mlsx|-mscq +diff --git a/toolchain/gcc/patches-16.x/840-armv4_pass_fix-v4bx_to_ld.patch b/toolchain/gcc/patches-16.x/840-armv4_pass_fix-v4bx_to_ld.patch +new file mode 100644 +index 0000000..e3cb616 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/840-armv4_pass_fix-v4bx_to_ld.patch +@@ -0,0 +1,28 @@ ++commit 7edc8ca5456d9743dd0075eb3cc5b04f4f24c8cc ++Author: Imre Kaloz ++Date: Wed Feb 2 19:34:36 2011 +0000 ++ ++ add armv4 fixup patches ++ ++ SVN-Revision: 25322 ++ ++ ++--- a/gcc/config/arm/linux-eabi.h +++++ b/gcc/config/arm/linux-eabi.h ++@@ -91,10 +91,15 @@ ++ #define MUSL_DYNAMIC_LINKER \ ++ "/lib/ld-musl-arm" MUSL_DYNAMIC_LINKER_E "%{mfloat-abi=hard:hf}%{mfdpic:-fdpic}.so.1" ++ +++/* For armv4 we pass --fix-v4bx to linker to support EABI */ +++#undef TARGET_FIX_V4BX_SPEC +++#define TARGET_FIX_V4BX_SPEC " %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*"\ +++ "|march=armv4|mcpu=fa526|mcpu=fa626:--fix-v4bx}" +++ ++ /* At this point, bpabi.h will have clobbered LINK_SPEC. We want to ++ use the GNU/Linux version, not the generic BPABI version. */ ++ #undef LINK_SPEC ++-#define LINK_SPEC EABI_LINK_SPEC \ +++#define LINK_SPEC EABI_LINK_SPEC TARGET_FIX_V4BX_SPEC \ ++ LINUX_OR_ANDROID_LD (LINUX_TARGET_LINK_SPEC, \ ++ LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC) ++ +diff --git a/toolchain/gcc/patches-16.x/850-use_shared_libgcc.patch b/toolchain/gcc/patches-16.x/850-use_shared_libgcc.patch +new file mode 100644 +index 0000000..210c790 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/850-use_shared_libgcc.patch +@@ -0,0 +1,54 @@ ++commit dcfc40358b5a3cae7320c17f8d1cebd5ad5540cd ++Author: Felix Fietkau ++Date: Sun Feb 12 20:25:47 2012 +0000 ++ ++ gcc 4.6: port over the missing patch 850-use_shared_libgcc.patch to prevent libgcc crap from leaking into every single binary ++ ++ SVN-Revision: 30486 ++--- a/gcc/config/arm/linux-eabi.h +++++ b/gcc/config/arm/linux-eabi.h ++@@ -132,10 +132,6 @@ ++ "%{Ofast|ffast-math|funsafe-math-optimizations:%{!shared:crtfastmath.o%s}} " \ ++ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_ENDFILE_SPEC, ANDROID_ENDFILE_SPEC) ++ ++-/* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we ++- do not use -lfloat. */ ++-#undef LIBGCC_SPEC ++- ++ /* Clear the instruction cache from `beg' to `end'. This is ++ implemented in lib1funcs.S, so ensure an error if this definition ++ is used. */ ++--- a/gcc/config/linux.h +++++ b/gcc/config/linux.h ++@@ -58,6 +58,10 @@ see the files COPYING3 and COPYING.RUNTI ++ builtin_assert ("system=posix"); \ ++ } while (0) ++ +++#ifndef LIBGCC_SPEC +++#define LIBGCC_SPEC "%{static|static-libgcc:-lgcc}%{!static:%{!static-libgcc:-lgcc_s}}" +++#endif +++ ++ /* Determine which dynamic linker to use depending on whether GLIBC or ++ uClibc or Bionic or musl is the default C library and whether ++ -muclibc or -mglibc or -mbionic or -mmusl has been passed to change ++--- a/libgcc/mkmap-symver.awk +++++ b/libgcc/mkmap-symver.awk ++@@ -136,5 +136,5 @@ function output(lib) { ++ else if (inherit[lib]) ++ printf("} %s;\n", inherit[lib]); ++ else ++- printf ("\n local:\n\t*;\n};\n"); +++ printf ("\n\t*;\n};\n"); ++ } ++--- a/gcc/config/rs6000/linux.h +++++ b/gcc/config/rs6000/linux.h ++@@ -70,6 +70,9 @@ ++ #undef CPP_OS_DEFAULT_SPEC ++ #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" ++ +++#undef LIBGCC_SPEC +++#define LIBGCC_SPEC "%{!static:%{!static-libgcc:-lgcc_s}} -lgcc" +++ ++ #undef LINK_SHLIB_SPEC ++ #define LINK_SHLIB_SPEC "%{shared:-shared} %{!shared: %{static:-static}} \ ++ %{static-pie:-static -pie --no-dynamic-linker -z text}" +diff --git a/toolchain/gcc/patches-16.x/851-libgcc_no_compat.patch b/toolchain/gcc/patches-16.x/851-libgcc_no_compat.patch +new file mode 100644 +index 0000000..d710e40 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/851-libgcc_no_compat.patch +@@ -0,0 +1,22 @@ ++commit 64661de100da1ec1061ef3e5e400285dce115e6b ++Author: Felix Fietkau ++Date: Sun May 10 13:16:35 2015 +0000 ++ ++ gcc: add some size optimization patches ++ ++ Signed-off-by: Felix Fietkau ++ ++ SVN-Revision: 45664 ++ ++--- a/libgcc/config/t-libunwind +++++ b/libgcc/config/t-libunwind ++@@ -2,8 +2,7 @@ ++ ++ HOST_LIBGCC2_CFLAGS += -DUSE_GAS_SYMVER ++ ++-LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \ ++- $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c +++LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c ++ LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c ++ ++ # Override the default value from t-slibgcc-elf-ver and mention -lunwind +diff --git a/toolchain/gcc/patches-16.x/870-ppc_no_crtsavres.patch b/toolchain/gcc/patches-16.x/870-ppc_no_crtsavres.patch +new file mode 100644 +index 0000000..0dca688 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/870-ppc_no_crtsavres.patch +@@ -0,0 +1,11 @@ ++--- a/gcc/config/rs6000/rs6000-logue.cc +++++ b/gcc/config/rs6000/rs6000-logue.cc ++@@ -344,7 +344,7 @@ rs6000_savres_strategy (rs6000_stack_t * ++ /* Define cutoff for using out-of-line functions to save registers. */ ++ if (DEFAULT_ABI == ABI_V4 || TARGET_ELF) ++ { ++- if (!optimize_size) +++ if (1) ++ { ++ strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS; ++ strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS; +diff --git a/toolchain/gcc/patches-16.x/881-no_tm_section.patch b/toolchain/gcc/patches-16.x/881-no_tm_section.patch +new file mode 100644 +index 0000000..2029910 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/881-no_tm_section.patch +@@ -0,0 +1,11 @@ ++--- a/libgcc/crtstuff.c +++++ b/libgcc/crtstuff.c ++@@ -152,7 +152,7 @@ call_ ## FUNC (void) \ ++ #endif ++ ++ #if !defined(USE_TM_CLONE_REGISTRY) && defined(OBJECT_FORMAT_ELF) ++-# define USE_TM_CLONE_REGISTRY 1 +++# define USE_TM_CLONE_REGISTRY 0 ++ #elif !defined(USE_TM_CLONE_REGISTRY) ++ # define USE_TM_CLONE_REGISTRY 0 ++ #endif +diff --git a/toolchain/gcc/patches-16.x/900-bad-mips16-crt.patch b/toolchain/gcc/patches-16.x/900-bad-mips16-crt.patch +new file mode 100644 +index 0000000..b355545 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/900-bad-mips16-crt.patch +@@ -0,0 +1,9 @@ ++--- a/libgcc/config/mips/t-mips16 +++++ b/libgcc/config/mips/t-mips16 ++@@ -42,3 +42,6 @@ SYNC_CFLAGS = -mno-mips16 ++ ++ # Version these symbols if building libgcc.so. ++ SHLIB_MAPFILES += $(srcdir)/config/mips/libgcc-mips16.ver +++ +++CRTSTUFF_T_CFLAGS += -mno-mips16 +++CRTSTUFF_T_CFLAGS_S += -mno-mips16 +diff --git a/toolchain/gcc/patches-16.x/910-mbsd_multi.patch b/toolchain/gcc/patches-16.x/910-mbsd_multi.patch +new file mode 100644 +index 0000000..23cd6ef +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/910-mbsd_multi.patch +@@ -0,0 +1,146 @@ ++commit 99368862e44740ff4fd33760893f04e14f9dbdf1 ++Author: Felix Fietkau ++Date: Tue Jul 31 00:52:27 2007 +0000 ++ ++ Port the mbsd_multi patch from freewrt, which adds -fhonour-copts. This will emit warnings in packages that don't use our target cflags properly ++ ++ SVN-Revision: 8256 ++ ++ This patch brings over a feature from MirBSD: ++ * -fhonour-copts ++ If this option is not given, it's warned (depending ++ on environment variables). This is to catch errors ++ of misbuilt packages which override CFLAGS themselves. ++ ++ This patch was authored by Thorsten Glaser ++ with copyright assignment to the FSF in effect. ++ ++--- a/gcc/c-family/c-opts.cc +++++ b/gcc/c-family/c-opts.cc ++@@ -110,6 +110,9 @@ static size_t include_cursor; ++ /* Whether any standard preincluded header has been preincluded. */ ++ static bool done_preinclude; ++ +++/* Check if a port honours COPTS. */ +++static int honour_copts = 0; +++ ++ static void handle_OPT_d (const char *); ++ static void set_std_cxx98 (int); ++ static void set_std_cxx11 (int); ++@@ -503,6 +506,12 @@ c_common_handle_option (size_t scode, co ++ flag_no_builtin = !value; ++ break; ++ +++ case OPT_fhonour_copts: +++ if (c_language == clk_c) { +++ honour_copts++; +++ } +++ break; +++ ++ case OPT_fconstant_string_class_: ++ constant_string_class_name = arg; ++ break; ++@@ -1410,6 +1419,47 @@ c_common_init (void) ++ return false; ++ } ++ +++ if (c_language == clk_c) { +++ char *ev = getenv ("GCC_HONOUR_COPTS"); +++ int evv; +++ if (ev == NULL) +++ evv = -1; +++ else if ((*ev == '0') || (*ev == '\0')) +++ evv = 0; +++ else if (*ev == '1') +++ evv = 1; +++ else if (*ev == '2') +++ evv = 2; +++ else if (*ev == 's') +++ evv = -1; +++ else { +++ warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1"); +++ evv = 1; /* maybe depend this on something like MIRBSD_NATIVE? */ +++ } +++ if (evv == 1) { +++ if (honour_copts == 0) { +++ error ("someone does not honour COPTS at all in lenient mode"); +++ return false; +++ } else if (honour_copts != 1) { +++ warning (0, "someone does not honour COPTS correctly, passed %d times", +++ honour_copts); +++ } +++ } else if (evv == 2) { +++ if (honour_copts == 0) { +++ error ("someone does not honour COPTS at all in strict mode"); +++ return false; +++ } else if (honour_copts != 1) { +++ error ("someone does not honour COPTS correctly, passed %d times", +++ honour_copts); +++ return false; +++ } +++ } else if (evv == 0) { +++ if (honour_copts != 1) +++ inform (UNKNOWN_LOCATION, "someone does not honour COPTS correctly, passed %d times", +++ honour_copts); +++ } +++ } +++ ++ return true; ++ } ++ ++--- a/gcc/c-family/c.opt +++++ b/gcc/c-family/c.opt ++@@ -2080,6 +2080,9 @@ C++ ObjC++ Optimization Alias(fexception ++ fhonor-std ++ C++ ObjC++ WarnRemoved ++ +++fhonour-copts +++C ObjC C++ ObjC++ RejectNegative +++ ++ fhosted ++ C ObjC ++ Assume normal C execution environment. ++--- a/gcc/common.opt +++++ b/gcc/common.opt ++@@ -2004,6 +2004,9 @@ Enum(hardcfr_check_noreturn_calls) Strin ++ EnumValue ++ Enum(hardcfr_check_noreturn_calls) String(always) Value(HCFRNR_ALWAYS) ++ +++fhonour-copts +++Common RejectNegative +++ ++ ; Nonzero means do not emit .ident assembler directives and ignore ++ ; `#ident' preprocessor directives. ++ fident ++--- a/gcc/doc/invoke.texi +++++ b/gcc/doc/invoke.texi ++@@ -11476,6 +11476,17 @@ This option is only supported for C and ++ ++ This warning is upgraded to an error by @option{-pedantic-errors}. ++ +++@item -fhonour-copts +++@opindex fhonour-copts +++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not +++given at least once, and warn if it is given more than once. +++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not +++given exactly once. +++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option +++is not given exactly once. +++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}. +++This flag and environment variable only affect the C language. +++ ++ @opindex Wstack-protector ++ @opindex Wno-stack-protector ++ @item -Wstack-protector ++--- a/gcc/opts.cc +++++ b/gcc/opts.cc ++@@ -2927,6 +2927,9 @@ common_handle_option (struct gcc_options ++ add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg); ++ break; ++ +++ case OPT_fhonour_copts: +++ break; +++ ++ case OPT_Werror: ++ dc->set_warning_as_error_requested (value); ++ break; +diff --git a/toolchain/gcc/patches-16.x/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches-16.x/920-specs_nonfatal_getenv.patch +new file mode 100644 +index 0000000..78dd5e0 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/920-specs_nonfatal_getenv.patch +@@ -0,0 +1,22 @@ ++Author: Jo-Philipp Wich ++Date: Sat Apr 21 03:02:39 2012 +0000 ++ ++ gcc: add patch to make the getenv() spec function nonfatal if requested environment variable is unset ++ ++ SVN-Revision: 31390 ++ ++--- a/gcc/gcc.cc +++++ b/gcc/gcc.cc ++@@ -10501,8 +10501,10 @@ getenv_spec_function (int argc, const ch ++ } ++ ++ if (!value) ++- fatal_error (input_location, ++- "environment variable %qs not defined", varname); +++ { +++ warning (input_location, "environment variable %qs not defined", varname); +++ value = ""; +++ } ++ ++ /* We have to escape every character of the environment variable so ++ they are not interpreted as active spec characters. A +diff --git a/toolchain/gcc/patches-16.x/960-gotools-fix-compilation-when-making-cross-compiler.patch b/toolchain/gcc/patches-16.x/960-gotools-fix-compilation-when-making-cross-compiler.patch +new file mode 100644 +index 0000000..b1d7576 +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/960-gotools-fix-compilation-when-making-cross-compiler.patch +@@ -0,0 +1,67 @@ ++From dda6b050cd74a352670787a294596a9c56c21327 Mon Sep 17 00:00:00 2001 ++From: Yousong Zhou ++Date: Fri, 4 May 2018 18:20:53 +0800 ++Subject: [PATCH] gotools: fix compilation when making cross compiler ++ ++libgo is "the runtime support library for the Go programming language. ++This library is intended for use with the Go frontend." ++ ++gccgo will link target files with libgo.so which depends on libgcc_s.so.1, but ++the linker will complain that it cannot find it. That's because shared libgcc ++is not present in the install directory yet. libgo.so was made without problem ++because gcc will emit -lgcc_s when compiled with -shared option. When gotools ++were being made, it was supplied with -static-libgcc thus no link option was ++provided. Check LIBGO in gcc/go/gcc-spec.c for how gccgo make a builtin spec ++for linking with libgo.so ++ ++- GccgoCrossCompilation, https://github.com/golang/go/wiki/GccgoCrossCompilation ++- Cross-building instructions, http://www.eglibc.org/archives/patches/msg00078.html ++ ++When 3-pass GCC compilation is used, shared libgcc runtime libraries will be ++available after gcc pass2 completed and will meet the gotools link requirement ++at gcc pass3 ++--- ++ gotools/Makefile.am | 4 +++- ++ gotools/Makefile.in | 4 +++- ++ 2 files changed, 6 insertions(+), 2 deletions(-) ++ ++--- a/gotools/Makefile.am +++++ b/gotools/Makefile.am ++@@ -26,6 +26,7 @@ PWD_COMMAND = $${PWDCMD-pwd} ++ STAMP = echo timestamp > ++ ++ libgodir = ../$(target_noncanonical)/libgo +++libgccdir = ../$(target_noncanonical)/libgcc ++ LIBGODEP = $(libgodir)/libgo.la ++ ++ LIBGOTOOL = $(libgodir)/libgotool.a ++@@ -41,7 +42,8 @@ GOCFLAGS = $(CFLAGS_FOR_TARGET) ++ GOCOMPILE = $(GOCOMPILER) $(GOCFLAGS) ++ ++ AM_GOCFLAGS = -I $(libgodir) ++-AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs +++AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs \ +++ -L $(libgccdir) -L $(libgccdir)/.libs -lgcc_s ++ GOLINK = $(GOCOMPILER) $(GOCFLAGS) $(AM_GOCFLAGS) $(LDFLAGS) $(AM_LDFLAGS) -o $@ ++ ++ libgosrcdir = $(srcdir)/../libgo/go ++--- a/gotools/Makefile.in +++++ b/gotools/Makefile.in ++@@ -337,6 +337,7 @@ mkinstalldirs = $(SHELL) $(toplevel_srcd ++ PWD_COMMAND = $${PWDCMD-pwd} ++ STAMP = echo timestamp > ++ libgodir = ../$(target_noncanonical)/libgo +++libgccdir = ../$(target_noncanonical)/libgcc ++ LIBGODEP = $(libgodir)/libgo.la ++ LIBGOTOOL = $(libgodir)/libgotool.a ++ @NATIVE_FALSE@GOCOMPILER = $(GOC) ++@@ -346,7 +347,8 @@ LIBGOTOOL = $(libgodir)/libgotool.a ++ GOCFLAGS = $(CFLAGS_FOR_TARGET) ++ GOCOMPILE = $(GOCOMPILER) $(GOCFLAGS) ++ AM_GOCFLAGS = -I $(libgodir) ++-AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs +++AM_LDFLAGS = -L $(libgodir) -L $(libgodir)/.libs \ +++ -L $(libgccdir) -L $(libgccdir)/.libs -lgcc_s ++ GOLINK = $(GOCOMPILER) $(GOCFLAGS) $(AM_GOCFLAGS) $(LDFLAGS) $(AM_LDFLAGS) -o $@ ++ libgosrcdir = $(srcdir)/../libgo/go ++ cmdsrcdir = $(libgosrcdir)/cmd +diff --git a/toolchain/gcc/patches-16.x/970-macos_arm64-building-fix.patch b/toolchain/gcc/patches-16.x/970-macos_arm64-building-fix.patch +new file mode 100644 +index 0000000..73bb1ad +--- /dev/null ++++ b/toolchain/gcc/patches-16.x/970-macos_arm64-building-fix.patch +@@ -0,0 +1,45 @@ ++commit 9c6e71079b46ad5433165feaa2001450f2017b56 ++Author: Przemysław Buczkowski ++Date: Mon Aug 16 13:16:21 2021 +0100 ++ ++ GCC: Patch for Apple Silicon compatibility ++ ++ This patch fixes a linker error occuring when compiling ++ the cross-compiler on macOS and ARM64 architecture. ++ ++ Adapted from: ++ https://github.com/richfelker/musl-cross-make/issues/116#issuecomment-823612404 ++ ++ Change-Id: Ia3ee98a163bbb62689f42e2da83a5ef36beb0913 ++ Reviewed-on: https://review.haiku-os.org/c/buildtools/+/4329 ++ Reviewed-by: John Scipione ++ Reviewed-by: Adrien Destugues ++ ++--- a/gcc/config/aarch64/aarch64.h +++++ b/gcc/config/aarch64/aarch64.h ++@@ -1531,7 +1531,7 @@ extern enum aarch64_code_model aarch64_c ++ ++ /* Extra specs when building a native AArch64-hosted compiler. ++ Option rewriting rules based on host system. */ ++-#if defined(__aarch64__) +++#if defined(__aarch64__) && ! defined(__APPLE__) ++ extern const char *host_detect_local_cpu (int argc, const char **argv); ++ #define HAVE_LOCAL_CPU_DETECT ++ # define EXTRA_SPEC_FUNCTIONS \ ++--- a/gcc/config/host-darwin.cc +++++ b/gcc/config/host-darwin.cc ++@@ -23,6 +23,8 @@ ++ #include "options.h" ++ #include "diagnostic-core.h" ++ #include "config/host-darwin.h" +++#include "hosthooks.h" +++#include "hosthooks-def.h" ++ #include ++ ++ /* For Darwin (macOS only) platforms, without ASLR (PIE) enabled on the ++@@ -181,3 +183,5 @@ darwin_gt_pch_use_address (void *&addr, ++ ++ return 1; ++ } +++ +++const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; +-- +2.47.3 + diff --git a/openwrt/patch/generic-25.12/0014-tools-mold-update-to-2.41.0.patch b/openwrt/patch/generic-25.12/0014-tools-mold-update-to-2.41.0.patch new file mode 100644 index 000000000..fd704df85 --- /dev/null +++ b/openwrt/patch/generic-25.12/0014-tools-mold-update-to-2.41.0.patch @@ -0,0 +1,33 @@ +From 39c5582d99c6c52d55dadf060c2045b378320530 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Mon, 11 May 2026 15:41:56 +0800 +Subject: [PATCH 2/2] tools: mold: update to 2.41.0 + +Signed-off-by: sbwml +--- + tools/mold/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/mold/Makefile b/tools/mold/Makefile +index 8c3e33f..ff1f5c7 100644 +--- a/tools/mold/Makefile ++++ b/tools/mold/Makefile +@@ -3,13 +3,13 @@ + include $(TOPDIR)/rules.mk + + PKG_NAME:=mold +-PKG_VERSION:=2.40.4 ++PKG_VERSION:=2.41.0 + PKG_RELEASE:=1 + + PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz + PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz + PKG_SOURCE_URL:=https://github.com/rui314/mold/archive/refs/tags +-PKG_HASH:=69414c702ec1084e1fa8ca16da24f167f549e5e11e9ecd5d70a8dcda6f08c249 ++PKG_HASH:=0a61abac85d818437b425df856822e9d6e9982baeae5a93bcb02fe6c0060c61a + + include $(INCLUDE_DIR)/host-build.mk + include $(INCLUDE_DIR)/cmake.mk +-- +2.47.3 + diff --git a/openwrt/patch/generic-25.12/0015-tools-build-lz4-by-default.patch b/openwrt/patch/generic-25.12/0015-tools-build-lz4-by-default.patch new file mode 100644 index 000000000..9b9e3f94c --- /dev/null +++ b/openwrt/patch/generic-25.12/0015-tools-build-lz4-by-default.patch @@ -0,0 +1,52 @@ +From be2b8b3b012a549f8a0fc3d1c4fe84644ee65cf0 Mon Sep 17 00:00:00 2001 +From: sbwml +Date: Mon, 11 May 2026 18:10:42 +0800 +Subject: [PATCH] tools: build lz4 by default + +Signed-off-by: sbwml +--- + tools/Makefile | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/tools/Makefile b/tools/Makefile +index 42b1265..7719ca6 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -23,9 +23,6 @@ endif + ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_BZIP2),) + BUILD_BZIP2_TOOLS = y + endif +-ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZ4),) +- BUILD_LZ4_TOOLS = y +-endif + ifneq ($(CONFIG_SDK)$(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),) + BUILD_LZO_TOOLS = y + endif +@@ -50,6 +47,7 @@ tools-y += gengetopt + tools-y += gnulib + tools-y += libressl + tools-y += libtool ++tools-y += lz4 + tools-y += lzma + tools-y += m4 + tools-y += make-ext4fs +@@ -76,7 +74,6 @@ tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS),y) += liblzo + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_B43_TOOLS),y) += b43-tools + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_BZIP2_TOOLS),y) += bzip2 + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_ISL),y) += isl +-tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_LZ4_TOOLS),y) += lz4 + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_LZO_TOOLS),y) += lzop + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(BUILD_TOOLCHAIN),y) += gmp mpc mpfr + tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_TARGET_apm821xx)$(CONFIG_TARGET_gemini),y) += genext2fs +@@ -133,7 +130,7 @@ $(curdir)/pkgconf/compile := $(curdir)/meson/compile + $(curdir)/quilt/compile := $(curdir)/autoconf/compile $(curdir)/findutils/compile + $(curdir)/sdcc/compile := $(curdir)/bison/compile + $(curdir)/squashfs3-lzma/compile := $(curdir)/lzma-old/compile +-$(curdir)/squashfs4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile ++$(curdir)/squashfs4/compile := $(curdir)/lz4/compile $(curdir)/xz/compile $(curdir)/zlib/compile + $(curdir)/util-linux/compile := $(curdir)/bison/compile $(curdir)/meson/compile + $(curdir)/yafut/compile := $(curdir)/cmake/compile + +-- +2.43.5 + diff --git a/openwrt/patch/packages-patches_gcc16/elfutils/900-fix-gcc16-null-dereference-with-lto.patch b/openwrt/patch/packages-patches_gcc16/elfutils/900-fix-gcc16-null-dereference-with-lto.patch new file mode 100644 index 000000000..95383f319 --- /dev/null +++ b/openwrt/patch/packages-patches_gcc16/elfutils/900-fix-gcc16-null-dereference-with-lto.patch @@ -0,0 +1,11 @@ +--- a/libelf/elf32_updatenull.c ++++ b/libelf/elf32_updatenull.c +@@ -133,6 +133,8 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (E + int ehdr_flags = 0; + + ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf); ++ if (ehdr == NULL) ++ return -1; + + /* Set the default values. */ + if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0) diff --git a/openwrt/patch/packages-patches_gcc16/libwebsockets/900-fix-build-for-gcc-16.patch b/openwrt/patch/packages-patches_gcc16/libwebsockets/900-fix-build-for-gcc-16.patch new file mode 100644 index 000000000..6d99f8e4d --- /dev/null +++ b/openwrt/patch/packages-patches_gcc16/libwebsockets/900-fix-build-for-gcc-16.patch @@ -0,0 +1,29 @@ +--- a/plugins/deaddrop/protocol_lws_deaddrop.c ++++ b/plugins/deaddrop/protocol_lws_deaddrop.c +@@ -135,7 +135,7 @@ scan_upload_dir(struct vhd_deaddrop *vhd + char filepath[256], subdir[3][128], *p; + struct lwsac *lwsac_head = NULL; + lws_list_ptr sorted_head = NULL; +- int i, sp = 0, found = 0; ++ int i, sp = 0; + struct dir_entry *dire; + struct dirent *de; + size_t initial, m; +@@ -224,8 +224,6 @@ scan_upload_dir(struct vhd_deaddrop *vhd + lws_strncpy(dire->user, subdir[1], sizeof(dire->user)); + #endif + +- found++; +- + memcpy(&dire[1], filepath + initial, m); + + lws_list_ptr_insert(&sorted_head, &dire->next, de_mtime_sort); +@@ -244,8 +242,6 @@ scan_upload_dir(struct vhd_deaddrop *vhd + + vhd->filelist_version++; + +- lwsl_info("%s: found %d\n", __func__, found); +- + lws_start_foreach_llp(struct pss_deaddrop **, ppss, vhd->pss_head) { + start_sending_dir(*ppss); + lws_callback_on_writable((*ppss)->wsi); diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index 5b1cfb5b7..b86798aee 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -26,6 +26,9 @@ curl -s $mirror/openwrt/patch/generic-25.12/0009-tools-squashfs4-enable-lz4-zstd curl -s $mirror/openwrt/patch/generic-25.12/0010-kernel-add-PREEMPT_RT-support-for-aarch64-x86_64.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-25.12/0011-config-include-image-add-support-for-squashfs-zstd-c.patch | patch -p1 curl -s $mirror/openwrt/patch/generic-25.12/0012-include-kernel-Always-collect-module-symvers.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0013-toolchain-gcc-add-support-for-GCC-16.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0014-tools-mold-update-to-2.41.0.patch | patch -p1 +curl -s $mirror/openwrt/patch/generic-25.12/0015-tools-build-lz4-by-default.patch | patch -p1 # add source mirror #sed -i '/"@OPENWRT": \[/a\\t\t"https://sources-cdn-openwrt.cooluc.com",' scripts/projectsmirrors.json diff --git a/openwrt/scripts/04-fix_kmod.sh b/openwrt/scripts/04-fix_kmod.sh index f9399906f..959747b00 100644 --- a/openwrt/scripts/04-fix_kmod.sh +++ b/openwrt/scripts/04-fix_kmod.sh @@ -90,7 +90,4 @@ if [ "$KERNEL_CLANG_LTO" = "y" ]; then # coova-chilli module rm -rf feeds/packages/net/coova-chilli git clone https://$github/sbwml/kmod_packages_net_coova-chilli feeds/packages/net/coova-chilli -else - # coova-chilli - fix gcc 15 c23 - [ "$USE_GCC15" = y ] && sed -i '/TARGET_CFLAGS/s/$/ -std=gnu17/' feeds/packages/net/coova-chilli/Makefile fi diff --git a/openwrt/scripts/05-fix-source.sh b/openwrt/scripts/05-fix-source.sh index 242db50e2..1e6c93967 100644 --- a/openwrt/scripts/05-fix-source.sh +++ b/openwrt/scripts/05-fix-source.sh @@ -40,59 +40,18 @@ curl -s $mirror/openwrt/patch/packages-patches/kselftests-bpf/Makefile > package ####################################### # fix gcc-15.0.1 gnu17 -if [ "$USE_GCC15" = y ]; then - # libtirpc - sed -i '/TARGET_CFLAGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/libtirpc/Makefile - # libsepol - sed -i '/HOST_MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' package/libs/libsepol/Makefile - # tree - sed -i '/MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/tree/Makefile - # gdbm - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/gdbm/Makefile - # libical - sed -i '/CMAKE_OPTIONS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/libical/Makefile - # libconfig - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' package/feeds/packages/libconfig/Makefile - # lsof - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/lsof/Makefile - # screen - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/screen/Makefile - # ppp - sed -i '/CONFIGURE_VARS/i \\nTARGET_CFLAGS += -std=gnu17\n' package/network/services/ppp/Makefile - # vim - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/vim/Makefile - # mtd - sed -i '/target=/i TARGET_CFLAGS += -std=gnu17\n' package/system/mtd/Makefile - # libselinux - sed -i '/MAKE_FLAGS/i TARGET_CFLAGS += -std=gnu17\n' package/libs/libselinux/Makefile - # avahi - sed -i '/TARGET_CFLAGS +=/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/avahi/Makefile +if [ "$USE_GCC15" = y ] || [ "$USE_GCC16" = y ]; then # xl2tpd sed -i '/ifneq (0,0)/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/xl2tpd/Makefile - # bluez - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/bluez/Makefile - # e2fsprogs - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' package/utils/e2fsprogs/Makefile - # f2fs-tools - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' package/utils/f2fs-tools/Makefile - # krb5 - sed -i '/CONFIGURE_VARS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/krb5/Makefile - # parted - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/parted/Makefile - # iperf3 - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/iperf3/Makefile - # db - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/libs/db/Makefile - # python3 - sed -i '/TARGET_CONFIGURE_OPTS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/lang/python/python3/Makefile - # uwsgi - sed -i '/MAKE_VARS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/uwsgi/Makefile - # perl - sed -i '/Target perl/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/lang/perl/Makefile - # rsync - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/net/rsync/Makefile - # shine - sed -i '/Build\/InstallDev/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/sound/shine/Makefile - # jq - sed -i '/CONFIGURE_ARGS/i TARGET_CFLAGS += -std=gnu17\n' feeds/packages/utils/jq/Makefile +fi + +# fix gcc-16.1.0 +if [ "$USE_GCC16" = y ]; then + # elfutils lto + curl -s $mirror/openwrt/patch/packages-patches_gcc16/elfutils/900-fix-gcc16-null-dereference-with-lto.patch > package/libs/elfutils/patches/900-fix-gcc16-null-dereference-with-lto.patch + # libwebsockets + mkdir -p feeds/packages/libs/libwebsockets/patches + curl -s $mirror/openwrt/patch/packages-patches_gcc16/libwebsockets/900-fix-build-for-gcc-16.patch > feeds/packages/libs/libwebsockets/patches/900-fix-build-for-gcc-16.patch + # bash + sed -i "/PKG_INSTALL:=/i\PKG_BUILD_FLAGS:=no-lto" feeds/packages/utils/bash/Makefile fi From 8fb4f1f1d80f84f282741341584805830c329a1d Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 14 May 2026 03:41:56 +0800 Subject: [PATCH 410/425] build.sh: add `luci-app-oaf` to code3 APK source Signed-off-by: sbwml --- openwrt/25-config-common | 5 ----- openwrt/25-config-minimal-common | 3 --- openwrt/25-config-std-common | 5 ----- openwrt/build.sh | 21 +++++++++++++-------- openwrt/generic/config-build-only | 7 +++++++ 5 files changed, 20 insertions(+), 21 deletions(-) create mode 100644 openwrt/generic/config-build-only diff --git a/openwrt/25-config-common b/openwrt/25-config-common index ba2c45539..27196660b 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -13,9 +13,6 @@ CONFIG_LIBCURL_OPENSSL=y ### Firewall CONFIG_PACKAGE_nat6=y -# Natflow -CONFIG_PACKAGE_natflow=m - ### Zram CONFIG_PACKAGE_zram-swap=y CONFIG_ZRAM_DEF_COMP_LZ4=y @@ -77,7 +74,6 @@ CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y CONFIG_PACKAGE_luci-app-aurora-config=y CONFIG_PACKAGE_luci-app-autoreboot=y -# CONFIG_PACKAGE_luci-app-bandix is not set CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y @@ -90,7 +86,6 @@ CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y -# CONFIG_PACKAGE_luci-app-oaf is not set CONFIG_PACKAGE_luci-app-openlist2=y CONFIG_PACKAGE_luci-app-qbittorrent=y CONFIG_PACKAGE_luci-app-ramfree=y diff --git a/openwrt/25-config-minimal-common b/openwrt/25-config-minimal-common index ce81c8c6f..293b4a3c8 100644 --- a/openwrt/25-config-minimal-common +++ b/openwrt/25-config-minimal-common @@ -13,9 +13,6 @@ CONFIG_LIBCURL_OPENSSL=y ### Firewall CONFIG_PACKAGE_nat6=y -# Natflow -CONFIG_PACKAGE_natflow=m - ### Zram CONFIG_PACKAGE_zram-swap=y CONFIG_ZRAM_DEF_COMP_LZ4=y diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index b5f0bc705..95a5c2fb1 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -13,9 +13,6 @@ CONFIG_LIBCURL_OPENSSL=y ### Firewall CONFIG_PACKAGE_nat6=y -# Natflow -CONFIG_PACKAGE_natflow=m - ### Zram CONFIG_PACKAGE_zram-swap=y CONFIG_ZRAM_DEF_COMP_LZ4=y @@ -66,7 +63,6 @@ CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y CONFIG_PACKAGE_luci-app-aurora-config=y CONFIG_PACKAGE_luci-app-autoreboot=y -# CONFIG_PACKAGE_luci-app-bandix is not set CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y @@ -77,7 +73,6 @@ CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y -# CONFIG_PACKAGE_luci-app-oaf is not set CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-socat=y CONFIG_PACKAGE_luci-app-sqm=y diff --git a/openwrt/build.sh b/openwrt/build.sh index 65fbcf330..4667c1b60 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -211,14 +211,11 @@ print_status "ENABLE_ISTORE" "$ENABLE_ISTORE" print_status "KERNEL_CLANG_LTO" "$KERNEL_CLANG_LTO" "$GREEN_COLOR" "$YELLOW_COLOR" "\n" # clean old files -rm -rf openwrt master +rm -rf openwrt # openwrt - releases [ "$(whoami)" = "runner" ] && group "source code" git clone --depth=1 https://$code_mirror/openwrt/openwrt -b $branch - -# immortalwrt master -git clone https://$github/immortalwrt/packages master/immortalwrt_packages --depth=1 [ "$(whoami)" = "runner" ] && endgroup if [ -d openwrt ]; then @@ -302,7 +299,6 @@ find feeds -type f -name "*.orig" -exec rm -f {} \; [ "$(whoami)" = "runner" ] && endgroup rm -f 0*-*.sh 10-custom.sh -rm -rf ../master # Load devices Config if [ "$platform" = "x86_64" ]; then @@ -418,6 +414,9 @@ fi sed -i '/qbittorrent/d' .config } +# add to core +[ "$OPENWRT_CORE" = "y" ] && curl -s $mirror/openwrt/generic/config-build-only >> .config + # Toolchain Cache if [ "$BUILD_FAST" = "y" ]; then [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl @@ -484,12 +483,14 @@ if [ "$platform" = "x86_64" ]; then cp -a bin/targets/x86/*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* cp -a bin/packages/x86_64/base/rtl88*a-firmware*.apk $kmodpkg_name/ || true - cp -a bin/packages/x86_64/base/natflow*.apk $kmodpkg_name/ || true [ "$OPENWRT_CORE" = "y" ] && { cp -a bin/packages/x86_64/base/*3ginfo*.apk $kmodpkg_name/ || true cp -a bin/packages/x86_64/base/*modemband*.apk $kmodpkg_name/ || true cp -a bin/packages/x86_64/base/*sms-tool*.apk $kmodpkg_name/ || true cp -a bin/packages/x86_64/base/*quectel*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/appfilter*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/luci-app-oaf*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/x86_64/base/*dpdk*.apk $kmodpkg_name/ || true @@ -534,12 +535,14 @@ elif [ "$platform" = "armv8" ]; then cp -a bin/targets/armsr/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* cp -a bin/packages/aarch64_generic/base/rtl88*a-firmware*.apk $kmodpkg_name/ || true - cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true [ "$OPENWRT_CORE" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*3ginfo*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*modemband*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*sms-tool*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*quectel*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/appfilter*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/luci-app-oaf*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.apk $kmodpkg_name/ || true @@ -579,12 +582,14 @@ else cp -a bin/targets/rockchip/armv8*/packages $kmodpkg_name rm -f $kmodpkg_name/Packages* cp -a bin/packages/aarch64_generic/base/rtl88*-firmware*.apk $kmodpkg_name/ || true - cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true [ "$OPENWRT_CORE" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*3ginfo*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*modemband*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*sms-tool*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/*quectel*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/appfilter*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/luci-app-oaf*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.apk $kmodpkg_name/ || true diff --git a/openwrt/generic/config-build-only b/openwrt/generic/config-build-only new file mode 100644 index 000000000..c2586d6a8 --- /dev/null +++ b/openwrt/generic/config-build-only @@ -0,0 +1,7 @@ + +# Natflow +CONFIG_PACKAGE_natflow=m + +# OAF +CONFIG_PACKAGE_luci-app-oaf=m +CONFIG_PACKAGE_appfilter=m From 4360c54e0ecf9e3288a9de22289f33cdfbf1121c Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 14 May 2026 15:09:50 +0800 Subject: [PATCH 411/425] ci: update snapshot tag name Signed-off-by: sbwml --- .github/workflows/build-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 2249388aa..a827a2bee 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -21,7 +21,7 @@ on: type: choice options: - 'release' - - 'snapshot-24.10' + - 'snapshot-25.12' ccache: description: 'Enable ccache (Use Cache to speed up next build)' type: boolean @@ -137,7 +137,7 @@ jobs: if [ "${{ github.event.inputs.version }}" = release ]; then tags=OpenWrt-$(git describe --abbrev=0 --tags) else - tags=snapshot-24.10-$(git log -n 1 --date=format:"%Y%m%d" --format="%cd")-$(git log --pretty=format:"%h" -1) + tags=snapshot-25.12-$(git log -n 1 --date=format:"%Y%m%d" --format="%cd")-$(git log --pretty=format:"%h" -1) fi echo "latest_release=$tags" >>$GITHUB_ENV From cb8857b6bde6cb20518d8ece2f2560a4547a6014 Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 14 May 2026 16:38:06 +0800 Subject: [PATCH 412/425] linux-6.18: bump to 6.18.29 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 05250b0fd..9af100919 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .28 -LINUX_KERNEL_HASH-6.18.28 = f360789483586cf8a20b4ab2bffe76ead6b62c0db1eeb0d917294456c4d77b74 +LINUX_VERSION-6.18 = .29 +LINUX_KERNEL_HASH-6.18.29 = c33ea75b1f3bc5fccab836790cd3684eab7057ff383464b5efd8a68ba622a83c From 769d7344a456a3c6692322d2ff0b4ab6ffa6f9dc Mon Sep 17 00:00:00 2001 From: sbwml Date: Thu, 14 May 2026 16:38:29 +0800 Subject: [PATCH 413/425] OpenWrt v25.12.4 Signed-off-by: sbwml --- tags/v25 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tags/v25 b/tags/v25 index 4b66be7c3..e19286fea 100644 --- a/tags/v25 +++ b/tags/v25 @@ -1 +1 @@ -25.12.3 +25.12.4 From 5ccbb8a87614b656f894067490c2eb0f169d97f6 Mon Sep 17 00:00:00 2001 From: sbwml Date: Fri, 15 May 2026 04:31:44 +0800 Subject: [PATCH 414/425] linux-6.18: bump to 6.18.30 Signed-off-by: sbwml --- openwrt/build.sh | 3 +++ tags/kernel-6.18 | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 4667c1b60..d16b15f5b 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -491,6 +491,7 @@ if [ "$platform" = "x86_64" ]; then cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/appfilter*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/luci-app-oaf*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/luci-i18n-oaf*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/x86_64/base/*dpdk*.apk $kmodpkg_name/ || true @@ -543,6 +544,7 @@ elif [ "$platform" = "armv8" ]; then cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/appfilter*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/luci-app-oaf*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/luci-i18n-oaf*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.apk $kmodpkg_name/ || true @@ -590,6 +592,7 @@ else cp -a bin/packages/aarch64_generic/base/natflow*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/appfilter*.apk $kmodpkg_name/ || true cp -a bin/packages/aarch64_generic/base/luci-app-oaf*.apk $kmodpkg_name/ || true + cp -a bin/packages/aarch64_generic/base/luci-i18n-oaf*.apk $kmodpkg_name/ || true } [ "$ENABLE_DPDK" = "y" ] && { cp -a bin/packages/aarch64_generic/base/*dpdk*.apk $kmodpkg_name/ || true diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 9af100919..9f634bfa4 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .29 -LINUX_KERNEL_HASH-6.18.29 = c33ea75b1f3bc5fccab836790cd3684eab7057ff383464b5efd8a68ba622a83c +LINUX_VERSION-6.18 = .30 +LINUX_KERNEL_HASH-6.18.30 = a8b3886ec3af573f7420b23d27390d4f2b0aac62e8da041662523ce2e7dfb3d4 From 27ba7a7bf71bb954aade60968d5e54af07d6d8b7 Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 16 May 2026 00:05:22 +0800 Subject: [PATCH 415/425] ci: update actions/cache workflow Signed-off-by: sbwml --- .github/workflows/build-release.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index a827a2bee..b4863503c 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -102,10 +102,10 @@ jobs: - name: Restore Cached if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device != 'armv8' && github.event.inputs.device != 'nanopi-r4s' }} - uses: actions/cache/restore@v4 + uses: actions/cache/restore@main with: path: /builder/.ccache - key: openwrt-24.10-${{ github.event.inputs.device }}-ccache + key: openwrt-25.12-${{ github.event.inputs.device }}-ccache - name: Restore Cached (releases) if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device == 'armv8' || github.event.inputs.device == 'nanopi-r4s' }} @@ -156,15 +156,15 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} run: | - gh cache delete openwrt-24.10-${{ github.event.inputs.device }}-ccache || true + gh cache delete openwrt-25.12-${{ github.event.inputs.device }}-ccache || true - name: Save Cached if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device != 'armv8' && github.event.inputs.device != 'nanopi-r4s' }} continue-on-error: true - uses: actions/cache/save@v4 + uses: actions/cache/save@main with: path: /builder/.ccache - key: openwrt-24.10-${{ github.event.inputs.device }}-ccache + key: openwrt-25.12-${{ github.event.inputs.device }}-ccache - name: Create ccache tar files if: ${{ github.event.inputs.ccache == 'true' && github.event.inputs.device == 'armv8' || github.event.inputs.device == 'nanopi-r4s' }} @@ -218,7 +218,7 @@ jobs: fi - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@main with: name: ${{ github.event.inputs.device }}-openwrt-${{ env.latest_release }} path: ${{ env.build_dir }}/rom/* From d00322457cd7e0be0290baf180a5f4279a2ab0ab Mon Sep 17 00:00:00 2001 From: sbwml Date: Sat, 16 May 2026 03:03:13 +0800 Subject: [PATCH 416/425] netfilter: fix kmod-nf-ipt depend Signed-off-by: sbwml --- openwrt/patch/openwrt-6.x/modules/netfilter.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/openwrt/patch/openwrt-6.x/modules/netfilter.mk b/openwrt/patch/openwrt-6.x/modules/netfilter.mk index 24ca52ad3..a6cca3b09 100644 --- a/openwrt/patch/openwrt-6.x/modules/netfilter.mk +++ b/openwrt/patch/openwrt-6.x/modules/netfilter.mk @@ -74,6 +74,7 @@ define KernelPackage/nf-ipt SUBMENU:=$(NF_MENU) TITLE:=Iptables core KCONFIG:=$(KCONFIG_NF_IPT) + DEPENDS:=+kmod-iptables FILES:=$(foreach mod,$(NF_IPT-m),$(LINUX_DIR)/net/$(mod).ko) AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_IPT-m))) endef From 3705a0c327422b6ea206c7b6f4ddf8f6d7cc02a4 Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 20 May 2026 09:48:38 +0800 Subject: [PATCH 417/425] linux-6.18: bump to 6.18.32 Signed-off-by: sbwml --- tags/kernel-6.18 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 9f634bfa4..65211c607 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .30 -LINUX_KERNEL_HASH-6.18.30 = a8b3886ec3af573f7420b23d27390d4f2b0aac62e8da041662523ce2e7dfb3d4 +LINUX_VERSION-6.18 = .32 +LINUX_KERNEL_HASH-6.18.32 = 067dadd445578284ea6158f312f7970d8940fed3e094dbe49cff66d188d3bda4 From ee2964e24f816d26a6fde5991eb03e3085589c5a Mon Sep 17 00:00:00 2001 From: sbwml Date: Wed, 20 May 2026 09:50:08 +0800 Subject: [PATCH 418/425] config: add luci-app-oaf (rewritten in JS) Signed-off-by: sbwml --- openwrt/25-config-common | 10 ++-------- openwrt/25-config-minimal-common | 4 ---- openwrt/25-config-std-common | 11 ++--------- openwrt/scripts/02-prepare_package.sh | 2 +- 4 files changed, 5 insertions(+), 22 deletions(-) diff --git a/openwrt/25-config-common b/openwrt/25-config-common index 27196660b..6b48104e2 100644 --- a/openwrt/25-config-common +++ b/openwrt/25-config-common @@ -28,7 +28,6 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y ### Dnsmasq CONFIG_PACKAGE_dnsmasq-full=y -# CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set # CONFIG_PACKAGE_dnsmasq is not set ### Docker @@ -79,15 +78,16 @@ CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y CONFIG_PACKAGE_luci-app-eqos=y -CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-frpc=y CONFIG_PACKAGE_luci-app-mentohust=y CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y +CONFIG_PACKAGE_luci-app-oaf=y CONFIG_PACKAGE_luci-app-openlist2=y CONFIG_PACKAGE_luci-app-qbittorrent=y +CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-rtp2httpd=y CONFIG_PACKAGE_luci-app-samba4=y @@ -142,7 +142,6 @@ CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules CONFIG_PACKAGE_kmod-bonding=y CONFIG_PACKAGE_kmod-br-netfilter=y -CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y CONFIG_PACKAGE_kmod-tun=y @@ -154,9 +153,6 @@ CONFIG_PACKAGE_kmod-fs-xfs=y CONFIG_PACKAGE_kmod-hwmon-pwmfan=y CONFIG_PACKAGE_kmod-ikconfig=y CONFIG_PACKAGE_kmod-inet-diag=y -CONFIG_PACKAGE_kmod-ipsec4=y -CONFIG_PACKAGE_kmod-ipsec6=y -CONFIG_PACKAGE_kmod-iptunnel6=y CONFIG_PACKAGE_kmod-mac80211=y CONFIG_PACKAGE_kmod-nf-socket=y CONFIG_PACKAGE_kmod-nft-fullcone=y @@ -251,8 +247,6 @@ CONFIG_PACKAGE_coreutils-mkdir=y CONFIG_PACKAGE_coreutils-mv=y CONFIG_PACKAGE_coreutils-nproc=y CONFIG_PACKAGE_coreutils-rm=y -CONFIG_PACKAGE_coreutils-sha1sum=y -CONFIG_PACKAGE_coreutils-sha512sum=y CONFIG_PACKAGE_coreutils-sleep=y CONFIG_PACKAGE_coreutils-timeout=y CONFIG_PACKAGE_coreutils-truncate=y diff --git a/openwrt/25-config-minimal-common b/openwrt/25-config-minimal-common index 293b4a3c8..1f50dc619 100644 --- a/openwrt/25-config-minimal-common +++ b/openwrt/25-config-minimal-common @@ -28,7 +28,6 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y ### Dnsmasq CONFIG_PACKAGE_dnsmasq-full=y -# CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set # CONFIG_PACKAGE_dnsmasq is not set ### Luci @@ -83,7 +82,6 @@ CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules CONFIG_PACKAGE_kmod-bonding=y CONFIG_PACKAGE_kmod-br-netfilter=y -CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y CONFIG_PACKAGE_kmod-fs-exfat=y @@ -94,8 +92,6 @@ CONFIG_PACKAGE_kmod-fs-xfs=y CONFIG_PACKAGE_kmod-hwmon-pwmfan=y CONFIG_PACKAGE_kmod-ikconfig=y CONFIG_PACKAGE_kmod-inet-diag=y -CONFIG_PACKAGE_kmod-ipsec4=y -CONFIG_PACKAGE_kmod-ipsec6=y CONFIG_PACKAGE_kmod-mac80211=y CONFIG_PACKAGE_kmod-nf-socket=y CONFIG_PACKAGE_kmod-nft-fullcone=y diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index 95a5c2fb1..582fc0471 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -28,7 +28,6 @@ CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG_INFO=y ### Dnsmasq CONFIG_PACKAGE_dnsmasq-full=y -# CONFIG_PACKAGE_dnsmasq_full_broken_rtc is not set # CONFIG_PACKAGE_dnsmasq is not set ### Luci @@ -67,12 +66,13 @@ CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y CONFIG_PACKAGE_luci-app-ddns=y CONFIG_PACKAGE_luci-app-diskman=y -CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-frpc=y CONFIG_PACKAGE_luci-app-mosdns=y CONFIG_PACKAGE_luci-app-natmap=y CONFIG_PACKAGE_luci-app-netspeedtest=y CONFIG_PACKAGE_luci-app-nlbwmon=y +CONFIG_PACKAGE_luci-app-oaf=y +CONFIG_PACKAGE_luci-app-quickfile=y CONFIG_PACKAGE_luci-app-ramfree=y CONFIG_PACKAGE_luci-app-socat=y CONFIG_PACKAGE_luci-app-sqm=y @@ -121,7 +121,6 @@ CONFIG_PACKAGE_kmod-usb-net-ipheth=y ### Kernel Modules CONFIG_PACKAGE_kmod-bonding=y CONFIG_PACKAGE_kmod-br-netfilter=y -CONFIG_PACKAGE_kmod-button-hotplug=y CONFIG_PACKAGE_kmod-crypto-chacha20poly1305=y CONFIG_PACKAGE_kmod-crypto-sha256=y CONFIG_PACKAGE_kmod-fs-exfat=y @@ -132,9 +131,6 @@ CONFIG_PACKAGE_kmod-fs-xfs=y CONFIG_PACKAGE_kmod-hwmon-pwmfan=y CONFIG_PACKAGE_kmod-ikconfig=y CONFIG_PACKAGE_kmod-inet-diag=y -CONFIG_PACKAGE_kmod-ipsec4=y -CONFIG_PACKAGE_kmod-ipsec6=y -CONFIG_PACKAGE_kmod-iptunnel6=y CONFIG_PACKAGE_kmod-mac80211=y CONFIG_PACKAGE_kmod-nf-socket=y CONFIG_PACKAGE_kmod-nft-fullcone=y @@ -158,7 +154,6 @@ CONFIG_PACKAGE_kmod-usb2-pci=y CONFIG_PACKAGE_kmod-usb2=y CONFIG_PACKAGE_kmod-usb3=y CONFIG_PACKAGE_kmod-veth=y -CONFIG_PACKAGE_kmod-xdp-sockets-diag=y ### Kernel Modules - out-of-tree driver CONFIG_PACKAGE_kmod-usb-net-rtl8152-vendor=y @@ -228,8 +223,6 @@ CONFIG_PACKAGE_coreutils-mkdir=y CONFIG_PACKAGE_coreutils-mv=y CONFIG_PACKAGE_coreutils-nproc=y CONFIG_PACKAGE_coreutils-rm=y -CONFIG_PACKAGE_coreutils-sha1sum=y -CONFIG_PACKAGE_coreutils-sha512sum=y CONFIG_PACKAGE_coreutils-sleep=y CONFIG_PACKAGE_coreutils-timeout=y CONFIG_PACKAGE_coreutils-truncate=y diff --git a/openwrt/scripts/02-prepare_package.sh b/openwrt/scripts/02-prepare_package.sh index a9a3179e4..1735e93a4 100644 --- a/openwrt/scripts/02-prepare_package.sh +++ b/openwrt/scripts/02-prepare_package.sh @@ -139,7 +139,7 @@ sed -i 's/100/85/g' package/new/luci-app-aurora-config/root/usr/share/luci/menu. git clone https://$github/sbwml/luci-app-mosdns -b v5 package/new/mosdns --depth=1 # OpenAppFilter -git clone https://$github/sbwml/OpenAppFilter --depth=1 package/new/OpenAppFilter -b v6 +git clone https://$github/sbwml/OpenAppFilter --depth=1 package/new/OpenAppFilter -b main # iperf3 sed -i "s/D_GNU_SOURCE/D_GNU_SOURCE -funroll-loops/g" feeds/packages/net/iperf3/Makefile From 1a32cf2b312e8e92e59472aca50ae05ad21a239f Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 25 May 2026 04:26:25 +0800 Subject: [PATCH 419/425] config-std: remove luci-theme-aurora Signed-off-by: sbwml --- openwrt/25-config-std-common | 2 -- 1 file changed, 2 deletions(-) diff --git a/openwrt/25-config-std-common b/openwrt/25-config-std-common index 582fc0471..92fab0ac7 100644 --- a/openwrt/25-config-std-common +++ b/openwrt/25-config-std-common @@ -35,7 +35,6 @@ CONFIG_PACKAGE_luci=y CONFIG_PACKAGE_luci-nginx=y CONFIG_PACKAGE_luci-proto-wireguard=y CONFIG_PACKAGE_luci-theme-argon=y -CONFIG_PACKAGE_luci-theme-aurora=y CONFIG_LUCI_LANG_zh_Hans=y # CONFIG_LUCI_CSSTIDY is not set # CONFIG_LUCI_JSMIN is not set @@ -60,7 +59,6 @@ CONFIG_NGINX_STREAM_REAL_IP=y CONFIG_PACKAGE_luci-app-airconnect=y CONFIG_PACKAGE_luci-app-airplay2=y CONFIG_PACKAGE_luci-app-argon-config=y -CONFIG_PACKAGE_luci-app-aurora-config=y CONFIG_PACKAGE_luci-app-autoreboot=y CONFIG_PACKAGE_luci-app-commands=y CONFIG_PACKAGE_luci-app-cpufreq=y From d5698bd77dfa82c0d4b4e990b6e52bd84e4d0be5 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 25 May 2026 04:26:41 +0800 Subject: [PATCH 420/425] build.sh: fix thread count detection to prevent OOM on RHEL 10 Replace `nproc --all` with `nproc` when determining the maximum number of parallel jobs. Signed-off-by: sbwml --- openwrt/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index d16b15f5b..972954299 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -66,7 +66,7 @@ starttime=`date +'%Y-%m-%d %H:%M:%S'` CURRENT_DATE=$(date +%s) # Cpus -cores=`expr $(nproc --all) + 1` +cores=`expr $(nproc) + 1` # $CURL_BAR if curl --help | grep progress-bar >/dev/null 2>&1; then From 0960c7526ee4383bc1dc07fc5f00bc06215bcfa9 Mon Sep 17 00:00:00 2001 From: sbwml Date: Mon, 25 May 2026 07:12:15 +0800 Subject: [PATCH 421/425] build.sh: update RHEL 10 identifier Signed-off-by: sbwml --- openwrt/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openwrt/build.sh b/openwrt/build.sh index 972954299..dcd655531 100644 --- a/openwrt/build.sh +++ b/openwrt/build.sh @@ -329,7 +329,8 @@ fi [ "$ENABLE_OTA" = "y" ] && [ "$version" = "rc2" ] && echo 'CONFIG_PACKAGE_luci-app-ota=y' >> .config # bpf -[ "$ENABLE_BPF" = "y" ] && curl -s $mirror/openwrt/generic/config-bpf >> .config +curl -s $mirror/openwrt/generic/config-bpf >> .config +[ "$ENABLE_BPF" != "y" ] && sed -i '/KERNEL_DEBUG_INFO\|KERNEL_MODULE_ALLOW_BTF/d' .config # LTO export ENABLE_LTO=$ENABLE_LTO @@ -420,11 +421,10 @@ fi # Toolchain Cache if [ "$BUILD_FAST" = "y" ]; then [ "$ENABLE_GLIBC" = "y" ] && LIBC=glibc || LIBC=musl - [ "$isCN" = "CN" ] && github_proxy="ghp.ci/" || github_proxy="" echo -e "\n${GREEN_COLOR}Download Toolchain ...${RES}" PLATFORM_ID="" [ -f /etc/os-release ] && source /etc/os-release - if [ "$PLATFORM_ID" = "platform:el9" ]; then + if [ "$PLATFORM_ID" = "platform:el10" ]; then TOOLCHAIN_URL="http://127.0.0.1:8080" else TOOLCHAIN_URL=https://"$github_proxy"github.com/sbwml/openwrt_caches/releases/download/openwrt-25.12 From 7462ee5dc66c239df3cb41eff63281e568d76c8d Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 31 May 2026 00:40:11 +0800 Subject: [PATCH 422/425] config: nanopi: enable `CONFIG_KERNEL_PSI` Signed-off-by: sbwml --- openwrt/25-config-musl-r4s | 1 + openwrt/25-config-musl-r5s | 1 + openwrt/25-config-musl-r76s | 1 + 3 files changed, 3 insertions(+) diff --git a/openwrt/25-config-musl-r4s b/openwrt/25-config-musl-r4s index bacf85ebf..51d6d95cd 100644 --- a/openwrt/25-config-musl-r4s +++ b/openwrt/25-config-musl-r4s @@ -13,6 +13,7 @@ CONFIG_KERNEL_MEMCG_V1=y CONFIG_KERNEL_MPTCP=y CONFIG_KERNEL_MPTCP_IPV6=y # CONFIG_KERNEL_PREEMPT_RT is not set +CONFIG_KERNEL_PSI=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/25-config-musl-r5s b/openwrt/25-config-musl-r5s index ded403445..59bf69938 100644 --- a/openwrt/25-config-musl-r5s +++ b/openwrt/25-config-musl-r5s @@ -15,6 +15,7 @@ CONFIG_KERNEL_MEMCG_V1=y CONFIG_KERNEL_MPTCP=y CONFIG_KERNEL_MPTCP_IPV6=y # CONFIG_KERNEL_PREEMPT_RT is not set +CONFIG_KERNEL_PSI=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y diff --git a/openwrt/25-config-musl-r76s b/openwrt/25-config-musl-r76s index d36bb7321..bdb09f2b7 100644 --- a/openwrt/25-config-musl-r76s +++ b/openwrt/25-config-musl-r76s @@ -13,6 +13,7 @@ CONFIG_KERNEL_MEMCG_V1=y CONFIG_KERNEL_MPTCP=y CONFIG_KERNEL_MPTCP_IPV6=y # CONFIG_KERNEL_PREEMPT_RT is not set +CONFIG_KERNEL_PSI=y CONFIG_PACKAGE_autocore-arm=y CONFIG_PACKAGE_bind-host=y CONFIG_PACKAGE_block-mount=y From 916695c4e5dc76f2aa52214a0f838e7774d353cc Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 31 May 2026 00:40:42 +0800 Subject: [PATCH 423/425] nginx: set `client_body_buffer_size` * fix XHR request aborted by browser Signed-off-by: sbwml --- openwrt/nginx/uci.conf.template | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openwrt/nginx/uci.conf.template b/openwrt/nginx/uci.conf.template index 6ea39ae43..0dd4ec4c7 100644 --- a/openwrt/nginx/uci.conf.template +++ b/openwrt/nginx/uci.conf.template @@ -26,7 +26,8 @@ http { default_type application/octet-stream; sendfile on; - client_max_body_size 8192M; + client_max_body_size 0; + client_body_buffer_size 128k; large_client_header_buffers 4 32k; gzip on; From 554df43d981faacd5c86368d8c1f7f356aa549de Mon Sep 17 00:00:00 2001 From: sbwml Date: Sun, 31 May 2026 23:31:43 +0800 Subject: [PATCH 424/425] nginx-util: remove uci.conf.template in upgrade backup Signed-off-by: sbwml --- openwrt/scripts/00-prepare_base.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openwrt/scripts/00-prepare_base.sh b/openwrt/scripts/00-prepare_base.sh index b86798aee..3ca14f590 100644 --- a/openwrt/scripts/00-prepare_base.sh +++ b/openwrt/scripts/00-prepare_base.sh @@ -227,6 +227,9 @@ sed -i '/ubus_parallel_req/a\ ubus_script_timeout 300;' feeds/packages/ne curl -s $mirror/openwrt/nginx/luci.locations > feeds/packages/net/nginx/files-luci-support/luci.locations curl -s $mirror/openwrt/nginx/uci.conf.template > feeds/packages/net/nginx-util/files/uci.conf.template +# nginx-util +sed -i '/\/etc\/nginx\/uci.conf.template/d' feeds/packages/net/nginx-util/Makefile + # netifd curl -s $mirror/openwrt/patch/netifd/001-hack-packet_steering-for-nanopi-r76s.patch | patch -p1 From 815b1c35a0d776c09b1668fa69ededa30d1f04f1 Mon Sep 17 00:00:00 2001 From: sbwml Date: Tue, 2 Jun 2026 01:52:06 +0800 Subject: [PATCH 425/425] linux-6.18: bump to 6.18.34 Signed-off-by: sbwml --- ...-broaden-app-limited-rate-sample-detectio.patch | 4 ++-- ...-v2-shrink-delivered_mstamp-first_tx_msta.patch | 2 +- ...-v2-snapshot-packets-in-flight-at-transmi.patch | 8 ++++---- ...-v2-count-packets-lost-over-TCP-rate-samp.patch | 4 ++-- ...-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch | 4 ++-- ...-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch | 4 ++-- ...-v2-adjust-skb-tx.in_flight-upon-merge-in.patch | 2 +- ...-v2-adjust-skb-tx.in_flight-upon-split-in.patch | 6 +++--- ...-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch | 4 ++-- ...generalize-TSO-sizing-in-TCP-CC-module-AP.patch | 4 ++-- ...-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch | 6 +++--- ...-v2-record-app-limited-status-of-TLP-repa.patch | 2 +- ...-v2-inform-CC-module-of-losses-repaired-b.patch | 4 ++-- ...-v2-introduce-is_acking_tlp_retrans_seq-i.patch | 10 +++++----- ...ce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch | 2 +- ...-v3-update-TCP-bbr-congestion-control-mod.patch | 14 +++++++------- ...-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch | 2 +- ...TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch | 2 +- tags/kernel-6.18 | 4 ++-- 19 files changed, 44 insertions(+), 44 deletions(-) diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch index ac7b44451..f0f22b801 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0001-net-tcp_bbr-broaden-app-limited-rate-sample-detectio.patch @@ -32,7 +32,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4042,6 +4042,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4048,6 +4048,7 @@ static int tcp_ack(struct sock *sk, cons prior_fack = tcp_is_sack(tp) ? tcp_highest_sack_seq(tp) : tp->snd_una; rs.prior_in_flight = tcp_packets_in_flight(tp); @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade * is in window. --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c -@@ -702,6 +702,7 @@ void tcp_write_timer_handler(struct sock +@@ -703,6 +703,7 @@ void tcp_write_timer_handler(struct sock icsk_timeout(icsk)); return; } diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch index 6def0c575..0667ead6c 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0002-net-tcp_bbr-v2-shrink-delivered_mstamp-first_tx_msta.patch @@ -37,7 +37,7 @@ Signed-off-by: Alexandre Frade /* provide the departure time in us unit */ static inline u64 tcp_skb_timestamp_us(const struct sk_buff *skb) { -@@ -1056,9 +1061,9 @@ struct tcp_skb_cb { +@@ -1059,9 +1064,9 @@ struct tcp_skb_cb { /* pkts S/ACKed so far upon tx of skb, incl retrans: */ __u32 delivered; /* start of send pipeline phase */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch index 65c97f9d1..6c284d409 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0003-net-tcp_bbr-v2-snapshot-packets-in-flight-at-transmi.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1064,6 +1064,10 @@ struct tcp_skb_cb { +@@ -1067,6 +1067,10 @@ struct tcp_skb_cb { u32 first_tx_mstamp; /* when we reached the "delivered" count */ u32 delivered_mstamp; @@ -38,7 +38,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1228,6 +1232,7 @@ struct rate_sample { +@@ -1231,6 +1235,7 @@ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ u32 prior_delivered_ce;/* tp->delivered_ce at "prior_mstamp" */ @@ -46,7 +46,7 @@ Signed-off-by: Alexandre Frade s32 delivered; /* number of packets delivered over interval */ s32 delivered_ce; /* number of packets delivered w/ CE marks*/ long interval_us; /* time for tp->delivered to incr "delivered" */ -@@ -1371,6 +1376,7 @@ static inline void tcp_ca_event(struct s +@@ -1374,6 +1379,7 @@ static inline void tcp_ca_event(struct s void tcp_set_ca_state(struct sock *sk, const u8 ca_state); /* From tcp_rate.c */ @@ -56,7 +56,7 @@ Signed-off-by: Alexandre Frade struct rate_sample *rs); --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2937,6 +2937,7 @@ static bool tcp_write_xmit(struct sock * +@@ -2916,6 +2916,7 @@ static bool tcp_write_xmit(struct sock * skb_set_delivery_time(skb, tp->tcp_wstamp_ns, SKB_CLOCK_MONOTONIC); list_move_tail(&skb->tcp_tsorted_anchor, &tp->tsorted_sent_queue); tcp_init_tso_segs(skb, mss_now); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch index ceac09fba..affccb9d6 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0004-net-tcp_bbr-v2-count-packets-lost-over-TCP-rate-samp.patch @@ -19,7 +19,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1068,6 +1068,7 @@ struct tcp_skb_cb { +@@ -1071,6 +1071,7 @@ struct tcp_skb_cb { #define TCPCB_IN_FLIGHT_MAX ((1U << TCPCB_IN_FLIGHT_BITS) - 1) u32 in_flight:20, /* packets in flight at transmit */ unused2:12; @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade } tx; /* only used for outgoing skbs */ union { struct inet_skb_parm h4; -@@ -1230,11 +1231,13 @@ struct ack_sample { +@@ -1233,11 +1234,13 @@ struct ack_sample { */ struct rate_sample { u64 prior_mstamp; /* starting timestamp for interval */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch index fde30ff41..7d08adfe5 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0005-net-tcp_bbr-v2-export-FLAG_ECE-in-rate_sample.is_ece.patch @@ -18,7 +18,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1249,6 +1249,7 @@ struct rate_sample { +@@ -1252,6 +1252,7 @@ struct rate_sample { bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ bool is_ack_delayed; /* is this (likely) a delayed ACK? */ @@ -28,7 +28,7 @@ Signed-off-by: Alexandre Frade struct tcp_congestion_ops { --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4140,6 +4140,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4146,6 +4146,7 @@ static int tcp_ack(struct sock *sk, cons lost = tp->lost - lost; /* freshly marked lost */ rs.is_ack_delayed = !!(flag & FLAG_ACK_MAYBE_DELAYED); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch index 972ea9630..5295e0ddb 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0006-net-tcp_bbr-v2-introduce-ca_ops-skb_marked_lost-CC-m.patch @@ -30,7 +30,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1276,6 +1276,9 @@ struct tcp_congestion_ops { +@@ -1279,6 +1279,9 @@ struct tcp_congestion_ops { /* override sysctl_tcp_min_tso_segs */ u32 (*min_tso_segs)(struct sock *sk); @@ -42,7 +42,7 @@ Signed-off-by: Alexandre Frade */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1289,7 +1289,12 @@ static void tcp_verify_retransmit_hint(s +@@ -1290,7 +1290,12 @@ static void tcp_verify_retransmit_hint(s */ static void tcp_notify_skb_loss_event(struct tcp_sock *tp, const struct sk_buff *skb) { diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch index d8ccc70e5..2e0a7e537 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0007-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-merge-in.patch @@ -39,7 +39,7 @@ Signed-off-by: Alexandre Frade --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -1659,6 +1659,17 @@ static bool tcp_shifted_skb(struct sock +@@ -1660,6 +1660,17 @@ static bool tcp_shifted_skb(struct sock WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount); tcp_skb_pcount_add(skb, -pcount); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch index 7419d1310..89fb3ba89 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0008-net-tcp_bbr-v2-adjust-skb-tx.in_flight-upon-split-in.patch @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1396,6 +1396,21 @@ static inline bool tcp_skb_sent_after(u6 +@@ -1399,6 +1399,21 @@ static inline bool tcp_skb_sent_after(u6 return t1 > t2 || (t1 == t2 && after(seq1, seq2)); } @@ -55,7 +55,7 @@ Signed-off-by: Alexandre Frade * between different flows. --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -1759,7 +1759,7 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1761,7 +1761,7 @@ int tcp_fragment(struct sock *sk, enum t { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; @@ -64,7 +64,7 @@ Signed-off-by: Alexandre Frade long limit; u16 flags; int nlen; -@@ -1834,6 +1834,30 @@ int tcp_fragment(struct sock *sk, enum t +@@ -1836,6 +1836,30 @@ int tcp_fragment(struct sock *sk, enum t if (diff) tcp_adjust_pcount(sk, skb, diff); diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch index a18e66738..2dd2abf6c 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0009-net-tcp-add-new-ca-opts-flag-TCP_CONG_WANTS_CE_EVENT.patch @@ -23,7 +23,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1209,9 +1209,11 @@ enum tcp_ca_ack_event_flags { +@@ -1212,9 +1212,11 @@ enum tcp_ca_ack_event_flags { #define TCP_CONG_ECT_1_NEGOTIATION BIT(3) /* Cannot fallback to RFC3168 during AccECN negotiation */ #define TCP_CONG_NO_FALLBACK_RFC3168 BIT(4) @@ -36,7 +36,7 @@ Signed-off-by: Alexandre Frade union tcp_cc_info; -@@ -1343,6 +1345,14 @@ static inline char *tcp_ca_get_name_by_k +@@ -1346,6 +1348,14 @@ static inline char *tcp_ca_get_name_by_k } #endif diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch index 87ccc3266..dd5ac81a8 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0010-net-tcp-re-generalize-TSO-sizing-in-TCP-CC-module-AP.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1275,8 +1275,8 @@ struct tcp_congestion_ops { +@@ -1278,8 +1278,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); @@ -97,7 +97,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -2214,13 +2214,12 @@ static u32 tcp_tso_autosize(const struct +@@ -2216,13 +2216,12 @@ static u32 tcp_tso_autosize(const struct static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) { const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch index 7af965997..10c4ada05 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0011-net-tcp-add-fast_ack_mode-1-skip-rwin-check-in-tcp_f.patch @@ -21,7 +21,7 @@ Signed-off-by: Alexandre Frade --- a/include/linux/tcp.h +++ b/include/linux/tcp.h -@@ -236,7 +236,8 @@ struct tcp_sock { +@@ -235,7 +235,8 @@ struct tcp_sock { tcp_usec_ts : 1, /* TSval values in usec */ is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */ @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade /* RX read-mostly hotpath cache lines */ --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -3471,6 +3471,7 @@ int tcp_disconnect(struct sock *sk, int +@@ -3468,6 +3468,7 @@ int tcp_disconnect(struct sock *sk, int tp->rx_opt.dsack = 0; tp->rx_opt.num_sacks = 0; tp->rcv_ooopack = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade if (tcp_ca_needs_ecn(sk)) --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -5906,13 +5906,14 @@ static void __tcp_ack_snd_check(struct s +@@ -5912,13 +5912,14 @@ static void __tcp_ack_snd_check(struct s /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch index 7624a8084..427e1d655 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0012-net-tcp_bbr-v2-record-app-limited-status-of-TLP-repa.patch @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade u8 accecn_minlen:2,/* Minimum length of AccECN option sent */ --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -3173,6 +3173,7 @@ void tcp_send_loss_probe(struct sock *sk +@@ -3152,6 +3152,7 @@ void tcp_send_loss_probe(struct sock *sk if (WARN_ON(!skb || !tcp_skb_pcount(skb))) goto rearm_timer; diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch index c560e1daf..1d075e54c 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0013-net-tcp_bbr-v2-inform-CC-module-of-losses-repaired-b.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1181,6 +1181,7 @@ enum tcp_ca_event { +@@ -1184,6 +1184,7 @@ enum tcp_ca_event { CA_EVENT_LOSS, /* loss timeout */ CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ @@ -35,7 +35,7 @@ Signed-off-by: Alexandre Frade /* Information about inbound ACK, passed to cong_ops->in_ack_event() */ --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3922,6 +3922,7 @@ static void tcp_process_tlp_ack(struct s +@@ -3924,6 +3924,7 @@ static void tcp_process_tlp_ack(struct s /* ACK advances: there was a loss, so reduce cwnd. Reset * tlp_high_seq in tcp_init_cwnd_reduction() */ diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch index bb410c8b1..b399ac5d4 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0014-net-tcp_bbr-v2-introduce-is_acking_tlp_retrans_seq-i.patch @@ -21,7 +21,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -1251,6 +1251,7 @@ struct rate_sample { +@@ -1254,6 +1254,7 @@ struct rate_sample { u32 last_end_seq; /* end_seq of most recently ACKed packet */ bool is_app_limited; /* is sample from packet with bubble in pipe? */ bool is_retrans; /* is sample from retransmission? */ @@ -31,7 +31,7 @@ Signed-off-by: Alexandre Frade }; --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3905,7 +3905,8 @@ static int tcp_replace_ts_recent(struct +@@ -3907,7 +3907,8 @@ static int tcp_replace_ts_recent(struct /* This routine deals with acks during a TLP episode and ends an episode by * resetting tlp_high_seq. Ref: TLP algorithm in RFC8985 */ @@ -41,7 +41,7 @@ Signed-off-by: Alexandre Frade { struct tcp_sock *tp = tcp_sk(sk); -@@ -3933,6 +3934,11 @@ static void tcp_process_tlp_ack(struct s +@@ -3935,6 +3936,11 @@ static void tcp_process_tlp_ack(struct s FLAG_NOT_DUP | FLAG_DATA_SACKED))) { /* Pure dupack: original and TLP probe arrived; no loss */ tp->tlp_high_seq = 0; @@ -53,7 +53,7 @@ Signed-off-by: Alexandre Frade } } -@@ -4132,7 +4138,7 @@ static int tcp_ack(struct sock *sk, cons +@@ -4138,7 +4144,7 @@ static int tcp_ack(struct sock *sk, cons tcp_in_ack_event(sk, flag); if (tp->tlp_high_seq) @@ -62,7 +62,7 @@ Signed-off-by: Alexandre Frade if (tcp_ack_is_dubious(sk, flag)) { if (!(flag & (FLAG_SND_UNA_ADVANCED | -@@ -4183,7 +4189,7 @@ no_queue: +@@ -4189,7 +4195,7 @@ no_queue: tcp_ack_probe(sk); if (tp->tlp_high_seq) diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch index 3523ebbc9..c01f5d4ce 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0015-tcp-introduce-per-route-feature-RTAX_FEATURE_ECN_LOW.patch @@ -33,7 +33,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -404,6 +404,7 @@ static inline void tcp_dec_quickack_mode +@@ -402,6 +402,7 @@ static inline void tcp_dec_quickack_mode #define TCP_ECN_DEMAND_CWR BIT(2) #define TCP_ECN_SEEN BIT(3) #define TCP_ECN_MODE_ACCECN BIT(4) diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch index 198da7d4f..75a819dbe 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0016-net-tcp_bbr-v3-update-TCP-bbr-congestion-control-mod.patch @@ -153,7 +153,7 @@ Signed-off-by: Alexandre Frade #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -2619,7 +2619,7 @@ struct tcp_plb_state { +@@ -2649,7 +2649,7 @@ struct tcp_plb_state { u8 consec_cong_rounds:5, /* consecutive congested rounds */ unused:3; u32 pause_until; /* jiffies32 when PLB can resume rerouting */ @@ -1266,8 +1266,8 @@ Signed-off-by: Alexandre Frade - - if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { - bbr->mode = BBR_DRAIN; /* drain queue we created */ -- tcp_sk(sk)->snd_ssthresh = -- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); +- WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, +- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT)); - } /* fall through to check if in-flight is already small: */ - if (bbr->mode == BBR_DRAIN && - bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= @@ -2360,8 +2360,7 @@ Signed-off-by: Alexandre Frade +/* If pipe is probably full, drain the queue and then enter steady-state. */ +static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs, + struct bbr_context *ctx) - { -- bbr_update_bw(sk, rs); ++{ + struct bbr *bbr = inet_csk_ca(sk); + + if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { @@ -2384,7 +2383,8 @@ Signed-off-by: Alexandre Frade + +static void bbr_update_model(struct sock *sk, const struct rate_sample *rs, + struct bbr_context *ctx) -+{ + { +- bbr_update_bw(sk, rs); + bbr_update_congestion_signals(sk, rs, ctx); bbr_update_ack_aggregation(sk, rs); - bbr_update_cycle_phase(sk, rs); @@ -2503,7 +2503,7 @@ Signed-off-by: Alexandre Frade + + bbr->init_cwnd = min(0x7FU, tcp_snd_cwnd(tp)); + bbr->prior_cwnd = tp->prior_cwnd; - tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; + WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH); - bbr->rtt_cnt = 0; bbr->next_rtt_delivered = tp->delivered; bbr->prev_ca_state = TCP_CA_Open; diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch index db73b98b2..4b8cd0183 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0017-net-tcp_bbr-v3-ensure-ECN-enabled-BBR-flows-set-ECT-.patch @@ -25,7 +25,7 @@ Signed-off-by: Alexandre Frade --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -405,6 +405,7 @@ static inline void tcp_dec_quickack_mode +@@ -403,6 +403,7 @@ static inline void tcp_dec_quickack_mode #define TCP_ECN_SEEN BIT(3) #define TCP_ECN_MODE_ACCECN BIT(4) #define TCP_ECN_LOW BIT(5) diff --git a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch index c01bc6661..c0bea586a 100644 --- a/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch +++ b/openwrt/patch/kernel-6.18/bbr3/010-bbr3-0018-tcp-export-TCPI_OPT_ECN_LOW-in-tcp_info-tcpi_options.patch @@ -27,7 +27,7 @@ Signed-off-by: Alexandre Frade * Sender's congestion state indicating normal or abnormal situations --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c -@@ -4229,6 +4229,8 @@ void tcp_get_info(struct sock *sk, struc +@@ -4256,6 +4256,8 @@ void tcp_get_info(struct sock *sk, struc info->tcpi_options |= TCPI_OPT_ECN; if (tp->ecn_flags & TCP_ECN_SEEN) info->tcpi_options |= TCPI_OPT_ECN_SEEN; diff --git a/tags/kernel-6.18 b/tags/kernel-6.18 index 65211c607..ccd85ab5b 100644 --- a/tags/kernel-6.18 +++ b/tags/kernel-6.18 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.18 = .32 -LINUX_KERNEL_HASH-6.18.32 = 067dadd445578284ea6158f312f7970d8940fed3e094dbe49cff66d188d3bda4 +LINUX_VERSION-6.18 = .34 +LINUX_KERNEL_HASH-6.18.34 = 640c4732fb42842166db97e032c1fe7e5ff72c85a8982c75b40f74be3555d760

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®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[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 z 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