1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-03-09 15:40:20 +00:00

Add x86_64 kernel 6.11 support

This commit is contained in:
Ycarus (Yannick Chabanois) 2024-09-18 14:21:22 +02:00
parent 38e052ca4c
commit d35fc5c104
174 changed files with 35677 additions and 2 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,210 @@
From a779a482fb9b9f8fcdf8b2519c789b4b9bb5dd05 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 7 Jul 2017 16:56:48 +0200
Subject: build: add a hack for removing non-essential module info
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/linux/module.h | 13 ++++++++-----
include/linux/moduleparam.h | 15 ++++++++++++---
init/Kconfig | 7 +++++++
kernel/module.c | 5 ++++-
scripts/mod/modpost.c | 12 ++++++++++++
5 files changed, 43 insertions(+), 9 deletions(-)
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -164,6 +164,7 @@ extern void cleanup_module(void);
/* Generic info of form tag = "info" */
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
+#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
/* For userspace: you can also call me... */
#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
@@ -233,12 +234,12 @@ extern void cleanup_module(void);
* Author(s), use "Name <email>" or just "Name", for multiple
* authors use multiple MODULE_AUTHOR() statements/lines.
*/
-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
+#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
/* What your module does. */
-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
+#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
-#ifdef MODULE
+#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
/* Creates an alias so file2alias.c can find device table. */
#define MODULE_DEVICE_TABLE(type, name) \
extern typeof(name) __mod_##type##__##name##_device_table \
@@ -265,7 +266,9 @@ extern typeof(name) __mod_##type##__##na
*/
#if defined(MODULE) || !defined(CONFIG_SYSFS)
-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
+#elif defined(CONFIG_MODULE_STRIPPED)
+#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
#else
#define MODULE_VERSION(_version) \
MODULE_INFO(version, _version); \
@@ -288,7 +291,7 @@ extern typeof(name) __mod_##type##__##na
/* Optional firmware file (or files) needed by the module
* format is simply firmware file name. Multiple firmware
* files require multiple MODULE_FIRMWARE() specifiers */
-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
+#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
#define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, __stringify(ns))
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -20,6 +20,16 @@
/* Chosen so that structs with an unsigned long line up. */
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
+/* This struct is here for syntactic coherency, it is not used */
+#define __MODULE_INFO_DISABLED(name) \
+ struct __UNIQUE_ID(name) {}
+
+#ifdef CONFIG_MODULE_STRIPPED
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
+#else
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
+#endif
+
#define __MODULE_INFO(tag, name, info) \
static const char __UNIQUE_ID(name)[] \
__used __section(".modinfo") __aligned(1) \
@@ -31,7 +41,7 @@
/* One for each parameter, describing how to use it. Some files do
multiple of these per line, so can't just use MODULE_INFO. */
#define MODULE_PARM_DESC(_parm, desc) \
- __MODULE_INFO(parm, _parm, #_parm ":" desc)
+ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
struct kernel_param;
--- a/kernel/module/Kconfig
+++ b/kernel/module/Kconfig
@@ -389,4 +389,11 @@ config MODULES_TREE_LOOKUP
def_bool y
depends on PERF_EVENTS || TRACING || CFI_CLANG
+config MODULE_STRIPPED
+ bool "Reduce module size"
+ depends on MODULES
+ help
+ Remove module parameter descriptions, author info, version, aliases,
+ device tables, etc.
+
endif # MODULES
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -997,6 +997,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE(
static const char vermagic[] = VERMAGIC_STRING;
+#if defined(CONFIG_MODVERSIONS) || !defined(CONFIG_MODULE_STRIPPED)
int try_to_force_load(struct module *mod, const char *reason)
{
#ifdef CONFIG_MODULE_FORCE_LOAD
@@ -1008,6 +1009,7 @@ int try_to_force_load(struct module *mod
return -ENOEXEC;
#endif
}
+#endif
/* Parse tag=value strings from .modinfo section */
char *module_next_tag_pair(char *string, unsigned long *secsize)
@@ -2075,9 +2077,11 @@ static void module_augment_kernel_taints
static int check_modinfo(struct module *mod, struct load_info *info, int flags)
{
- const char *modmagic = get_modinfo(info, "vermagic");
int err;
+#ifndef CONFIG_MODULE_STRIPPED
+ const char *modmagic = get_modinfo(info, "vermagic");
+
if (flags & MODULE_INIT_IGNORE_VERMAGIC)
modmagic = NULL;
@@ -2091,6 +2095,7 @@ static int check_modinfo(struct module *
info->name, modmagic, vermagic);
return -ENOEXEC;
}
+#endif
err = check_modinfo_livepatch(mod, info);
if (err)
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1692,7 +1692,9 @@ static void read_symbols(const char *mod
symname = remove_dot(info.strtab + sym->st_name);
handle_symbol(mod, &info, sym, symname);
+#ifndef CONFIG_MODULE_STRIPPED
handle_moddevtable(mod, &info, sym, symname);
+#endif
}
check_sec_ref(mod, &info);
@@ -1865,8 +1867,10 @@ static void add_header(struct buffer *b,
buf_printf(b, "BUILD_SALT;\n");
buf_printf(b, "BUILD_LTO_INFO;\n");
buf_printf(b, "\n");
+#ifndef CONFIG_MODULE_STRIPPED
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
+#endif
buf_printf(b, "\n");
buf_printf(b, "__visible struct module __this_module\n");
buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
@@ -1880,8 +1884,10 @@ static void add_header(struct buffer *b,
buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
buf_printf(b, "};\n");
+#ifndef CONFIG_MODULE_STRIPPED
if (!external_module)
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
+#endif
buf_printf(b,
"\n"
@@ -1889,8 +1895,10 @@ static void add_header(struct buffer *b,
"MODULE_INFO(retpoline, \"Y\");\n"
"#endif\n");
+#ifndef CONFIG_MODULE_STRIPPED
if (strstarts(mod->name, "drivers/staging"))
buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+#endif
if (strstarts(mod->name, "tools/testing"))
buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
@@ -2000,11 +2008,13 @@ static void add_depends(struct buffer *b
static void add_srcversion(struct buffer *b, struct module *mod)
{
+#ifndef CONFIG_MODULE_STRIPPED
if (mod->srcversion[0]) {
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
mod->srcversion);
}
+#endif
}
static void write_buf(struct buffer *b, const char *fname)
@@ -2087,7 +2097,9 @@ static void write_mod_c_file(struct modu
add_exported_symbols(&buf, mod);
add_versions(&buf, mod);
add_depends(&buf, mod);
+#ifndef CONFIG_MODULE_STRIPPED
add_moddevtable(&buf, mod);
+#endif
add_srcversion(&buf, mod);
ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);

View file

@ -0,0 +1,41 @@
From 310e8e04a05d9eb43fa9dd7f00143300afcaa37a Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Fri, 11 Nov 2022 13:33:44 +0100
Subject: [PATCH] kconfig: abort configuration on unset symbol
When a target configuration has unset Kconfig symbols, the build will
fail when OpenWrt is compiled with V=s and stdin is connected to a tty.
In case OpenWrt is compiled without either of these preconditions, the
build will succeed with the symbols in question being unset.
Modify the kernel configuration in a way it fails on unset symbols
regardless of the aforementioned preconditions.
Signed-off-by: David Bauer <mail@david-bauer.net>
---
scripts/kconfig/conf.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -338,6 +338,9 @@ static int conf_askvalue(struct symbol *
}
/* fall through */
default:
+ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) {
+ exit(1);
+ }
fflush(stdout);
xfgets(line, sizeof(line), stdin);
break;
@@ -520,6 +523,9 @@ static int conf_choice(struct menu *menu
}
/* fall through */
case oldaskconfig:
+ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) {
+ exit(1);
+ }
fflush(stdout);
xfgets(line, sizeof(line), stdin);
strip(line);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
From e44fc2af1ddc452b6659d08c16973d65c73b7d0a Mon Sep 17 00:00:00 2001
From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
Date: Wed, 5 Feb 2020 18:36:43 +0000
Subject: [PATCH] file2alias: build on macos
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
---
scripts/mod/file2alias.c | 3 +++
1 file changed, 3 insertions(+)
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -35,6 +35,9 @@ typedef uint32_t __u32;
typedef uint16_t __u16;
typedef unsigned char __u8;
+#ifdef __APPLE__
+#define uuid_t compat_uuid_t
+#endif
/* UUID types for backward compatibility, don't use in new code */
typedef struct {
__u8 b[16];

View file

@ -0,0 +1,24 @@
From be9be95ff10e16a5b4ad36f903978d0cc5747024 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 7 Jul 2017 17:04:08 +0200
Subject: kernel: fix linux/spi/spidev.h portability issues with musl
Felix will try to get this define included into musl
lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/uapi/linux/spi/spidev.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/include/uapi/linux/spi/spidev.h
+++ b/include/uapi/linux/spi/spidev.h
@@ -93,7 +93,7 @@ struct spi_ioc_transfer {
/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
#define SPI_MSGSIZE(N) \
- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
+ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])

View file

@ -0,0 +1,38 @@
From b3d00b452467f621317953d9e4c6f9ae8dcfd271 Mon Sep 17 00:00:00 2001
From: Imre Kaloz <kaloz@openwrt.org>
Date: Fri, 7 Jul 2017 17:06:55 +0200
Subject: use the openwrt lzma options for now
lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
lib/decompress.c | 1 +
scripts/Makefile.lib | 2 +-
usr/gen_initramfs_list.sh | 10 +++++-----
3 files changed, 7 insertions(+), 6 deletions(-)
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -53,6 +53,7 @@ static const struct compress_format comp
{ {0x1f, 0x9e}, "gzip", gunzip },
{ {0x42, 0x5a}, "bzip2", bunzip2 },
{ {0x5d, 0x00}, "lzma", unlzma },
+ { {0x6d, 0x00}, "lzma-openwrt", unlzma },
{ {0xfd, 0x37}, "xz", unxz },
{ {0x89, 0x4c}, "lzo", unlzo },
{ {0x02, 0x21}, "lz4", unlz4 },
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -456,10 +456,10 @@ quiet_cmd_bzip2_with_size = BZIP2 $@
# ---------------------------------------------------------------------------
quiet_cmd_lzma = LZMA $@
- cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@
+ cmd_lzma = cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so > $@
quiet_cmd_lzma_with_size = LZMA $@
- cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@
+ cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@
quiet_cmd_lzo = LZO $@
cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@

View file

@ -0,0 +1,27 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: hack: net: remove bogus netfilter dependencies
lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/netfilter/Kconfig | 2 --
1 file changed, 2 deletions(-)
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -259,7 +259,6 @@ config NF_CONNTRACK_FTP
config NF_CONNTRACK_H323
tristate "H.323 protocol support"
- depends on IPV6 || IPV6=n
depends on NETFILTER_ADVANCED
help
H.323 is a VoIP signalling protocol from ITU-T. As one of the most
@@ -1120,7 +1119,6 @@ config NETFILTER_XT_TARGET_SECMARK
config NETFILTER_XT_TARGET_TCPMSS
tristate '"TCPMSS" target support'
- depends on IPV6 || IPV6=n
default m if NETFILTER_ADVANCED=n
help
This option adds a `TCPMSS' target, which allows you to alter the

View file

@ -0,0 +1,157 @@
From da3c50704f14132f4adf80d48e9a4cd5d46e54c9 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Fri, 7 Jul 2017 17:09:21 +0200
Subject: kconfig: owrt specifc dependencies
Signed-off-by: John Crispin <john@phrozen.org>
---
crypto/Kconfig | 10 +++++-----
drivers/bcma/Kconfig | 1 +
drivers/ssb/Kconfig | 3 ++-
lib/Kconfig | 8 ++++----
net/netfilter/Kconfig | 2 +-
net/wireless/Kconfig | 17 ++++++++++-------
sound/core/Kconfig | 4 ++--
7 files changed, 25 insertions(+), 20 deletions(-)
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -55,7 +55,7 @@ config CRYPTO_FIPS_VERSION
By default the KERNELRELEASE value is used.
config CRYPTO_ALGAPI
- tristate
+ tristate "ALGAPI"
select CRYPTO_ALGAPI2
help
This option provides the API for cryptographic algorithms.
@@ -64,7 +64,7 @@ config CRYPTO_ALGAPI2
tristate
config CRYPTO_AEAD
- tristate
+ tristate "AEAD"
select CRYPTO_AEAD2
select CRYPTO_ALGAPI
@@ -82,7 +82,7 @@ config CRYPTO_SIG2
select CRYPTO_ALGAPI2
config CRYPTO_SKCIPHER
- tristate
+ tristate "SKCIPHER"
select CRYPTO_SKCIPHER2
select CRYPTO_ALGAPI
@@ -91,7 +91,7 @@ config CRYPTO_SKCIPHER2
select CRYPTO_ALGAPI2
config CRYPTO_HASH
- tristate
+ tristate "HASH"
select CRYPTO_HASH2
select CRYPTO_ALGAPI
@@ -100,7 +100,7 @@ config CRYPTO_HASH2
select CRYPTO_ALGAPI2
config CRYPTO_RNG
- tristate
+ tristate "RNG"
select CRYPTO_RNG2
select CRYPTO_ALGAPI
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -16,6 +16,7 @@ if BCMA
# Support for Block-I/O. SELECT this from the driver that needs it.
config BCMA_BLOCKIO
bool
+ default y
config BCMA_HOST_PCI_POSSIBLE
bool
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -29,6 +29,7 @@ config SSB_SPROM
config SSB_BLOCKIO
bool
depends on SSB
+ default y
config SSB_PCIHOST_POSSIBLE
bool
@@ -49,7 +50,7 @@ config SSB_PCIHOST
config SSB_B43_PCI_BRIDGE
bool
depends on SSB_PCIHOST
- default n
+ default y
config SSB_PCMCIAHOST_POSSIBLE
bool
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -460,16 +460,16 @@ config BCH_CONST_T
# Textsearch support is select'ed if needed
#
config TEXTSEARCH
- bool
+ bool "Textsearch support"
config TEXTSEARCH_KMP
- tristate
+ tristate "Textsearch KMP"
config TEXTSEARCH_BM
- tristate
+ tristate "Textsearch BM"
config TEXTSEARCH_FSM
- tristate
+ tristate "Textsearch FSM"
config BTREE
bool
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -22,7 +22,7 @@ config NETFILTER_SKIP_EGRESS
def_bool NETFILTER_EGRESS && (NET_CLS_ACT || IFB)
config NETFILTER_NETLINK
- tristate
+ tristate "Netfilter NFNETLINK interface"
config NETFILTER_FAMILY_BRIDGE
bool
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM
tristate
config SND_HWDEP
- tristate
+ tristate "Sound hardware support"
config SND_SEQ_DEVICE
tristate
@@ -40,7 +40,7 @@ config SND_UMP_LEGACY_RAWMIDI
The device contains 16 substreams corresponding to UMP groups.
config SND_COMPRESS_OFFLOAD
- tristate
+ tristate "Compression offloading support"
config SND_JACK
bool
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -467,7 +467,7 @@ config NET_DEVLINK
default n
config PAGE_POOL
- bool
+ bool "Page pool support"
config PAGE_POOL_STATS
default n

View file

@ -0,0 +1,32 @@
From dcd966fa7ca63f38cf7147e1184d13d66e2ca340 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 13:33:30 +0200
Subject: [PATCH] Kconfig: add tristate for OID and ASNI string
---
init/Kconfig | 2 +-
lib/Kconfig | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1989,7 +1989,7 @@ config PADATA
bool
config ASN1
- tristate
+ tristate "ASN1"
help
Build a simple ASN.1 grammar compiler that produces a bytecode output
that can be interpreted by the ASN.1 stream decoder and used to
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -647,7 +647,7 @@ config LIBFDT
bool
config OID_REGISTRY
- tristate
+ tristate "OID"
help
Enable fast lookup object identifier registry.

View file

@ -0,0 +1,156 @@
From 811d9e2268a62b830cfe93cd8bc929afcb8b198b Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 15 Jul 2017 21:12:38 +0200
Subject: kernel: move regmap bloat out of the kernel image if it is only being used in modules
lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/base/regmap/Kconfig | 15 ++++++++++-----
drivers/base/regmap/Makefile | 12 ++++++++----
drivers/base/regmap/regmap.c | 3 +++
include/linux/regmap.h | 2 +-
4 files changed, 22 insertions(+), 10 deletions(-)
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -4,8 +4,7 @@
# subsystems should select the appropriate symbols.
config REGMAP
- bool
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI)
+ tristate
select IRQ_DOMAIN if REGMAP_IRQ
select MDIO_BUS if REGMAP_MDIO
help
@@ -19,7 +18,7 @@ config REGMAP
config REGMAP_KUNIT
tristate "KUnit tests for regmap"
- depends on KUNIT && REGMAP
+ depends on KUNIT
default KUNIT_ALL_TESTS
select REGMAP_RAM
@@ -34,60 +33,76 @@ config REGMAP_BUILD
normally enabled.
config REGMAP_AC97
+ select REGMAP
tristate
config REGMAP_I2C
+ select REGMAP
tristate
depends on I2C
config REGMAP_SLIMBUS
+ select REGMAP
tristate
depends on SLIMBUS
config REGMAP_SPI
+ select REGMAP
tristate
depends on SPI
config REGMAP_SPMI
+ select REGMAP
tristate
depends on SPMI
config REGMAP_W1
+ select REGMAP
tristate
depends on W1
config REGMAP_MDIO
+ select REGMAP
tristate
config REGMAP_MMIO
+ select REGMAP
tristate
config REGMAP_IRQ
+ select REGMAP
bool
config REGMAP_RAM
+ select REGMAP
tristate
config REGMAP_SOUNDWIRE
+ select REGMAP
tristate
depends on SOUNDWIRE
config REGMAP_SOUNDWIRE_MBQ
+ select REGMAP
tristate
depends on SOUNDWIRE
config REGMAP_SCCB
+ select REGMAP
tristate
depends on I2C
config REGMAP_I3C
+ select REGMAP
tristate
depends on I3C
config REGMAP_SPI_AVMM
+ select REGMAP
tristate
depends on SPI
config REGMAP_FSI
+ select REGMAP
tristate
depends on FSI
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -2,9 +2,11 @@
# For include/trace/define_trace.h to include trace.h
CFLAGS_regmap.o := -I$(src)
-obj-$(CONFIG_REGMAP) += regmap.o regcache.o
-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o regcache-maple.o
-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
+regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o regcache-maple.o
+ifdef CONFIG_DEBUG_FS
+regmap-core-objs += regmap-debugfs.o
+endif
+obj-$(CONFIG_REGMAP) += regmap-core.o
obj-$(CONFIG_REGMAP_KUNIT) += regmap-kunit.o
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/property.h>
@@ -3470,3 +3471,5 @@ static int __init regmap_initcall(void)
return 0;
}
postcore_initcall(regmap_initcall);
+
+MODULE_LICENSE("GPL");
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -197,7 +197,7 @@ struct reg_sequence {
__ret ?: __tmp; \
})
-#ifdef CONFIG_REGMAP
+#if IS_REACHABLE(CONFIG_REGMAP)
enum regmap_endian {
/* Unspecified -> 0 -> Backwards compatible default */

View file

@ -0,0 +1,54 @@
From fd1799b0bf5efa46dd3e6dfbbf3955564807e508 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 7 Jul 2017 17:12:51 +0200
Subject: kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run
Reduces kernel size after LZMA by about 5k on MIPS
lede-commit: 044c316167e076479a344c59905e5b435b84a77f
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
crypto/Kconfig | 13 ++++++-------
crypto/algboss.c | 4 ++++
2 files changed, 10 insertions(+), 7 deletions(-)
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -148,15 +148,15 @@ config CRYPTO_MANAGER
cbc(aes).
config CRYPTO_MANAGER2
- def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
- select CRYPTO_ACOMP2
- select CRYPTO_AEAD2
- select CRYPTO_AKCIPHER2
- select CRYPTO_SIG2
- select CRYPTO_HASH2
- select CRYPTO_KPP2
- select CRYPTO_RNG2
- select CRYPTO_SKCIPHER2
+ def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS)
+ select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_SIG2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_RNG2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ select CRYPTO_SKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
config CRYPTO_USER
tristate "Userspace cryptographic algorithm configuration"
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -204,6 +204,10 @@ static int cryptomgr_schedule_test(struc
memcpy(param->alg, alg->cra_name, sizeof(param->alg));
param->type = alg->cra_flags;
+#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
+ param->type |= CRYPTO_ALG_TESTED;
+#endif
+
thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
if (IS_ERR(thread))
goto err_free_param;

View file

@ -0,0 +1,24 @@
From 241e5d3f7b0dd3c01f8c7fa83cbc9a3882286d53 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 13:35:18 +0200
Subject: [PATCH] lib/crypto: add tristate string for ARC4
This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We
need this to be able to compile this into the kernel and make use of it
from backports.
---
lib/crypto/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -15,7 +15,7 @@ config CRYPTO_LIB_AESGCM
select CRYPTO_LIB_UTILS
config CRYPTO_LIB_ARC4
- tristate
+ tristate "ARC4 cipher library"
config CRYPTO_LIB_GF128MUL
tristate

View file

@ -0,0 +1,84 @@
From 236c1acdfef5958010ac9814a9872e0a46fd78ee Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Fri, 7 Jul 2017 17:13:44 +0200
Subject: rfkill: add fake rfkill support
allow building of modules depending on RFKILL even if RFKILL is not enabled.
Signed-off-by: John Crispin <john@phrozen.org>
---
include/linux/rfkill.h | 2 +-
net/Makefile | 2 +-
net/rfkill/Kconfig | 14 +++++++++-----
net/rfkill/Makefile | 2 +-
4 files changed, 12 insertions(+), 8 deletions(-)
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -64,7 +64,7 @@ struct rfkill_ops {
int (*set_block)(void *data, bool blocked);
};
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE)
/**
* rfkill_alloc - Allocate rfkill structure
* @name: name of the struct -- the string is not copied internally
--- a/net/Makefile
+++ b/net/Makefile
@@ -52,7 +52,7 @@ obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
obj-$(CONFIG_IUCV) += iucv/
obj-$(CONFIG_SMC) += smc/
-obj-$(CONFIG_RFKILL) += rfkill/
+obj-$(CONFIG_RFKILL_FULL) += rfkill/
obj-$(CONFIG_NET_9P) += 9p/
obj-$(CONFIG_CAIF) += caif/
obj-$(CONFIG_DCB) += dcb/
--- a/net/rfkill/Kconfig
+++ b/net/rfkill/Kconfig
@@ -2,7 +2,11 @@
#
# RF switch subsystem configuration
#
-menuconfig RFKILL
+config RFKILL
+ bool
+ default y
+
+menuconfig RFKILL_FULL
tristate "RF switch subsystem support"
help
Say Y here if you want to have control over RF switches
@@ -14,19 +18,19 @@ menuconfig RFKILL
# LED trigger support
config RFKILL_LEDS
bool
- depends on RFKILL
+ depends on RFKILL_FULL
depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
default y
config RFKILL_INPUT
bool "RF switch input support" if EXPERT
- depends on RFKILL
+ depends on RFKILL_FULL
depends on INPUT = y || RFKILL = INPUT
default y if !EXPERT
config RFKILL_GPIO
tristate "GPIO RFKILL driver"
- depends on RFKILL
+ depends on RFKILL_FULL
depends on GPIOLIB || COMPILE_TEST
default n
help
--- a/net/rfkill/Makefile
+++ b/net/rfkill/Makefile
@@ -5,5 +5,5 @@
rfkill-y += core.o
rfkill-$(CONFIG_RFKILL_INPUT) += input.o
-obj-$(CONFIG_RFKILL) += rfkill.o
+obj-$(CONFIG_RFKILL_FULL) += rfkill.o
obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o

View file

@ -0,0 +1,64 @@
From: Ben Menchaca <ben.menchaca@qca.qualcomm.com>
Date: Fri, 7 Jun 2013 18:35:22 -0500
Subject: MIPS: r4k_cache: use more efficient cache blast
Optimize the compiler output for larger cache blast cases that are
common for DMA-based networking.
Signed-off-by: Ben Menchaca <ben.menchaca@qca.qualcomm.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/arch/mips/include/asm/r4kcache.h
+++ b/arch/mips/include/asm/r4kcache.h
@@ -286,14 +286,46 @@ static inline void prot##extra##blast_##
unsigned long end) \
{ \
unsigned long lsize = cpu_##desc##_line_size(); \
+ unsigned long lsize_2 = lsize * 2; \
+ unsigned long lsize_3 = lsize * 3; \
+ unsigned long lsize_4 = lsize * 4; \
+ unsigned long lsize_5 = lsize * 5; \
+ unsigned long lsize_6 = lsize * 6; \
+ unsigned long lsize_7 = lsize * 7; \
+ unsigned long lsize_8 = lsize * 8; \
unsigned long addr = start & ~(lsize - 1); \
- unsigned long aend = (end - 1) & ~(lsize - 1); \
+ unsigned long aend = (end + lsize - 1) & ~(lsize - 1); \
+ int lines = (aend - addr) / lsize; \
\
- while (1) { \
+ while (lines >= 8) { \
+ prot##cache_op(hitop, addr); \
+ prot##cache_op(hitop, addr + lsize); \
+ prot##cache_op(hitop, addr + lsize_2); \
+ prot##cache_op(hitop, addr + lsize_3); \
+ prot##cache_op(hitop, addr + lsize_4); \
+ prot##cache_op(hitop, addr + lsize_5); \
+ prot##cache_op(hitop, addr + lsize_6); \
+ prot##cache_op(hitop, addr + lsize_7); \
+ addr += lsize_8; \
+ lines -= 8; \
+ } \
+ \
+ if (lines & 0x4) { \
+ prot##cache_op(hitop, addr); \
+ prot##cache_op(hitop, addr + lsize); \
+ prot##cache_op(hitop, addr + lsize_2); \
+ prot##cache_op(hitop, addr + lsize_3); \
+ addr += lsize_4; \
+ } \
+ \
+ if (lines & 0x2) { \
+ prot##cache_op(hitop, addr); \
+ prot##cache_op(hitop, addr + lsize); \
+ addr += lsize_2; \
+ } \
+ \
+ if (lines & 0x1) { \
prot##cache_op(hitop, addr); \
- if (addr == aend) \
- break; \
- addr += lsize; \
} \
}

View file

@ -0,0 +1,112 @@
From 0bccc3722bdd88e8ae995e77ef9f7b77ee4cbdee Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 7 Apr 2021 22:45:54 +0100
Subject: [PATCH 2/2] mtd: blktrans: call add disks after mtd device
To: linux-mtd@lists.infradead.org
Cc: Vignesh Raghavendra <vigneshr@ti.com>,
Richard Weinberger <richard@nod.at>,
Miquel Raynal <miquel.raynal@bootlin.com>,
David Woodhouse <dwmw2@infradead.org>
Calling device_add_disk while holding mtd_table_mutex leads
to deadlock in case part_bits!=0 as block partition parsers
will try to open the newly created disks, trying to acquire
mutex once again.
Move device_add_disk to additional function called after
add partitions of an MTD device have been added and locks
have been released.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/mtd_blkdevs.c | 33 ++++++++++++++++++++++++++-------
drivers/mtd/mtdcore.c | 3 +++
include/linux/mtd/blktrans.h | 1 +
3 files changed, 30 insertions(+), 7 deletions(-)
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -386,19 +386,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt
if (new->readonly)
set_disk_ro(gd, 1);
- ret = device_add_disk(&new->mtd->dev, gd, NULL);
- if (ret)
- goto out_cleanup_disk;
-
- if (new->disk_attributes) {
- ret = sysfs_create_group(&disk_to_dev(gd)->kobj,
- new->disk_attributes);
- WARN_ON(ret);
- }
return 0;
-out_cleanup_disk:
- put_disk(new->disk);
out_free_tag_set:
blk_mq_free_tag_set(new->tag_set);
out_kfree_tag_set:
@@ -408,6 +397,35 @@ out_list_del:
return ret;
}
+void register_mtd_blktrans_devs(void)
+{
+ struct mtd_blktrans_ops *tr;
+ struct mtd_blktrans_dev *dev, *next;
+ int ret;
+
+ list_for_each_entry(tr, &blktrans_majors, list) {
+ list_for_each_entry_safe(dev, next, &tr->devs, list) {
+ if (disk_live(dev->disk))
+ continue;
+
+ ret = device_add_disk(&dev->mtd->dev, dev->disk, NULL);
+ if (ret)
+ goto out_cleanup_disk;
+
+ if (dev->disk_attributes) {
+ ret = sysfs_create_group(&disk_to_dev(dev->disk)->kobj,
+ dev->disk_attributes);
+ WARN_ON(ret);
+ }
+ }
+ }
+
+ return;
+
+out_cleanup_disk:
+ put_disk(dev->disk);
+}
+
int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
{
unsigned long flags;
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -33,6 +33,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/blktrans.h>
#include "mtdcore.h"
@@ -1127,6 +1128,8 @@ int mtd_device_parse_register(struct mtd
register_reboot_notifier(&mtd->reboot_notifier);
}
+ register_mtd_blktrans_devs();
+
out:
if (ret) {
nvmem_unregister(mtd->otp_user_nvmem);
--- a/include/linux/mtd/blktrans.h
+++ b/include/linux/mtd/blktrans.h
@@ -76,6 +76,7 @@ extern int deregister_mtd_blktrans(struc
extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev);
+extern void register_mtd_blktrans_devs(void);
/**
* module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver

View file

@ -0,0 +1,120 @@
From 6fa9e3678eb002246df1280322b6a024853950a5 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Mon, 11 Oct 2021 00:53:14 +0200
Subject: [PATCH] drivers: mtd: parsers: add nvmem support to cmdlinepart
Assuming cmdlinepart is only one level deep partition scheme and that
static partition are also defined in DTS, we can assign an of_node for
partition declared from bootargs. cmdlinepart have priority than
fiexed-partition parser so in this specific case the parser doesn't
assign an of_node. Fix this by searching a defined of_node using a
similar fixed_partition parser and if a partition is found with the same
label, check that it has the same offset and size and return the DT
of_node to correctly use NVMEM cells.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
drivers/mtd/parsers/cmdlinepart.c | 71 +++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
--- a/drivers/mtd/parsers/cmdlinepart.c
+++ b/drivers/mtd/parsers/cmdlinepart.c
@@ -43,6 +43,7 @@
#include <linux/mtd/partitions.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/of.h>
/* debug macro */
#if 0
@@ -323,6 +324,68 @@ static int mtdpart_setup_real(char *s)
return 0;
}
+static int search_fixed_partition(struct mtd_info *master,
+ struct mtd_partition *target_part,
+ struct mtd_partition *fixed_part)
+{
+ struct device_node *mtd_node;
+ struct device_node *ofpart_node;
+ struct device_node *pp;
+ struct mtd_partition part;
+ const char *partname;
+
+ mtd_node = mtd_get_of_node(master);
+ if (!mtd_node)
+ return -EINVAL;
+
+ ofpart_node = of_get_child_by_name(mtd_node, "partitions");
+
+ for_each_child_of_node(ofpart_node, pp) {
+ const __be32 *reg;
+ int len;
+ int a_cells, s_cells;
+
+ reg = of_get_property(pp, "reg", &len);
+ if (!reg) {
+ pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
+ master->name, pp,
+ mtd_node);
+ continue;
+ }
+
+ a_cells = of_n_addr_cells(pp);
+ s_cells = of_n_size_cells(pp);
+ if (len / 4 != a_cells + s_cells) {
+ pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
+ master->name, pp,
+ mtd_node);
+ continue;
+ }
+
+ part.offset = of_read_number(reg, a_cells);
+ part.size = of_read_number(reg + a_cells, s_cells);
+ part.of_node = pp;
+
+ partname = of_get_property(pp, "label", &len);
+ if (!partname)
+ partname = of_get_property(pp, "name", &len);
+ part.name = partname;
+
+ if (!strncmp(target_part->name, part.name, len)) {
+ if (part.offset != target_part->offset)
+ return -EINVAL;
+
+ if (part.size != target_part->size)
+ return -EINVAL;
+
+ memcpy(fixed_part, &part, sizeof(struct mtd_partition));
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
/*
* Main function to be called from the MTD mapping driver/device to
* obtain the partitioning information. At this point the command line
@@ -338,6 +401,7 @@ static int parse_cmdline_partitions(stru
int i, err;
struct cmdline_mtd_partition *part;
const char *mtd_id = master->name;
+ struct mtd_partition fixed_part;
/* parse command line */
if (!cmdline_parsed) {
@@ -382,6 +446,13 @@ static int parse_cmdline_partitions(stru
sizeof(*part->parts) * (part->num_parts - i));
i--;
}
+
+ err = search_fixed_partition(master, &part->parts[i], &fixed_part);
+ if (!err) {
+ part->parts[i].of_node = fixed_part.of_node;
+ pr_info("Found partition defined in DT for %s. Assigning OF node to support nvmem.",
+ part->parts[i].name);
+ }
}
*pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,

View file

@ -0,0 +1,33 @@
From ac84397efb3b3868c71c10ad7521161773228a17 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 13:41:44 +0200
Subject: [PATCH] mtd/nand: add MediaTek NAND bad block managment table
---
drivers/mtd/nand/Kconfig | 4 ++++
drivers/mtd/nand/Makefile | 1 +
2 files changed, 5 insertions(+)
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -46,6 +46,10 @@ config MTD_NAND_ECC_SW_BCH
ECC codes. They are used with NAND devices requiring more than 1 bit
of error correction.
+config MTD_NAND_MTK_BMT
+ bool "Support MediaTek NAND Bad-block Management Table"
+ default n
+
config MTD_NAND_ECC_MXIC
bool "Macronix external hardware ECC engine"
depends on HAS_IOMEM
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -3,6 +3,7 @@
nandcore-objs := core.o bbt.o
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o
+obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o
obj-y += onenand/
obj-y += raw/

View file

@ -0,0 +1,24 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 23 Apr 2024 12:35:21 +0200
Subject: [PATCH] net: enable fraglist GRO by default
This can significantly improve performance for packet forwarding/bridging
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -242,10 +242,10 @@ static inline int find_next_netdev_featu
#define NETIF_F_UPPER_DISABLES NETIF_F_LRO
/* changeable features with no special hardware requirements */
-#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO)
+#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO | NETIF_F_GRO_FRAGLIST)
/* Changeable features with no special hardware requirements that defaults to off. */
-#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_FRAGLIST | NETIF_F_GRO_UDP_FWD)
+#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_UDP_FWD)
#define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \
NETIF_F_HW_VLAN_CTAG_RX | \

View file

@ -0,0 +1,214 @@
From eda40b8c8c82e0f2789d6bc8bf63846dce2e8f32 Mon Sep 17 00:00:00 2001
From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
Date: Sat, 23 Mar 2019 09:29:49 +0000
Subject: [PATCH] netfilter: connmark: introduce set-dscpmark
set-dscpmark is a method of storing the DSCP of an ip packet into
conntrack mark. In combination with a suitable tc filter action
(act_ctinfo) DSCP values are able to be stored in the mark on egress and
restored on ingress across links that otherwise alter or bleach DSCP.
This is useful for qdiscs such as CAKE which are able to shape according
to policies based on DSCP.
Ingress classification is traditionally a challenging task since
iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT
lookups, hence are unable to see internal IPv4 addresses as used on the
typical home masquerading gateway.
x_tables CONNMARK set-dscpmark target solves the problem of storing the
DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc
action to restore.
The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a
32bit 'statemask'. The dscp mask must be 6 contiguous bits and
represents the area where the DSCP will be stored in the connmark. The
state mask is a minimum 1 bit length mask that must not overlap with the
dscpmask. It represents a flag which is set when the DSCP has been
stored in the conntrack mark. This is useful to implement a 'one shot'
iptables based classification where the 'complicated' iptables rules are
only run once to classify the connection on initial (egress) packet and
subsequent packets are all marked/restored with the same DSCP. A state
mask of zero disables the setting of a status bit/s.
example syntax with a suitably modified iptables user space application:
iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000
Would store the DSCP in the top 6 bits of the 32bit mark field, and use
the LSB of the top byte as the 'DSCP has been stored' marker.
|----0xFC----conntrack mark----000000---|
| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
| DSCP | unused | flag |unused |
|-----------------------0x01---000000---|
^ ^
| |
---| Conditional flag
| set this when dscp
|-ip diffserv-| stored in mark
| 6 bits |
|-------------|
an identically configured tc action to restore looks like:
tc filter show dev eth0 ingress
filter parent ffff: protocol all pref 10 u32 chain 0
filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1
filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw
match 00000000/00000000 at 0
action order 1: ctinfo zone 0 pipe
index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000
action order 2: mirred (Egress Redirect to device ifb4eth0) stolen
index 1 ref 1 bind 1
|----0xFC----conntrack mark----000000---|
| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
| DSCP | unused | flag |unused |
|-----------------------0x01---000000---|
| |
| |
---| Conditional flag
v only restore if set
|-ip diffserv-|
| 6 bits |
|-------------|
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
---
include/uapi/linux/netfilter/xt_connmark.h | 10 ++++
net/netfilter/xt_connmark.c | 55 ++++++++++++++++++----
2 files changed, 57 insertions(+), 8 deletions(-)
--- a/include/uapi/linux/netfilter/xt_connmark.h
+++ b/include/uapi/linux/netfilter/xt_connmark.h
@@ -15,6 +15,11 @@ enum {
};
enum {
+ XT_CONNMARK_VALUE = (1 << 0),
+ XT_CONNMARK_DSCP = (1 << 1)
+};
+
+enum {
D_SHIFT_LEFT = 0,
D_SHIFT_RIGHT,
};
@@ -29,6 +34,11 @@ struct xt_connmark_tginfo2 {
__u8 shift_dir, shift_bits, mode;
};
+struct xt_connmark_tginfo3 {
+ __u32 ctmark, ctmask, nfmask;
+ __u8 shift_dir, shift_bits, mode, func;
+};
+
struct xt_connmark_mtinfo1 {
__u32 mark, mask;
__u8 invert;
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -24,13 +24,13 @@ MODULE_ALIAS("ipt_connmark");
MODULE_ALIAS("ip6t_connmark");
static unsigned int
-connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
+connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info)
{
enum ip_conntrack_info ctinfo;
u_int32_t new_targetmark;
struct nf_conn *ct;
u_int32_t newmark;
- u_int32_t oldmark;
+ u_int8_t dscp;
ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL)
@@ -38,13 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, c
switch (info->mode) {
case XT_CONNMARK_SET:
- oldmark = READ_ONCE(ct->mark);
- newmark = (oldmark & ~info->ctmask) ^ info->ctmark;
- if (info->shift_dir == D_SHIFT_RIGHT)
- newmark >>= info->shift_bits;
- else
- newmark <<= info->shift_bits;
+ newmark = READ_ONCE(ct->mark);
+ if (info->func & XT_CONNMARK_VALUE) {
+ newmark = (newmark & ~info->ctmask) ^ info->ctmark;
+ if (info->shift_dir == D_SHIFT_RIGHT)
+ newmark >>= info->shift_bits;
+ else
+ newmark <<= info->shift_bits;
+ } else if (info->func & XT_CONNMARK_DSCP) {
+ if (skb->protocol == htons(ETH_P_IP))
+ dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
+ else /* protocol doesn't have diffserv */
+ break;
+ newmark = (newmark & ~info->ctmark) |
+ (info->ctmask | (dscp << info->shift_bits));
+ }
if (READ_ONCE(ct->mark) != newmark) {
WRITE_ONCE(ct->mark, newmark);
nf_conntrack_event_cache(IPCT_MARK, ct);
@@ -83,20 +94,36 @@ static unsigned int
connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_connmark_tginfo1 *info = par->targinfo;
- const struct xt_connmark_tginfo2 info2 = {
+ const struct xt_connmark_tginfo3 info3 = {
.ctmark = info->ctmark,
.ctmask = info->ctmask,
.nfmask = info->nfmask,
.mode = info->mode,
+ .func = XT_CONNMARK_VALUE
};
- return connmark_tg_shift(skb, &info2);
+ return connmark_tg_shift(skb, &info3);
}
static unsigned int
connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_connmark_tginfo2 *info = par->targinfo;
+ const struct xt_connmark_tginfo3 info3 = {
+ .ctmark = info->ctmark,
+ .ctmask = info->ctmask,
+ .nfmask = info->nfmask,
+ .mode = info->mode,
+ .func = XT_CONNMARK_VALUE
+ };
+
+ return connmark_tg_shift(skb, &info3);
+}
+
+static unsigned int
+connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct xt_connmark_tginfo3 *info = par->targinfo;
return connmark_tg_shift(skb, info);
}
@@ -167,6 +194,16 @@ static struct xt_target connmark_tg_reg[
.targetsize = sizeof(struct xt_connmark_tginfo2),
.destroy = connmark_tg_destroy,
.me = THIS_MODULE,
+ },
+ {
+ .name = "CONNMARK",
+ .revision = 3,
+ .family = NFPROTO_UNSPEC,
+ .checkentry = connmark_tg_check,
+ .target = connmark_tg_v3,
+ .targetsize = sizeof(struct xt_connmark_tginfo3),
+ .destroy = connmark_tg_destroy,
+ .me = THIS_MODULE,
}
};

View file

@ -0,0 +1,812 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 20 Feb 2018 15:56:02 +0100
Subject: [PATCH] netfilter: add xt_FLOWOFFLOAD target
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
create mode 100644 net/netfilter/xt_OFFLOAD.c
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -729,7 +729,6 @@ config NF_FLOW_TABLE
tristate "Netfilter flow table module"
depends on NETFILTER_INGRESS
depends on NF_CONNTRACK
- depends on NF_TABLES
help
This option adds the flow table core infrastructure.
@@ -1025,6 +1024,15 @@ config NETFILTER_XT_TARGET_NOTRACK
depends on NETFILTER_ADVANCED
select NETFILTER_XT_TARGET_CT
+config NETFILTER_XT_TARGET_FLOWOFFLOAD
+ tristate '"FLOWOFFLOAD" target support'
+ depends on NF_FLOW_TABLE
+ depends on NETFILTER_INGRESS
+ help
+ This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload
+ module to speed up processing of packets by bypassing the usual
+ netfilter chains
+
config NETFILTER_XT_TARGET_RATEEST
tristate '"RATEEST" target support'
depends on NETFILTER_ADVANCED
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -163,6 +163,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o
obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
--- /dev/null
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/xt_FLOWOFFLOAD.h>
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_flow_table.h>
+
+struct xt_flowoffload_hook {
+ struct hlist_node list;
+ struct nf_hook_ops ops;
+ struct net *net;
+ bool registered;
+ bool used;
+};
+
+struct xt_flowoffload_table {
+ struct nf_flowtable ft;
+ struct hlist_head hooks;
+ struct delayed_work work;
+};
+
+struct nf_forward_info {
+ const struct net_device *indev;
+ const struct net_device *outdev;
+ const struct net_device *hw_outdev;
+ struct id {
+ __u16 id;
+ __be16 proto;
+ } encap[NF_FLOW_TABLE_ENCAP_MAX];
+ u8 num_encaps;
+ u8 ingress_vlans;
+ u8 h_source[ETH_ALEN];
+ u8 h_dest[ETH_ALEN];
+ enum flow_offload_xmit_type xmit_type;
+};
+
+static DEFINE_SPINLOCK(hooks_lock);
+
+struct xt_flowoffload_table flowtable[2];
+
+static unsigned int
+xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
+{
+ struct vlan_ethhdr *veth;
+ __be16 proto;
+
+ switch (skb->protocol) {
+ case htons(ETH_P_8021Q):
+ veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+ proto = veth->h_vlan_encapsulated_proto;
+ break;
+ case htons(ETH_P_PPP_SES):
+ if (!nf_flow_pppoe_proto(skb, &proto))
+ return NF_ACCEPT;
+ break;
+ default:
+ proto = skb->protocol;
+ break;
+ }
+
+ switch (proto) {
+ case htons(ETH_P_IP):
+ return nf_flow_offload_ip_hook(priv, skb, state);
+ case htons(ETH_P_IPV6):
+ return nf_flow_offload_ipv6_hook(priv, skb, state);
+ }
+
+ return NF_ACCEPT;
+}
+
+static int
+xt_flowoffload_create_hook(struct xt_flowoffload_table *table,
+ struct net_device *dev)
+{
+ struct xt_flowoffload_hook *hook;
+ struct nf_hook_ops *ops;
+
+ hook = kzalloc(sizeof(*hook), GFP_ATOMIC);
+ if (!hook)
+ return -ENOMEM;
+
+ ops = &hook->ops;
+ ops->pf = NFPROTO_NETDEV;
+ ops->hooknum = NF_NETDEV_INGRESS;
+ ops->priority = 10;
+ ops->priv = &table->ft;
+ ops->hook = xt_flowoffload_net_hook;
+ ops->dev = dev;
+
+ hlist_add_head(&hook->list, &table->hooks);
+ mod_delayed_work(system_power_efficient_wq, &table->work, 0);
+
+ return 0;
+}
+
+static struct xt_flowoffload_hook *
+flow_offload_lookup_hook(struct xt_flowoffload_table *table,
+ struct net_device *dev)
+{
+ struct xt_flowoffload_hook *hook;
+
+ hlist_for_each_entry(hook, &table->hooks, list) {
+ if (hook->ops.dev == dev)
+ return hook;
+ }
+
+ return NULL;
+}
+
+static void
+xt_flowoffload_check_device(struct xt_flowoffload_table *table,
+ struct net_device *dev)
+{
+ struct xt_flowoffload_hook *hook;
+
+ if (!dev)
+ return;
+
+ spin_lock_bh(&hooks_lock);
+ hook = flow_offload_lookup_hook(table, dev);
+ if (hook)
+ hook->used = true;
+ else
+ xt_flowoffload_create_hook(table, dev);
+ spin_unlock_bh(&hooks_lock);
+}
+
+static void
+xt_flowoffload_register_hooks(struct xt_flowoffload_table *table)
+{
+ struct xt_flowoffload_hook *hook;
+
+restart:
+ hlist_for_each_entry(hook, &table->hooks, list) {
+ if (hook->registered)
+ continue;
+
+ hook->registered = true;
+ hook->net = dev_net(hook->ops.dev);
+ spin_unlock_bh(&hooks_lock);
+ nf_register_net_hook(hook->net, &hook->ops);
+ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD)
+ table->ft.type->setup(&table->ft, hook->ops.dev,
+ FLOW_BLOCK_BIND);
+ spin_lock_bh(&hooks_lock);
+ goto restart;
+ }
+
+}
+
+static bool
+xt_flowoffload_cleanup_hooks(struct xt_flowoffload_table *table)
+{
+ struct xt_flowoffload_hook *hook;
+ bool active = false;
+
+restart:
+ spin_lock_bh(&hooks_lock);
+ hlist_for_each_entry(hook, &table->hooks, list) {
+ if (hook->used || !hook->registered) {
+ active = true;
+ continue;
+ }
+
+ hlist_del(&hook->list);
+ spin_unlock_bh(&hooks_lock);
+ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD)
+ table->ft.type->setup(&table->ft, hook->ops.dev,
+ FLOW_BLOCK_UNBIND);
+ nf_unregister_net_hook(hook->net, &hook->ops);
+ kfree(hook);
+ goto restart;
+ }
+ spin_unlock_bh(&hooks_lock);
+
+ return active;
+}
+
+static void
+xt_flowoffload_check_hook(struct nf_flowtable *flowtable,
+ struct flow_offload *flow, void *data)
+{
+ struct xt_flowoffload_table *table;
+ struct flow_offload_tuple *tuple0 = &flow->tuplehash[0].tuple;
+ struct flow_offload_tuple *tuple1 = &flow->tuplehash[1].tuple;
+ struct xt_flowoffload_hook *hook;
+
+ table = container_of(flowtable, struct xt_flowoffload_table, ft);
+
+ spin_lock_bh(&hooks_lock);
+ hlist_for_each_entry(hook, &table->hooks, list) {
+ if (hook->ops.dev->ifindex != tuple0->iifidx &&
+ hook->ops.dev->ifindex != tuple1->iifidx)
+ continue;
+
+ hook->used = true;
+ }
+ spin_unlock_bh(&hooks_lock);
+}
+
+static void
+xt_flowoffload_hook_work(struct work_struct *work)
+{
+ struct xt_flowoffload_table *table;
+ struct xt_flowoffload_hook *hook;
+ int err;
+
+ table = container_of(work, struct xt_flowoffload_table, work.work);
+
+ spin_lock_bh(&hooks_lock);
+ xt_flowoffload_register_hooks(table);
+ hlist_for_each_entry(hook, &table->hooks, list)
+ hook->used = false;
+ spin_unlock_bh(&hooks_lock);
+
+ err = nf_flow_table_iterate(&table->ft, xt_flowoffload_check_hook,
+ NULL);
+ if (err && err != -EAGAIN)
+ goto out;
+
+ if (!xt_flowoffload_cleanup_hooks(table))
+ return;
+
+out:
+ queue_delayed_work(system_power_efficient_wq, &table->work, HZ);
+}
+
+static bool
+xt_flowoffload_skip(struct sk_buff *skb, int family)
+{
+ if (skb_sec_path(skb))
+ return true;
+
+ if (family == NFPROTO_IPV4) {
+ const struct ip_options *opt = &(IPCB(skb)->opt);
+
+ if (unlikely(opt->optlen))
+ return true;
+ }
+
+ return false;
+}
+
+static enum flow_offload_xmit_type nf_xmit_type(struct dst_entry *dst)
+{
+ if (dst_xfrm(dst))
+ return FLOW_OFFLOAD_XMIT_XFRM;
+
+ return FLOW_OFFLOAD_XMIT_NEIGH;
+}
+
+static void nf_default_forward_path(struct nf_flow_route *route,
+ struct dst_entry *dst_cache,
+ enum ip_conntrack_dir dir,
+ struct net_device **dev)
+{
+ dev[!dir] = dst_cache->dev;
+ route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex;
+ route->tuple[dir].dst = dst_cache;
+ route->tuple[dir].xmit_type = nf_xmit_type(dst_cache);
+}
+
+static bool nf_is_valid_ether_device(const struct net_device *dev)
+{
+ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER ||
+ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr))
+ return false;
+
+ return true;
+}
+
+static void nf_dev_path_info(const struct net_device_path_stack *stack,
+ struct nf_forward_info *info,
+ unsigned char *ha)
+{
+ const struct net_device_path *path;
+ int i;
+
+ memcpy(info->h_dest, ha, ETH_ALEN);
+
+ for (i = 0; i < stack->num_paths; i++) {
+ path = &stack->path[i];
+ switch (path->type) {
+ case DEV_PATH_ETHERNET:
+ case DEV_PATH_DSA:
+ case DEV_PATH_VLAN:
+ case DEV_PATH_PPPOE:
+ info->indev = path->dev;
+ if (is_zero_ether_addr(info->h_source))
+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
+
+ if (path->type == DEV_PATH_ETHERNET)
+ break;
+ if (path->type == DEV_PATH_DSA) {
+ i = stack->num_paths;
+ break;
+ }
+
+ /* DEV_PATH_VLAN and DEV_PATH_PPPOE */
+ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
+ info->indev = NULL;
+ break;
+ }
+ if (!info->outdev)
+ info->outdev = path->dev;
+ info->encap[info->num_encaps].id = path->encap.id;
+ info->encap[info->num_encaps].proto = path->encap.proto;
+ info->num_encaps++;
+ if (path->type == DEV_PATH_PPPOE)
+ memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
+ break;
+ case DEV_PATH_BRIDGE:
+ if (is_zero_ether_addr(info->h_source))
+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
+
+ switch (path->bridge.vlan_mode) {
+ case DEV_PATH_BR_VLAN_UNTAG_HW:
+ info->ingress_vlans |= BIT(info->num_encaps - 1);
+ break;
+ case DEV_PATH_BR_VLAN_TAG:
+ info->encap[info->num_encaps].id = path->bridge.vlan_id;
+ info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
+ info->num_encaps++;
+ break;
+ case DEV_PATH_BR_VLAN_UNTAG:
+ info->num_encaps--;
+ break;
+ case DEV_PATH_BR_VLAN_KEEP:
+ break;
+ }
+ break;
+ default:
+ info->indev = NULL;
+ break;
+ }
+ }
+ if (!info->outdev)
+ info->outdev = info->indev;
+
+ info->hw_outdev = info->indev;
+
+ if (nf_is_valid_ether_device(info->indev))
+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
+}
+
+static int nf_dev_fill_forward_path(const struct nf_flow_route *route,
+ const struct dst_entry *dst_cache,
+ const struct nf_conn *ct,
+ enum ip_conntrack_dir dir, u8 *ha,
+ struct net_device_path_stack *stack)
+{
+ const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
+ struct net_device *dev = dst_cache->dev;
+ struct neighbour *n;
+ u8 nud_state;
+
+ if (!nf_is_valid_ether_device(dev))
+ goto out;
+
+ n = dst_neigh_lookup(dst_cache, daddr);
+ if (!n)
+ return -1;
+
+ read_lock_bh(&n->lock);
+ nud_state = n->nud_state;
+ ether_addr_copy(ha, n->ha);
+ read_unlock_bh(&n->lock);
+ neigh_release(n);
+
+ if (!(nud_state & NUD_VALID))
+ return -1;
+
+out:
+ return dev_fill_forward_path(dev, ha, stack);
+}
+
+static void nf_dev_forward_path(struct nf_flow_route *route,
+ const struct nf_conn *ct,
+ enum ip_conntrack_dir dir,
+ struct net_device **devs)
+{
+ const struct dst_entry *dst = route->tuple[dir].dst;
+ struct net_device_path_stack stack;
+ struct nf_forward_info info = {};
+ unsigned char ha[ETH_ALEN];
+ int i;
+
+ if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
+ nf_dev_path_info(&stack, &info, ha);
+
+ devs[!dir] = (struct net_device *)info.indev;
+ if (!info.indev)
+ return;
+
+ route->tuple[!dir].in.ifindex = info.indev->ifindex;
+ for (i = 0; i < info.num_encaps; i++) {
+ route->tuple[!dir].in.encap[i].id = info.encap[i].id;
+ route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
+ }
+ route->tuple[!dir].in.num_encaps = info.num_encaps;
+ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
+
+ if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
+ memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
+ memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
+ route->tuple[dir].out.ifindex = info.outdev->ifindex;
+ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
+ route->tuple[dir].xmit_type = info.xmit_type;
+ }
+}
+
+static int
+xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct,
+ const struct xt_action_param *par,
+ struct nf_flow_route *route, enum ip_conntrack_dir dir,
+ struct net_device **devs)
+{
+ struct dst_entry *this_dst = skb_dst(skb);
+ struct dst_entry *other_dst = NULL;
+ struct flowi fl;
+
+ memset(&fl, 0, sizeof(fl));
+ switch (xt_family(par)) {
+ case NFPROTO_IPV4:
+ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
+ fl.u.ip4.flowi4_oif = xt_in(par)->ifindex;
+ break;
+ case NFPROTO_IPV6:
+ fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.dst.u3.in6;
+ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
+ fl.u.ip6.flowi6_oif = xt_in(par)->ifindex;
+ break;
+ }
+
+ if (!dst_hold_safe(this_dst))
+ return -ENOENT;
+
+ nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par));
+ if (!other_dst) {
+ dst_release(this_dst);
+ return -ENOENT;
+ }
+
+ nf_default_forward_path(route, this_dst, dir, devs);
+ nf_default_forward_path(route, other_dst, !dir, devs);
+
+ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
+ route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
+ nf_dev_forward_path(route, ct, dir, devs);
+ nf_dev_forward_path(route, ct, !dir, devs);
+ }
+
+ return 0;
+}
+
+static unsigned int
+flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ struct xt_flowoffload_table *table;
+ const struct xt_flowoffload_target_info *info = par->targinfo;
+ struct tcphdr _tcph, *tcph = NULL;
+ enum ip_conntrack_info ctinfo;
+ enum ip_conntrack_dir dir;
+ struct nf_flow_route route = {};
+ struct flow_offload *flow = NULL;
+ struct net_device *devs[2] = {};
+ struct nf_conn *ct;
+ struct net *net;
+
+ if (xt_flowoffload_skip(skb, xt_family(par)))
+ return XT_CONTINUE;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct == NULL)
+ return XT_CONTINUE;
+
+ switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
+ case IPPROTO_TCP:
+ if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
+ return XT_CONTINUE;
+
+ tcph = skb_header_pointer(skb, par->thoff,
+ sizeof(_tcph), &_tcph);
+ if (unlikely(!tcph || tcph->fin || tcph->rst))
+ return XT_CONTINUE;
+ break;
+ case IPPROTO_UDP:
+ break;
+ default:
+ return XT_CONTINUE;
+ }
+
+ if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
+ ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH))
+ return XT_CONTINUE;
+
+ if (!nf_ct_is_confirmed(ct))
+ return XT_CONTINUE;
+
+ dir = CTINFO2DIR(ctinfo);
+
+ devs[dir] = xt_out(par);
+ devs[!dir] = xt_in(par);
+
+ if (!devs[dir] || !devs[!dir])
+ return XT_CONTINUE;
+
+ if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
+ return XT_CONTINUE;
+
+ if (xt_flowoffload_route(skb, ct, par, &route, dir, devs) < 0)
+ goto err_flow_route;
+
+ flow = flow_offload_alloc(ct);
+ if (!flow)
+ goto err_flow_alloc;
+
+ flow_offload_route_init(flow, &route);
+
+ if (tcph) {
+ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
+ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
+ }
+
+ table = &flowtable[!!(info->flags & XT_FLOWOFFLOAD_HW)];
+
+ net = read_pnet(&table->ft.net);
+ if (!net)
+ write_pnet(&table->ft.net, xt_net(par));
+
+ __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags);
+ if (flow_offload_add(&table->ft, flow) < 0)
+ goto err_flow_add;
+
+ xt_flowoffload_check_device(table, devs[0]);
+ xt_flowoffload_check_device(table, devs[1]);
+
+ return XT_CONTINUE;
+
+err_flow_add:
+ flow_offload_free(flow);
+err_flow_alloc:
+ dst_release(route.tuple[dir].dst);
+ dst_release(route.tuple[!dir].dst);
+err_flow_route:
+ clear_bit(IPS_OFFLOAD_BIT, &ct->status);
+
+ return XT_CONTINUE;
+}
+
+static int flowoffload_chk(const struct xt_tgchk_param *par)
+{
+ struct xt_flowoffload_target_info *info = par->targinfo;
+
+ if (info->flags & ~XT_FLOWOFFLOAD_MASK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct xt_target offload_tg_reg __read_mostly = {
+ .family = NFPROTO_UNSPEC,
+ .name = "FLOWOFFLOAD",
+ .revision = 0,
+ .targetsize = sizeof(struct xt_flowoffload_target_info),
+ .usersize = sizeof(struct xt_flowoffload_target_info),
+ .checkentry = flowoffload_chk,
+ .target = flowoffload_tg,
+ .me = THIS_MODULE,
+};
+
+static int flow_offload_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct xt_flowoffload_hook *hook0, *hook1;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+ if (event != NETDEV_UNREGISTER)
+ return NOTIFY_DONE;
+
+ spin_lock_bh(&hooks_lock);
+ hook0 = flow_offload_lookup_hook(&flowtable[0], dev);
+ if (hook0)
+ hlist_del(&hook0->list);
+
+ hook1 = flow_offload_lookup_hook(&flowtable[1], dev);
+ if (hook1)
+ hlist_del(&hook1->list);
+ spin_unlock_bh(&hooks_lock);
+
+ if (hook0) {
+ nf_unregister_net_hook(hook0->net, &hook0->ops);
+ kfree(hook0);
+ }
+
+ if (hook1) {
+ nf_unregister_net_hook(hook1->net, &hook1->ops);
+ kfree(hook1);
+ }
+
+ nf_flow_table_cleanup(dev);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block flow_offload_netdev_notifier = {
+ .notifier_call = flow_offload_netdev_event,
+};
+
+static int nf_flow_rule_route_inet(struct net *net,
+ struct flow_offload *flow,
+ enum flow_offload_tuple_dir dir,
+ struct nf_flow_rule *flow_rule)
+{
+ const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
+ int err;
+
+ switch (flow_tuple->l3proto) {
+ case NFPROTO_IPV4:
+ err = nf_flow_rule_route_ipv4(net, flow, dir, flow_rule);
+ break;
+ case NFPROTO_IPV6:
+ err = nf_flow_rule_route_ipv6(net, flow, dir, flow_rule);
+ break;
+ default:
+ err = -1;
+ break;
+ }
+
+ return err;
+}
+
+static struct nf_flowtable_type flowtable_inet = {
+ .family = NFPROTO_INET,
+ .init = nf_flow_table_init,
+ .setup = nf_flow_table_offload_setup,
+ .action = nf_flow_rule_route_inet,
+ .free = nf_flow_table_free,
+ .hook = xt_flowoffload_net_hook,
+ .owner = THIS_MODULE,
+};
+
+static int init_flowtable(struct xt_flowoffload_table *tbl)
+{
+ INIT_DELAYED_WORK(&tbl->work, xt_flowoffload_hook_work);
+ tbl->ft.type = &flowtable_inet;
+ tbl->ft.flags = NF_FLOWTABLE_COUNTER;
+
+ return nf_flow_table_init(&tbl->ft);
+}
+
+static int __init xt_flowoffload_tg_init(void)
+{
+ int ret;
+
+ register_netdevice_notifier(&flow_offload_netdev_notifier);
+
+ ret = init_flowtable(&flowtable[0]);
+ if (ret)
+ return ret;
+
+ ret = init_flowtable(&flowtable[1]);
+ if (ret)
+ goto cleanup;
+
+ flowtable[1].ft.flags |= NF_FLOWTABLE_HW_OFFLOAD;
+
+ ret = xt_register_target(&offload_tg_reg);
+ if (ret)
+ goto cleanup2;
+
+ return 0;
+
+cleanup2:
+ nf_flow_table_free(&flowtable[1].ft);
+cleanup:
+ nf_flow_table_free(&flowtable[0].ft);
+ return ret;
+}
+
+static void __exit xt_flowoffload_tg_exit(void)
+{
+ xt_unregister_target(&offload_tg_reg);
+ unregister_netdevice_notifier(&flow_offload_netdev_notifier);
+ nf_flow_table_free(&flowtable[0].ft);
+ nf_flow_table_free(&flowtable[1].ft);
+}
+
+MODULE_LICENSE("GPL");
+module_init(xt_flowoffload_tg_init);
+module_exit(xt_flowoffload_tg_exit);
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -7,7 +7,6 @@
#include <linux/netdevice.h>
#include <net/ip.h>
#include <net/ip6_route.h>
-#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_flow_table.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
@@ -377,8 +376,7 @@ flow_offload_lookup(struct nf_flowtable
}
EXPORT_SYMBOL_GPL(flow_offload_lookup);
-static int
-nf_flow_table_iterate(struct nf_flowtable *flow_table,
+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
void (*iter)(struct nf_flowtable *flowtable,
struct flow_offload *flow, void *data),
void *data)
@@ -439,6 +437,7 @@ static void nf_flow_offload_gc_step(stru
nf_flow_offload_stats(flow_table, flow);
}
}
+EXPORT_SYMBOL_GPL(nf_flow_table_iterate);
void nf_flow_table_gc_run(struct nf_flowtable *flow_table)
{
--- /dev/null
+++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _XT_FLOWOFFLOAD_H
+#define _XT_FLOWOFFLOAD_H
+
+#include <linux/types.h>
+
+enum {
+ XT_FLOWOFFLOAD_HW = 1 << 0,
+
+ XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW
+};
+
+struct xt_flowoffload_target_info {
+ __u32 flags;
+};
+
+#endif /* _XT_FLOWOFFLOAD_H */
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -293,6 +293,11 @@ void nf_flow_table_free(struct nf_flowta
void flow_offload_teardown(struct flow_offload *flow);
+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
+ void (*iter)(struct nf_flowtable *flowtable,
+ struct flow_offload *flow, void *data),
+ void *data);
+
void nf_flow_snat_port(const struct flow_offload *flow,
struct sk_buff *skb, unsigned int thoff,
u8 protocol, enum flow_offload_tuple_dir dir);

View file

@ -0,0 +1,24 @@
From 6d3bc769657b0ee7c7506dad9911111c4226a7ea Mon Sep 17 00:00:00 2001
From: Imre Kaloz <kaloz@openwrt.org>
Date: Fri, 7 Jul 2017 17:21:05 +0200
Subject: mac80211: increase wireless mesh header size
lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
include/linux/netdevice.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -157,8 +157,8 @@ static inline bool dev_xmit_complete(int
#if defined(CONFIG_HYPERV_NET)
# define LL_MAX_HEADER 128
-#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
-# if defined(CONFIG_MAC80211_MESH)
+#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1
+# if defined(CONFIG_MAC80211_MESH) || 1
# define LL_MAX_HEADER 128
# else
# define LL_MAX_HEADER 96

View file

@ -0,0 +1,27 @@
From a6ccb238939b25851474a279b20367fd24a0e816 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 7 Jul 2017 17:21:53 +0200
Subject: hack: net: fq_codel: tune defaults for small devices
Assume that x86_64 devices always have a big memory and do not need this
optimization compared to devices with only 32 MB or 64 MB RAM.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/sched/sch_fq_codel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -471,7 +471,11 @@ static int fq_codel_init(struct Qdisc *s
sch->limit = 10*1024;
q->flows_cnt = 1024;
+#ifdef CONFIG_X86_64
q->memory_limit = 32 << 20; /* 32 MBytes */
+#else
+ q->memory_limit = 4 << 20; /* 4 MBytes */
+#endif
q->drop_batch_size = 64;
q->quantum = psched_mtu(qdisc_dev(sch));
INIT_LIST_HEAD(&q->new_flows);

View file

@ -0,0 +1,25 @@
From 804fbb3f2ec9283f7b778e057a68bfff440a0be6 Mon Sep 17 00:00:00 2001
From: Rui Salvaterra <rsalvaterra@gmail.com>
Date: Wed, 30 Mar 2022 22:51:55 +0100
Subject: [PATCH] kernel: ct: size the hashtable more adequately
To set the default size of the connection tracking hash table, a divider of
16384 becomes inadequate for a router handling lots of connections. Divide by
2048 instead, making the default size scale better with the available RAM.
Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
---
net/netfilter/nf_conntrack_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -2682,7 +2682,7 @@ int nf_conntrack_init_start(void)
if (!nf_conntrack_htable_size) {
nf_conntrack_htable_size
- = (((nr_pages << PAGE_SHIFT) / 16384)
+ = (((nr_pages << PAGE_SHIFT) / 2048)
/ sizeof(struct hlist_head));
if (BITS_PER_LONG >= 64 &&
nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE)))

View file

@ -0,0 +1,21 @@
From ebd924d773223593142d417c41d4ee6fa16f1805 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 13:45:56 +0200
Subject: [PATCH] net/dsa/mv88e6xxx: disable ATU violation
---
drivers/net/dsa/mv88e6xxx/chip.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3375,6 +3375,9 @@ static int mv88e6xxx_setup_port(struct m
else
reg = 1 << port;
+ /* Disable ATU member violation interrupt */
+ reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG;
+
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
reg);
if (err)

View file

@ -0,0 +1,117 @@
From 5f62951fba63a9f9cfff564209426bdea5fcc371 Mon Sep 17 00:00:00 2001
From: Alex Marginean <alexandru.marginean@nxp.com>
Date: Tue, 27 Aug 2019 15:16:56 +0300
Subject: [PATCH] drivers: net: phy: aquantia: enable AQR112 and AQR412
Adds support for AQR112 and AQR412 which is mostly based on existing code
with the addition of code configuring the protocol on system side.
This allows changing the system side protocol without having to deploy a
different firmware on the PHY.
Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
---
drivers/net/phy/aquantia/aquantia_main.c | 88 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
@@ -127,6 +127,29 @@ struct aqr107_priv {
u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
};
+/* registers in MDIO_MMD_VEND1 region */
+#define AQUANTIA_VND1_GLOBAL_SC 0x000
+#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb)
+
+/* global start rate, the protocol associated with this speed is used by default
+ * on SI.
+ */
+#define AQUANTIA_VND1_GSTART_RATE 0x31a
+#define AQUANTIA_VND1_GSTART_RATE_OFF 0
+#define AQUANTIA_VND1_GSTART_RATE_100M 1
+#define AQUANTIA_VND1_GSTART_RATE_1G 2
+#define AQUANTIA_VND1_GSTART_RATE_10G 3
+#define AQUANTIA_VND1_GSTART_RATE_2_5G 4
+#define AQUANTIA_VND1_GSTART_RATE_5G 5
+
+/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */
+#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b
+#define AQUANTIA_VND1_GSYSCFG_100M 0
+#define AQUANTIA_VND1_GSYSCFG_1G 1
+#define AQUANTIA_VND1_GSYSCFG_2_5G 2
+#define AQUANTIA_VND1_GSYSCFG_5G 3
+#define AQUANTIA_VND1_GSYSCFG_10G 4
+
static int aqr107_get_sset_count(struct phy_device *phydev)
{
return AQR107_SGMII_STAT_SZ;
@@ -233,6 +256,51 @@ static int aqr_config_aneg(struct phy_de
return genphy_c45_check_and_restart_aneg(phydev, changed);
}
+static struct {
+ u16 syscfg;
+ int cnt;
+ u16 start_rate;
+} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = {
+ [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G,
+ AQUANTIA_VND1_GSTART_RATE_1G},
+ [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
+ AQUANTIA_VND1_GSTART_RATE_2_5G},
+ [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G,
+ AQUANTIA_VND1_GSTART_RATE_10G},
+ [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G,
+ AQUANTIA_VND1_GSTART_RATE_10G},
+};
+
+/* Sets up protocol on system side before calling aqr_config_aneg */
+static int aqr_config_aneg_set_prot(struct phy_device *phydev)
+{
+ int if_type = phydev->interface;
+ int i;
+
+ if (!aquantia_syscfg[if_type].cnt)
+ return 0;
+
+ /* set PHY in low power mode so we can configure protocols */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC,
+ AQUANTIA_VND1_GLOBAL_SC_LP);
+ mdelay(10);
+
+ /* set the default rate to enable the SI link */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
+ aquantia_syscfg[if_type].start_rate);
+
+ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ AQUANTIA_VND1_GSYSCFG_BASE + i,
+ aquantia_syscfg[if_type].syscfg);
+
+ /* wake PHY back up */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
+ mdelay(10);
+
+ return aqr_config_aneg(phydev);
+}
+
static int aqr_config_intr(struct phy_device *phydev)
{
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
@@ -838,7 +906,7 @@ static struct phy_driver aqr_driver[] =
PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
.name = "Aquantia AQR112",
.probe = aqr107_probe,
- .config_aneg = aqr_config_aneg,
+ .config_aneg = aqr_config_aneg_set_prot,
.config_intr = aqr_config_intr,
.handle_interrupt = aqr_handle_interrupt,
.get_tunable = aqr107_get_tunable,
@@ -863,7 +931,7 @@ static struct phy_driver aqr_driver[] =
PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
.name = "Aquantia AQR412",
.probe = aqr107_probe,
- .config_aneg = aqr_config_aneg,
+ .config_aneg = aqr_config_aneg_set_prot,
.config_intr = aqr_config_intr,
.handle_interrupt = aqr_handle_interrupt,
.get_tunable = aqr107_get_tunable,

View file

@ -0,0 +1,34 @@
From 5f008cb22f60da4e10375f22266c1a4e20b1252e Mon Sep 17 00:00:00 2001
From: Alex Marginean <alexandru.marginean@nxp.com>
Date: Fri, 20 Sep 2019 18:22:52 +0300
Subject: [PATCH] drivers: net: phy: aquantia: fix system side protocol
misconfiguration
Do not set up protocols for speeds that are not supported by FW. Enabling
these protocols leads to link issues on system side.
Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
---
drivers/net/phy/aquantia/aquantia_main.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
@@ -289,10 +289,16 @@ static int aqr_config_aneg_set_prot(stru
phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
aquantia_syscfg[if_type].start_rate);
- for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
+ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) {
+ u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ AQUANTIA_VND1_GSYSCFG_BASE + i);
+ if (!reg)
+ continue;
+
phy_write_mmd(phydev, MDIO_MMD_VEND1,
AQUANTIA_VND1_GSYSCFG_BASE + i,
aquantia_syscfg[if_type].syscfg);
+ }
/* wake PHY back up */
phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);

View file

@ -0,0 +1,63 @@
From 3b92ee7b7899b6beffb2b484c58326e36612a873 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 23 Dec 2021 14:52:56 +0000
Subject: [PATCH] net: phy: aquantia: add PHY_ID for AQR112R
As advised by Ian Chang this PHY is used in Puzzle devices.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/aquantia/aquantia_main.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
@@ -30,6 +30,8 @@
#define PHY_ID_AQR113C 0x31c31c12
#define PHY_ID_AQR114C 0x31c31c22
#define PHY_ID_AQR813 0x31c31cb2
+#define PHY_ID_AQR112C 0x03a1b790
+#define PHY_ID_AQR112R 0x31c31d12
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
@@ -1062,6 +1064,30 @@ static struct phy_driver aqr_driver[] =
.led_polarity_set = aqr_phy_led_polarity_set,
#endif
},
+{
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112C),
+ .name = "Aquantia AQR112C",
+ .probe = aqr107_probe,
+ .config_aneg = aqr_config_aneg_set_prot,
+ .config_intr = aqr_config_intr,
+ .handle_interrupt = aqr_handle_interrupt,
+ .read_status = aqr107_read_status,
+ .get_sset_count = aqr107_get_sset_count,
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+},
+{
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112R),
+ .name = "Aquantia AQR112R",
+ .probe = aqr107_probe,
+ .config_aneg = aqr_config_aneg_set_prot,
+ .config_intr = aqr_config_intr,
+ .handle_interrupt = aqr_handle_interrupt,
+ .read_status = aqr107_read_status,
+ .get_sset_count = aqr107_get_sset_count,
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+},
};
module_phy_driver(aqr_driver);
@@ -1082,6 +1108,8 @@ static struct mdio_device_id __maybe_unu
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) },
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) },
{ }
};

View file

@ -0,0 +1,74 @@
From 82985725e071f2a5735052f18e109a32aeac3a0b Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Sun, 26 Jul 2020 02:38:31 +0200
Subject: [PATCH] net: usb: r8152: add LED configuration from OF
This adds the ability to configure the LED configuration register using
OF. This way, the correct value for board specific LED configuration can
be determined.
Signed-off-by: David Bauer <mail@david-bauer.net>
---
drivers/net/usb/r8152.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -11,6 +11,7 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/usb.h>
+#include <linux/of.h>
#include <linux/crc32.h>
#include <linux/if_vlan.h>
#include <linux/uaccess.h>
@@ -7035,6 +7036,22 @@ static void rtl_tally_reset(struct r8152
ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
}
+static int r8152_led_configuration(struct r8152 *tp)
+{
+ u32 led_data;
+ int ret;
+
+ ret = of_property_read_u32(tp->udev->dev.of_node, "realtek,led-data",
+ &led_data);
+
+ if (ret)
+ return ret;
+
+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LEDSEL, led_data);
+
+ return 0;
+}
+
static void r8152b_init(struct r8152 *tp)
{
u32 ocp_data;
@@ -7076,6 +7093,8 @@ static void r8152b_init(struct r8152 *tp
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+ r8152_led_configuration(tp);
}
static void r8153_init(struct r8152 *tp)
@@ -7216,6 +7235,8 @@ static void r8153_init(struct r8152 *tp)
tp->coalesce = COALESCE_SLOW;
break;
}
+
+ r8152_led_configuration(tp);
}
static void r8153b_init(struct r8152 *tp)
@@ -7298,6 +7319,8 @@ static void r8153b_init(struct r8152 *tp
rtl_tally_reset(tp);
tp->coalesce = 15000; /* 15 us */
+
+ r8152_led_configuration(tp);
}
static void r8153c_init(struct r8152 *tp)

View file

@ -0,0 +1,54 @@
From 3ee05f4aa64fc86af3be5bc176ba5808de9260a7 Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Sun, 26 Jul 2020 15:30:33 +0200
Subject: [PATCH] dt-bindings: net: add RTL8152 binding documentation
Add binding documentation for the Realtek RTL8152 / RTL8153 USB ethernet
adapters.
Signed-off-by: David Bauer <mail@david-bauer.net>
---
.../bindings/net/realtek,rtl8152.yaml | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl8152.yaml
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/realtek,rtl8152.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Realtek RTL8152/RTL8153 series USB ethernet
+
+maintainers:
+ - David Bauer <mail@david-bauer.net>
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - realtek,rtl8152
+ - realtek,rtl8153
+
+ reg:
+ description: The device number on the USB bus
+
+ realtek,led-data:
+ description: Value to be written to the LED configuration register.
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ usb-eth@2 {
+ compatible = "realtek,rtl8153";
+ reg = <2>;
+ realtek,led-data = <0x87>;
+ };
\ No newline at end of file

View file

@ -0,0 +1,72 @@
From cc225d163b5a4f7a0d1968298bf7927306646a47 Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Fri, 28 Apr 2023 01:53:01 +0200
Subject: [PATCH] net: phy: mediatek-ge: add LED configuration interface
This adds a small hack similar to the one used for ar8xxx switches to
read a reg:value map for configuring the LED configuration registers.
This allows OpenWrt to write device-specific LED action as well as blink
configurations. It is unlikely to be accepted upstream, as upstream
plans on integrating their own framework for handling these LEDs.
Signed-off-by: David Bauer <mail@david-bauer.net>
---
drivers/net/phy/mediatek-ge.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
--- a/drivers/net/phy/mediatek-ge.c
+++ b/drivers/net/phy/mediatek-ge.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
+#include <linux/of.h>
#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/phy.h>
@@ -53,6 +54,36 @@ static int mt7530_phy_config_init(struct
return 0;
}
+static int mt7530_led_config_of(struct phy_device *phydev)
+{
+ struct device_node *np = phydev->mdio.dev.of_node;
+ const __be32 *paddr;
+ int len;
+ int i;
+
+ paddr = of_get_property(np, "mediatek,led-config", &len);
+ if (!paddr)
+ return 0;
+
+ if (len < (2 * sizeof(*paddr)))
+ return -EINVAL;
+
+ len /= sizeof(*paddr);
+
+ phydev_warn(phydev, "Configure LED registers (num=%d)\n", len);
+ for (i = 0; i < len - 1; i += 2) {
+ u32 reg;
+ u32 val;
+
+ reg = be32_to_cpup(paddr + i);
+ val = be32_to_cpup(paddr + i + 1);
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val);
+ }
+
+ return 0;
+}
+
static int mt7531_phy_config_init(struct phy_device *phydev)
{
mtk_gephy_config_init(phydev);
@@ -65,6 +96,9 @@ static int mt7531_phy_config_init(struct
phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
+ /* LED Config*/
+ mt7530_led_config_of(phydev);
+
return 0;
}

View file

@ -0,0 +1,98 @@
From 3cb240533ab787899dc7f17aa7d6c5b4810e2e58 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Fri, 7 Jul 2017 17:26:01 +0200
Subject: bcm53xx: bgmac: use srab switch driver
use the srab switch driver on these SoCs.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/bgmac-bcma.c | 1 +
drivers/net/ethernet/broadcom/bgmac.c | 24 ++++++++++++++++++++++++
drivers/net/ethernet/broadcom/bgmac.h | 4 ++++
3 files changed, 29 insertions(+)
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
@@ -280,6 +280,7 @@ static int bgmac_probe(struct bcma_devic
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
+ bgmac->feature_flags |= BGMAC_FEAT_SRAB;
break;
default:
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -12,6 +12,7 @@
#include <linux/bcma/bcma.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
+#include <linux/platform_data/b53.h>
#include <linux/bcm47xx_nvram.h>
#include <linux/phy.h>
#include <linux/phy_fixed.h>
@@ -1408,6 +1409,17 @@ static const struct ethtool_ops bgmac_et
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
+static struct b53_platform_data bgmac_b53_pdata = {
+};
+
+static struct platform_device bgmac_b53_dev = {
+ .name = "b53-srab-switch",
+ .id = -1,
+ .dev = {
+ .platform_data = &bgmac_b53_pdata,
+ },
+};
+
/**************************************************
* MII
**************************************************/
@@ -1546,6 +1558,14 @@ int bgmac_enet_probe(struct bgmac *bgmac
bgmac->in_init = false;
+ if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) {
+ bgmac_b53_pdata.regs = ioremap(0x18007000, 0x1000);
+
+ err = platform_device_register(&bgmac_b53_dev);
+ if (!err)
+ bgmac->b53_device = &bgmac_b53_dev;
+ }
+
err = register_netdev(bgmac->net_dev);
if (err) {
dev_err(bgmac->dev, "Cannot register net device\n");
@@ -1568,6 +1588,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe);
void bgmac_enet_remove(struct bgmac *bgmac)
{
+ if (bgmac->b53_device)
+ platform_device_unregister(&bgmac_b53_dev);
+ bgmac->b53_device = NULL;
+
unregister_netdev(bgmac->net_dev);
phy_disconnect(bgmac->net_dev->phydev);
netif_napi_del(&bgmac->napi);
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -388,6 +388,7 @@
#define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18)
#define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19)
#define BGMAC_FEAT_IDM_MASK BIT(20)
+#define BGMAC_FEAT_SRAB BIT(21)
struct bgmac_slot_info {
union {
@@ -495,6 +496,9 @@ struct bgmac {
void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
u32 set);
int (*phy_connect)(struct bgmac *bgmac);
+
+ /* platform device for associated switch */
+ struct platform_device *b53_device;
};
struct bgmac *bgmac_alloc(struct device *dev);

View file

@ -0,0 +1,69 @@
From f81700b6bb2eda3756247bce472d8eaf6f466f61 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 13:49:26 +0200
Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support
---
drivers/net/usb/qmi_wwan.c | 1 +
drivers/usb/serial/option.c | 7 +++++++
2 files changed, 8 insertions(+)
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1083,12 +1083,18 @@ static const struct usb_device_id produc
USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* Meiglink SGM828 */
+ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49, USB_CLASS_VENDOR_SPEC, 0x10, 0x05),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
+
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */
+ {QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)}, /* MeigLink SLM750 */
/* 3. Combined interface devices matching on interface number */
{QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -247,6 +247,11 @@ static void option_instat_callback(struc
#define UBLOX_PRODUCT_R410M 0x90b2
/* These Yuga products use Qualcomm's vendor ID */
#define YUGA_PRODUCT_CLM920_NC5 0x9625
+/* These MeigLink products use Qualcomm's vendor ID */
+#define MEIGLINK_PRODUCT_SLM750 0xf601
+
+#define MEIGLINK_VENDOR_ID 0x2dee
+#define MEIGLINK_PRODUCT_SLM828 0x4d49
#define QUECTEL_VENDOR_ID 0x2c7c
/* These Quectel products use Quectel's vendor ID */
@@ -1156,6 +1161,11 @@ static const struct usb_device_id option
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */
.driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) },
+ /* MeiG */
+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x02) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x03) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x04) },
/* Quectel products using Qualcomm vendor ID */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
@@ -1197,6 +1207,11 @@ static const struct usb_device_id option
.driver_info = ZLP },
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
.driver_info = RSVD(4) },
+ /* Meiglink products using Qualcomm vendor ID */
+ // Works OK. In case of some issues check macros that are used by Quectel Products
+ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0xff, 0xff),
+ .driver_info = NUMEP2 },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },

View file

@ -0,0 +1,69 @@
From 9fabf60187f1fa19e6f6bb5441587d485bd534b0 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 9 Apr 2024 17:06:38 +0100
Subject: [PATCH] rndis_host: add a bunch of USB IDs
Add a bunch of USB IDs found in various places online to the
RNDIS USB network driver.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/usb/rndis_host.c | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -630,6 +630,16 @@ static const struct driver_info zte_rndi
.tx_fixup = rndis_tx_fixup,
};
+static const struct driver_info asr_rndis_info = {
+ .description = "Asr RNDIS device",
+ .flags = FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT | FLAG_NOARP,
+ .bind = rndis_bind,
+ .unbind = rndis_unbind,
+ .status = rndis_status,
+ .rx_fixup = rndis_rx_fixup,
+ .tx_fixup = rndis_tx_fixup,
+};
+
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
@@ -666,6 +676,36 @@ static const struct usb_device_id produc
USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
.driver_info = (unsigned long) &rndis_info,
}, {
+ /* Quectel EG060V rndis device */
+ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6004,
+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
+ .driver_info = (unsigned long) &asr_rndis_info,
+}, {
+ /* Quectel EC200A rndis device */
+ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6005,
+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
+ .driver_info = (unsigned long) &asr_rndis_info,
+}, {
+ /* Quectel EC200T rndis device */
+ USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6026,
+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
+ .driver_info = (unsigned long) &asr_rndis_info,
+}, {
+ /* Simcom A7906E rndis device */
+ USB_DEVICE_AND_INTERFACE_INFO(0x1e0e, 0x9011,
+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
+ .driver_info = (unsigned long) &asr_rndis_info,
+}, {
+ /* Meig SLM770A */
+ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d57,
+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
+ .driver_info = (unsigned long) &asr_rndis_info,
+}, {
+ /* Meig SLM828 */
+ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49,
+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
+ .driver_info = (unsigned long) &asr_rndis_info,
+}, {
/* Novatel Verizon USB730L */
USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1),
.driver_info = (unsigned long) &rndis_info,

View file

@ -0,0 +1,181 @@
From 3b6115d6b57a263bdc8c9b1df273bd4a7955eead Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 8 Jul 2017 08:16:31 +0200
Subject: debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/Kconfig | 3 +++
net/core/Makefile | 3 ++-
net/core/sock.c | 2 ++
net/ipv4/Kconfig | 1 +
net/netlink/Kconfig | 1 +
net/packet/Kconfig | 1 +
net/unix/Kconfig | 1 +
7 files changed, 11 insertions(+), 1 deletion(-)
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -129,6 +129,9 @@ source "net/mptcp/Kconfig"
endif # if INET
+config SOCK_DIAG
+ bool
+
config NETWORK_SECMARK
bool "Security Marking"
help
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -11,12 +11,13 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
obj-y += dev.o dev_addr_lists.o dst.o netevent.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
- sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
+ dev_ioctl.o tso.o sock_reuseport.o \
fib_notifier.o xdp.o flow_offload.o gro.o \
netdev-genl.o netdev-genl-gen.o gso.o
obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
+obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
obj-y += net-sysfs.o
obj-$(CONFIG_PAGE_POOL) += page_pool.o
obj-$(CONFIG_PROC_FS) += net-procfs.o
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -118,6 +118,7 @@
#include <linux/mroute.h>
#include <linux/mroute6.h>
#include <linux/icmpv6.h>
+#include <linux/cookie.h>
#include <linux/uaccess.h>
@@ -150,6 +151,7 @@
static DEFINE_MUTEX(proto_list_mutex);
static LIST_HEAD(proto_list);
+DEFINE_COOKIE(sock_cookie);
static void sock_def_write_space_wfree(struct sock *sk);
static void sock_def_write_space(struct sock *sk);
@@ -590,6 +592,21 @@ discard_and_relse:
}
EXPORT_SYMBOL(__sk_receive_skb);
+u64 __sock_gen_cookie(struct sock *sk)
+{
+ u64 res = atomic64_read(&sk->sk_cookie);
+
+ if (!res) {
+ u64 new = gen_cookie_next(&sock_cookie);
+
+ atomic64_cmpxchg(&sk->sk_cookie, res, new);
+
+ /* Another thread might have changed sk_cookie before us. */
+ res = atomic64_read(&sk->sk_cookie);
+ }
+ return res;
+}
+
INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *,
u32));
INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *,
@@ -2247,9 +2264,11 @@ static void __sk_free(struct sock *sk)
if (likely(sk->sk_net_refcnt))
sock_inuse_add(sock_net(sk), -1);
+#ifdef CONFIG_SOCK_DIAG
if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk)))
sock_diag_broadcast_destroy(sk);
else
+#endif
sk_destruct(sk);
}
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -12,7 +12,6 @@
#include <linux/tcp.h>
#include <linux/workqueue.h>
#include <linux/nospec.h>
-#include <linux/cookie.h>
#include <linux/inet_diag.h>
#include <linux/sock_diag.h>
@@ -21,23 +20,6 @@ static int (*inet_rcv_compat)(struct sk_
static DEFINE_MUTEX(sock_diag_table_mutex);
static struct workqueue_struct *broadcast_wq;
-DEFINE_COOKIE(sock_cookie);
-
-u64 __sock_gen_cookie(struct sock *sk)
-{
- u64 res = atomic64_read(&sk->sk_cookie);
-
- if (!res) {
- u64 new = gen_cookie_next(&sock_cookie);
-
- atomic64_cmpxchg(&sk->sk_cookie, res, new);
-
- /* Another thread might have changed sk_cookie before us. */
- res = atomic64_read(&sk->sk_cookie);
- }
- return res;
-}
-
int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie)
{
u64 res;
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -423,6 +423,7 @@ config INET_TUNNEL
config INET_DIAG
tristate "INET: socket monitoring interface"
+ select SOCK_DIAG
default y
help
Support for INET (TCP, DCCP, etc) socket monitoring interface used by
--- a/net/netlink/Kconfig
+++ b/net/netlink/Kconfig
@@ -5,6 +5,7 @@
config NETLINK_DIAG
tristate "NETLINK: socket monitoring interface"
+ select SOCK_DIAG
default n
help
Support for NETLINK socket monitoring interface used by the ss tool.
--- a/net/packet/Kconfig
+++ b/net/packet/Kconfig
@@ -19,6 +19,7 @@ config PACKET
config PACKET_DIAG
tristate "Packet: sockets monitoring interface"
depends on PACKET
+ select SOCK_DIAG
default n
help
Support for PF_PACKET sockets monitoring interface used by the ss tool.
--- a/net/unix/Kconfig
+++ b/net/unix/Kconfig
@@ -29,6 +29,7 @@ config AF_UNIX_OOB
config UNIX_DIAG
tristate "UNIX: socket monitoring interface"
depends on UNIX
+ select SOCK_DIAG
default n
help
Support for UNIX socket monitoring interface used by the ss tool.
--- a/net/xdp/Kconfig
+++ b/net/xdp/Kconfig
@@ -10,6 +10,7 @@ config XDP_SOCKETS
config XDP_SOCKETS_DIAG
tristate "XDP sockets: monitoring interface"
depends on XDP_SOCKETS
+ select SOCK_DIAG
default n
help
Support for PF_XDP sockets monitoring interface used by the ss tool.

View file

@ -0,0 +1,93 @@
From e3692cb2fcd5ba1244512a0f43b8118f65f1c375 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 8 Jul 2017 08:20:43 +0200
Subject: debloat: dmabuf
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/base/Kconfig | 2 +-
drivers/dma-buf/Makefile | 10 +++++++---
drivers/dma-buf/dma-buf.c | 4 +++-
kernel/sched/core.c | 1 +
4 files changed, 12 insertions(+), 5 deletions(-)
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -198,7 +198,7 @@ config SOC_BUS
source "drivers/base/regmap/Kconfig"
config DMA_SHARED_BUFFER
- bool
+ tristate
default n
select IRQ_WORK
help
--- a/drivers/dma-buf/heaps/Makefile
+++ b/drivers/dma-buf/heaps/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o
-obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o
+dma-buf-objs-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o
+dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -1,12 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
+
+dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
dma-fence-unwrap.o dma-resv.o
-obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o
-obj-$(CONFIG_DMABUF_HEAPS) += heaps/
-obj-$(CONFIG_SYNC_FILE) += sync_file.o
-obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
-obj-$(CONFIG_UDMABUF) += udmabuf.o
-obj-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o
+dma-buf-objs-$(CONFIG_DMABUF_HEAPS) += dma-heap.o
+obj-$(CONFIG_DMABUF_HEAPS) += heaps/
+dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o
+dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
+dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o
+dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o
dmabuf_selftests-y := \
selftest.o \
@@ -15,4 +17,6 @@ dmabuf_selftests-y := \
st-dma-fence-unwrap.o \
st-dma-resv.o
-obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
+dma-buf-objs-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
+
+dma-shared-buffer-objs := $(dma-buf-objs-y)
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1731,4 +1731,5 @@ static void __exit dma_buf_deinit(void)
kern_unmount(dma_buf_mnt);
dma_buf_uninit_sysfs_statistics();
}
-__exitcall(dma_buf_deinit);
+module_exit(dma_buf_deinit);
+MODULE_LICENSE("GPL");
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4487,6 +4487,7 @@ int wake_up_state(struct task_struct *p,
{
return try_to_wake_up(p, state, 0);
}
+EXPORT_SYMBOL_GPL(wake_up_state);
/*
* Perform scheduler related setup for a newly forked process p.
--- a/fs/d_path.c
+++ b/fs/d_path.c
@@ -314,6 +314,7 @@ char *dynamic_dname(char *buffer, int bu
buffer += buflen - sz;
return memcpy(buffer, temp, sz);
}
+EXPORT_SYMBOL_GPL(dynamic_dname);
char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
{

View file

@ -0,0 +1,21 @@
From e08bcbbaa52fcc41f02743fd2e62a33255ce52da Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 13:52:28 +0200
Subject: [PATCH] of/ftd: add device tree cmdline
---
drivers/of/fdt.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -1185,6 +1185,9 @@ int __init early_init_dt_scan_chosen(cha
p = of_get_flat_dt_prop(node, "bootargs", &l);
if (p != NULL && l > 0)
strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE));
+ p = of_get_flat_dt_prop(node, "bootargs-append", &l);
+ if (p != NULL && l > 0)
+ strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE));
handle_cmdline:
/*

View file

@ -0,0 +1,81 @@
diff -urpN linux-6.1.38.old/include/net/netfilter/nf_conntrack.h linux-6.1.38/include/net/netfilter/nf_conntrack.h
--- linux-6.1.38.old/include/net/netfilter/nf_conntrack.h 2023-07-05 23:27:38.000000000 +0600
+++ linux-6.1.38/include/net/netfilter/nf_conntrack.h 2023-07-14 12:34:56.663750711 +0600
@@ -362,6 +362,11 @@ static inline struct nf_conntrack_net *n
return net_generic(net, nf_conntrack_net_id);
}
+#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
+void register_nf_ct_destroy_hook(void (*hook)(struct nf_conn *));
+void unregister_nf_ct_destroy_hook(void);
+#endif
+
#define NF_CT_STAT_INC(net, count) __this_cpu_inc((net)->ct.stat->count)
#define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
#define NF_CT_STAT_ADD_ATOMIC(net, count, v) this_cpu_add((net)->ct.stat->count, (v))
diff -urpN linux-6.1.38.old/net/netfilter/Kconfig linux-6.1.38/net/netfilter/Kconfig
--- linux-6.1.38.old/net/netfilter/Kconfig 2023-07-05 23:27:38.000000000 +0600
+++ linux-6.1.38/net/netfilter/Kconfig 2023-07-14 12:34:11.966879899 +0600
@@ -76,11 +76,15 @@ config NETFILTER_NETLINK_OSF
If this option is enabled, the kernel will include support
for passive OS fingerprint via NFNETLINK.
+config NF_CONNTRACK_DESTROY_HOOK
+ bool
+
config NF_CONNTRACK
tristate "Netfilter connection tracking support"
default m if NETFILTER_ADVANCED=n
select NF_DEFRAG_IPV4
select NF_DEFRAG_IPV6 if IPV6 != n
+ select NF_CONNTRACK_DESTROY_HOOK
help
Connection tracking keeps a record of what packets have passed
through your machine, in order to figure out how they are related
diff -urpN linux-6.1.38.old/net/netfilter/nf_conntrack_core.c linux-6.1.38/net/netfilter/nf_conntrack_core.c
--- linux-6.1.38.old/net/netfilter/nf_conntrack_core.c 2023-07-05 23:27:38.000000000 +0600
+++ linux-6.1.38/net/netfilter/nf_conntrack_core.c 2023-07-14 12:33:45.580092713 +0600
@@ -582,9 +582,30 @@ static void destroy_gre_conntrack(struct
#endif
}
+#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
+
+static void (*nf_ct_destroy_hook)(struct nf_conn *) __rcu __read_mostly = NULL;
+
+void register_nf_ct_destroy_hook(void (*hook)(struct nf_conn *))
+{
+ rcu_assign_pointer(nf_ct_destroy_hook, hook);
+}
+EXPORT_SYMBOL(register_nf_ct_destroy_hook);
+
+void unregister_nf_ct_destroy_hook(void)
+{
+ rcu_assign_pointer(nf_ct_destroy_hook, NULL);
+}
+
+EXPORT_SYMBOL(unregister_nf_ct_destroy_hook);
+#endif
+
void nf_ct_destroy(struct nf_conntrack *nfct)
{
struct nf_conn *ct = (struct nf_conn *)nfct;
+#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
+ void (*hook)(struct nf_conn *);
+#endif
pr_debug("%s(%p)\n", __func__, ct);
WARN_ON(refcount_read(&nfct->use) != 0);
@@ -594,6 +615,12 @@ void nf_ct_destroy(struct nf_conntrack *
return;
}
+#ifdef CONFIG_NF_CONNTRACK_DESTROY_HOOK
+ hook = rcu_dereference(nf_ct_destroy_hook);
+ if (hook)
+ hook(ct);
+#endif
+
if (unlikely(nf_ct_protonum(ct) == IPPROTO_GRE))
destroy_gre_conntrack(ct);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 22 Oct 2020 22:00:03 +0200
Subject: [PATCH] compiler.h: only include asm/rwonce.h for kernel code
This header file is not in uapi, which makes any user space code that includes
linux/compiler.h to fail with the error 'asm/rwonce.h: No such file or directory'
Fixes: e506ea451254 ("compiler.h: Split {READ,WRITE}_ONCE definitions out into rwonce.h")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -202,6 +202,8 @@ void ftrace_likely_update(struct ftrace_
__v; \
})
+#include <asm/rwonce.h>
+
#endif /* __KERNEL__ */
/*
@@ -243,6 +245,4 @@ static inline void *offset_to_ptr(const
*/
#define prevent_tail_call_optimization() mb()
-#include <asm/rwonce.h>
-
#endif /* __LINUX_COMPILER_H */

View file

@ -0,0 +1,57 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 18 Apr 2018 10:50:05 +0200
Subject: [PATCH] MIPS: only process negative stack offsets on stack traces
Fixes endless back traces in cases where the compiler emits a stack
pointer increase in a branch delay slot (probably for some form of
function return).
[ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low!
[ 3.480070] turning off the locking correctness validator.
[ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0
[ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000
[ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f
[ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000
[ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000
[ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000
[ 3.532942] ...
[ 3.535362] Call Trace:
[ 3.537818] [<80010a48>] show_stack+0x58/0x100
[ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170
[ 3.546613] [<80079f90>] save_trace+0xf0/0x110
[ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c
[ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08
[ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c
[ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78
[ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac
[ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0
[ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -395,6 +395,8 @@ static inline int is_sp_move_ins(union m
if (ip->i_format.opcode == addiu_op ||
ip->i_format.opcode == daddiu_op) {
+ if (ip->i_format.simmediate > 0)
+ return 0;
*frame_size = -ip->i_format.simmediate;
return 1;
}

View file

@ -0,0 +1,75 @@
From bd1b9f66d5134e518419f4c4dacf1884c1616983 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
Date: Thu, 28 Apr 2022 11:13:23 +0200
Subject: [PATCH] watchdog: max63xx_wdt: Add support for specifying WDI logic
via GPIO
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On some boards is WDI logic of max6370 chip connected via GPIO.
So extend max63xx_wdt driver to allow specifying WDI logic via GPIO.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
drivers/watchdog/max63xx_wdt.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/property.h>
+#include <linux/gpio/consumer.h>
#define DEFAULT_HEARTBEAT 60
#define MAX_HEARTBEAT 60
@@ -50,6 +51,9 @@ struct max63xx_wdt {
void __iomem *base;
spinlock_t lock;
+ /* GPIOs */
+ struct gpio_desc *gpio_wdi;
+
/* WDI and WSET bits write access routines */
void (*ping)(struct max63xx_wdt *wdt);
void (*set)(struct max63xx_wdt *wdt, u8 set);
@@ -155,6 +159,17 @@ static const struct watchdog_info max63x
.identity = "max63xx Watchdog",
};
+static void max63xx_gpio_ping(struct max63xx_wdt *wdt)
+{
+ spin_lock(&wdt->lock);
+
+ gpiod_set_value(wdt->gpio_wdi, 1);
+ udelay(1);
+ gpiod_set_value(wdt->gpio_wdi, 0);
+
+ spin_unlock(&wdt->lock);
+}
+
static void max63xx_mmap_ping(struct max63xx_wdt *wdt)
{
u8 val;
@@ -222,10 +237,19 @@ static int max63xx_wdt_probe(struct plat
return -EINVAL;
}
+ wdt->gpio_wdi = devm_gpiod_get(dev, NULL, GPIOD_FLAGS_BIT_DIR_OUT);
+ if (IS_ERR(wdt->gpio_wdi) && PTR_ERR(wdt->gpio_wdi) != -ENOENT)
+ return dev_err_probe(dev, PTR_ERR(wdt->gpio_wdi),
+ "unable to request gpio: %ld\n",
+ PTR_ERR(wdt->gpio_wdi));
+
err = max63xx_mmap_init(pdev, wdt);
if (err)
return err;
+ if (!IS_ERR(wdt->gpio_wdi))
+ wdt->ping = max63xx_gpio_ping;
+
platform_set_drvdata(pdev, &wdt->wdd);
watchdog_set_drvdata(&wdt->wdd, wdt);

View file

@ -0,0 +1,82 @@
From: Tobias Wolf <dev-NTEO@vplace.de>
Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation
An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any
kernel beyond version 4.3 resulting in:
BUG: Bad page state in process swapper pfn:086ac
bisect resulted in:
a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit
commit a1c34a3bf00af2cede839879502e12dc68491ad5
Author: Laura Abbott <laura@labbott.name>
Date: Thu Nov 5 18:48:46 2015 -0800
mm: Don't offset memmap for flatmem
Srinivas Kandagatla reported bad page messages when trying to remove the
bottom 2MB on an ARM based IFC6410 board
BUG: Bad page state in process swapper pfn:fffa8
page:ef7fb500 count:0 mapcount:0 mapping: (null) index:0x0
flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked)
page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
bad because of flags:
flags: 0x200041(locked|active|mlocked)
Modules linked in:
CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty
#816
Hardware name: Qualcomm (Flattened Device Tree)
unwind_backtrace
show_stack
dump_stack
bad_page
free_pages_prepare
free_hot_cold_page
__free_pages
free_highmem_page
mem_init
start_kernel
Disabling lock debugging due to kernel taint
[...]
:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4
0a8156f848733dfa21e16c196dfb6c0a76290709 M mm
This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by
page_to_pfn anymore.
The following output was generated with two hacked in printk statements:
printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map -
(pgdat->node_start_pfn - ARCH_PFN_OFFSET));
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
printk("after %p\n", mem_map);
Output:
[ 0.000000] before 8861b280 vs. 8861b280 or 8851b280
[ 0.000000] after 8851b280
As seen in the first line mem_map with subtraction of offset does not equal the
mem_map after subtraction of ARCH_PFN_OFFSET.
After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the
previously calculated offset is zero for the named platform it is able to boot
4.4 and 4.9-rc7 again.
Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
---
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -1673,7 +1673,7 @@ static void __init alloc_node_mem_map(st
if (pgdat == NODE_DATA(0)) {
mem_map = NODE_DATA(0)->node_mem_map;
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
- mem_map -= offset;
+ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
}
#endif
}

View file

@ -0,0 +1,81 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support
It is required for renames on overlayfs
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -617,8 +617,8 @@ static int jffs2_rmdir (struct inode *di
return ret;
}
-static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
- struct dentry *dentry, umode_t mode, dev_t rdev)
+static int __jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
+ struct dentry *dentry, umode_t mode, dev_t rdev, bool whiteout)
{
struct jffs2_inode_info *f, *dir_f;
struct jffs2_sb_info *c;
@@ -758,7 +758,11 @@ static int jffs2_mknod (struct mnt_idmap
mutex_unlock(&dir_f->sem);
jffs2_complete_reservation(c);
- d_instantiate_new(dentry, inode);
+ if (!whiteout)
+ d_instantiate_new(dentry, inode);
+ else
+ unlock_new_inode(inode);
+
return 0;
fail:
@@ -766,6 +770,19 @@ static int jffs2_mknod (struct mnt_idmap
return ret;
}
+static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i,
+ struct dentry *dentry, umode_t mode, dev_t rdev)
+{
+ return __jffs2_mknod(idmap, dir_i, dentry, mode, rdev, false);
+}
+
+static int jffs2_whiteout (struct mnt_idmap *idmap, struct inode *old_dir,
+ struct dentry *old_dentry)
+{
+ return __jffs2_mknod(idmap, old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE,
+ WHITEOUT_DEV, true);
+}
+
static int jffs2_rename (struct mnt_idmap *idmap,
struct inode *old_dir_i, struct dentry *old_dentry,
struct inode *new_dir_i, struct dentry *new_dentry,
@@ -777,7 +794,7 @@ static int jffs2_rename (struct mnt_idma
uint8_t type;
uint32_t now;
- if (flags & ~RENAME_NOREPLACE)
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
return -EINVAL;
/* The VFS will check for us and prevent trying to rename a
@@ -843,9 +860,14 @@ static int jffs2_rename (struct mnt_idma
if (d_is_dir(old_dentry) && !victim_f)
inc_nlink(new_dir_i);
- /* Unlink the original */
- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
+ if (flags & RENAME_WHITEOUT)
+ /* Replace with whiteout */
+ ret = jffs2_whiteout(idmap, old_dir_i, old_dentry);
+ else
+ /* Unlink the original */
+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+ old_dentry->d_name.name,
+ old_dentry->d_name.len, NULL, now);
/* We don't touch inode->i_nlink */

View file

@ -0,0 +1,73 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: jffs2: add RENAME_EXCHANGE support
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -791,18 +791,31 @@ static int jffs2_rename (struct mnt_idma
int ret;
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
struct jffs2_inode_info *victim_f = NULL;
+ struct inode *fst_inode = d_inode(old_dentry);
+ struct inode *snd_inode = d_inode(new_dentry);
uint8_t type;
uint32_t now;
- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE))
return -EINVAL;
+ if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) {
+ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
+ inc_nlink(new_dir_i);
+ drop_nlink(old_dir_i);
+ }
+ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
+ drop_nlink(new_dir_i);
+ inc_nlink(old_dir_i);
+ }
+ }
+
/* The VFS will check for us and prevent trying to rename a
* file over a directory and vice versa, but if it's a directory,
* the VFS can't check whether the victim is empty. The filesystem
* needs to do that for itself.
*/
- if (d_really_is_positive(new_dentry)) {
+ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
if (d_is_dir(new_dentry)) {
struct jffs2_full_dirent *fd;
@@ -837,7 +850,7 @@ static int jffs2_rename (struct mnt_idma
if (ret)
return ret;
- if (victim_f) {
+ if (victim_f && !(flags & RENAME_EXCHANGE)) {
/* There was a victim. Kill it off nicely */
if (d_is_dir(new_dentry))
clear_nlink(d_inode(new_dentry));
@@ -863,6 +876,12 @@ static int jffs2_rename (struct mnt_idma
if (flags & RENAME_WHITEOUT)
/* Replace with whiteout */
ret = jffs2_whiteout(idmap, old_dir_i, old_dentry);
+ else if (flags & RENAME_EXCHANGE)
+ /* Replace the original */
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
+ d_inode(new_dentry)->i_ino, type,
+ old_dentry->d_name.name, old_dentry->d_name.len,
+ now);
else
/* Unlink the original */
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
@@ -895,7 +914,7 @@ static int jffs2_rename (struct mnt_idma
return ret;
}
- if (d_is_dir(old_dentry))
+ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
drop_nlink(old_dir_i);
old_dir_i->i_mtime = inode_set_ctime_to_ts(old_dir_i, ITIME(now));

View file

@ -0,0 +1,20 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: jffs2: add splice ops
Add splice_read using generic_file_splice_read.
Add splice_write using iter_file_splice_write
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -53,6 +53,8 @@ const struct file_operations jffs2_file_
.open = generic_file_open,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
+ .splice_read = filemap_splice_read,
+ .splice_write = iter_file_splice_write,
.unlocked_ioctl=jffs2_ioctl,
.mmap = generic_file_readonly_mmap,
.fsync = jffs2_fsync,

View file

@ -0,0 +1,45 @@
From: Stephen Hemminger <stephen@networkplumber.org>
Subject: bridge: allow receiption on disabled port
When an ethernet device is enslaved to a bridge, and the bridge STP
detects loss of carrier (or operational state down), then normally
packet receiption is blocked.
This breaks control applications like WPA which maybe expecting to
receive packets to negotiate to bring link up. The bridge needs to
block forwarding packets from these disabled ports, but there is no
hard requirement to not allow local packet delivery.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -244,6 +244,9 @@ static void __br_handle_local_finish(str
/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
+ struct net_bridge_port *p = br_port_get_rcu(skb->dev);
+
+ if (p->state != BR_STATE_DISABLED)
__br_handle_local_finish(skb);
/* return 1 to signal the okfn() was called so it's ok to use the skb */
@@ -415,6 +418,17 @@ forward:
goto defer_stp_filtering;
switch (p->state) {
+ case BR_STATE_DISABLED:
+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
+ skb->pkt_type = PACKET_HOST;
+
+ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
+ dev_net(skb->dev), NULL, skb, skb->dev, NULL,
+ br_handle_local_finish) == 1) {
+ return RX_HANDLER_PASS;
+ }
+ break;
+
case BR_STATE_FORWARDING:
case BR_STATE_LEARNING:
defer_stp_filtering:

View file

@ -0,0 +1,37 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 4 Jan 2024 15:21:21 +0100
Subject: [PATCH] net: bridge: do not send arp replies if src and target hw
addr is the same
There are broken devices in the wild that handle duplicate IP address
detection by sending out ARP requests for the IP that they received from a
DHCP server and refuse the address if they get a reply.
When proxyarp is enabled, they would go into a loop of requesting an address
and then NAKing it again.
Link: https://github.com/openwrt/openwrt/issues/14309
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -204,7 +204,10 @@ void br_do_proxy_suppress_arp(struct sk_
if ((p && (p->flags & BR_PROXYARP)) ||
(f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) ||
br_is_neigh_suppress_enabled(f->dst, vid)) {
- if (!vid)
+ replied = true;
+ if (!memcmp(n->ha, sha, dev->addr_len))
+ replied = false;
+ else if (!vid)
br_arp_send(br, p, skb->dev, sip, tip,
sha, n->ha, sha, 0, 0);
else
@@ -212,7 +215,6 @@ void br_do_proxy_suppress_arp(struct sk_
sha, n->ha, sha,
skb->vlan_proto,
skb_vlan_tag_get(skb));
- replied = true;
}
/* If we have replied or as long as we know the

View file

@ -0,0 +1,94 @@
From: Daniel González Cabanelas <dgcbueu@gmail.com>
Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week
The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week
alarms.
Read the "wday" alarm register and convert it to a date to support up 1
week in our driver.
Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
---
drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 6 deletions(-)
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -399,7 +399,9 @@ static int rs5c_read_alarm(struct device
{
struct i2c_client *client = to_i2c_client(dev);
struct rs5c372 *rs5c = i2c_get_clientdata(client);
- int status;
+ int status, wday_offs;
+ struct rtc_time rtc;
+ unsigned long alarm_secs;
status = rs5c_get_regs(rs5c);
if (status < 0)
@@ -409,6 +411,30 @@ static int rs5c_read_alarm(struct device
t->time.tm_sec = 0;
t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
+ t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1;
+
+ /* determine the day, month and year based on alarm wday, taking as a
+ * reference the current time from the rtc
+ */
+ status = rs5c372_rtc_read_time(dev, &rtc);
+ if (status < 0)
+ return status;
+
+ wday_offs = t->time.tm_wday - rtc.tm_wday;
+ alarm_secs = mktime64(rtc.tm_year + 1900,
+ rtc.tm_mon + 1,
+ rtc.tm_mday + wday_offs,
+ t->time.tm_hour,
+ t->time.tm_min,
+ t->time.tm_sec);
+
+ if (wday_offs < 0 || (wday_offs == 0 &&
+ (t->time.tm_hour < rtc.tm_hour ||
+ (t->time.tm_hour == rtc.tm_hour &&
+ t->time.tm_min <= rtc.tm_min))))
+ alarm_secs += 7 * 86400;
+
+ rtc_time64_to_tm(alarm_secs, &t->time);
/* ... and status */
t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
@@ -423,12 +449,20 @@ static int rs5c_set_alarm(struct device
struct rs5c372 *rs5c = i2c_get_clientdata(client);
int status, addr, i;
unsigned char buf[3];
+ struct rtc_time rtc_tm;
+ unsigned long rtc_secs, alarm_secs;
- /* only handle up to 24 hours in the future, like RTC_ALM_SET */
- if (t->time.tm_mday != -1
- || t->time.tm_mon != -1
- || t->time.tm_year != -1)
+ /* chip only can handle alarms up to one week in the future*/
+ status = rs5c372_rtc_read_time(dev, &rtc_tm);
+ if (status)
+ return status;
+ rtc_secs = rtc_tm_to_time64(&rtc_tm);
+ alarm_secs = rtc_tm_to_time64(&t->time);
+ if (alarm_secs >= rtc_secs + 7 * 86400) {
+ dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n",
+ __func__, status);
return -EINVAL;
+ }
/* REVISIT: round up tm_sec */
@@ -449,7 +483,9 @@ static int rs5c_set_alarm(struct device
/* set alarm */
buf[0] = bin2bcd(t->time.tm_min);
buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
- buf[2] = 0x7f; /* any/all days */
+ /* each bit is the day of the week, 0x7f means all days */
+ buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ?
+ BIT(t->time.tm_wday) : 0x7f;
for (i = 0; i < sizeof(buf); i++) {
addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);

View file

@ -0,0 +1,41 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries
[john@phrozen.org: felix will add this to his upstream queue]
lede-commit 53827cdc824556cda910b23ce5030c363b8f1461
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
lib/vsprintf.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -982,8 +982,10 @@ char *symbol_string(char *buf, char *end
struct printf_spec spec, const char *fmt)
{
unsigned long value;
-#ifdef CONFIG_KALLSYMS
char sym[KSYM_SYMBOL_LEN];
+#ifndef CONFIG_KALLSYMS
+ struct module *mod;
+ int len;
#endif
if (fmt[1] == 'R')
@@ -1004,8 +1006,14 @@ char *symbol_string(char *buf, char *end
return string_nocheck(buf, end, sym, spec);
#else
- return special_hex_number(buf, end, value, sizeof(void *));
+ len = snprintf(sym, sizeof(sym), "0x%lx", value);
+ mod = __module_address(value);
+ if (mod)
+ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
+ mod->name, mod->mem[MOD_TEXT].base,
+ mod->mem[MOD_TEXT].size);
#endif
+ return string(buf, end, sym, spec);
}
static const struct printf_spec default_str_spec = {

View file

@ -0,0 +1,30 @@
From: Gabor Juhos <juhosg@openwrt.org>
Subject: usr: sanitize deps_initramfs list
If any filename in the intramfs dependency
list contains a colon, that causes a kernel
build error like this:
/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop.
make[5]: *** [usr] Error 2
Fix it by removing such filenames from the
deps_initramfs list.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
usr/Makefile | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -56,6 +56,8 @@ hostprogs := gen_init_cpio
# The dependency list is generated by gen_initramfs.sh -l
-include $(obj)/.initramfs_data.cpio.d
+deps_initramfs := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
+
# do not try to update files included in initramfs
$(deps_initramfs): ;

View file

@ -0,0 +1,40 @@
From: Mark Miller <mark@mirell.org>
Subject: mips: expose CONFIG_BOOT_RAW
This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
certain Broadcom chipsets running CFE in order to load the kernel.
Signed-off-by: Mark Miller <mark@mirell.org>
Acked-by: Rob Landley <rob@landley.net>
---
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1013,9 +1013,6 @@ config FW_ARC
config ARCH_MAY_HAVE_PC_FDC
bool
-config BOOT_RAW
- bool
-
config CEVT_BCM1480
bool
@@ -2996,6 +2993,18 @@ choice
bool "Extend builtin kernel arguments with bootloader arguments"
endchoice
+config BOOT_RAW
+ bool "Enable the kernel to be executed from the load address"
+ default n
+ help
+ Allow the kernel to be executed from the load address for
+ bootloaders which cannot read the ELF format. This places
+ a jump to start_kernel at the load address.
+
+ If unsure, say N.
+
+
+
endmenu
config LOCKDEP_SUPPORT

View file

@ -0,0 +1,71 @@
From e6e6ef4275978823ec3a84133fc91f4ffbef5c84 Mon Sep 17 00:00:00 2001
From: Paul Burton <paul.burton@imgtec.com>
Date: Mon, 22 Feb 2016 18:09:44 +0000
Subject: [PATCH] MIPS: Add barriers between dcache & icache flushes
Index-based cache operations may be arbitrarily reordered by out of
order CPUs. Thus code which writes back the dcache & then invalidates
the icache using indexed cache ops must include a barrier between
operating on the 2 caches in order to prevent the scenario in which:
- icache invalidation occurs.
- icache fetch occurs, due to speculation.
- dcache writeback occurs.
If the above were allowed to happen then the icache would contain stale
data. Forcing the dcache writeback to complete before the icache
invalidation avoids this.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: James Hogan <james.hogan@imgtec.com>
---
arch/mips/mm/c-r4k.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -403,6 +403,7 @@ static inline void local_r4k___flush_cac
default:
r4k_blast_dcache();
+ mb(); /* cache instructions may be reordered */
r4k_blast_icache();
break;
}
@@ -483,8 +484,10 @@ static inline void local_r4k_flush_cache
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
r4k_blast_dcache();
/* If executable, blast stale lines from icache */
- if (exec)
+ if (exec) {
+ mb(); /* cache instructions may be reordered */
r4k_blast_icache();
+ }
}
static void r4k_flush_cache_range(struct vm_area_struct *vma,
@@ -586,8 +589,13 @@ static inline void local_r4k_flush_cache
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
vaddr ? r4k_blast_dcache_page(addr) :
r4k_blast_dcache_user_page(addr);
- if (exec && !cpu_icache_snoops_remote_store)
+ if (exec)
+ mb(); /* cache instructions may be reordered */
+
+ if (exec && !cpu_icache_snoops_remote_store) {
r4k_blast_scache_page(addr);
+ mb(); /* cache instructions may be reordered */
+ }
}
if (exec) {
if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
@@ -654,6 +662,7 @@ static inline void __local_r4k_flush_ica
else
blast_dcache_range(start, end);
}
+ mb(); /* cache instructions may be reordered */
}
if (type == R4K_INDEX ||

View file

@ -0,0 +1,22 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: mips: use -mno-branch-likely for kernel and userspace
saves ~11k kernel size after lzma and ~12k squashfs size in the
lede-commit: 41a039f46450ffae9483d6216422098669da2900
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
arch/mips/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -94,7 +94,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
# machines may also. Since BFD is incredibly buggy with respect to
# crossformat linking we rely on the elf2ecoff tool for format conversion.
#
-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
+cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
cflags-y += -msoft-float -Wa,-msoft-float
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
KBUILD_AFLAGS_MODULE += -mlong-calls

View file

@ -0,0 +1,22 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2
This provides a good tradeoff across at least 24Kc-74Kc, while also
producing smaller code.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
arch/mips/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -163,7 +163,7 @@ cflags-$(CONFIG_CPU_R4300) += -march=r43
cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap
-cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -mtune=34kc -Wa,--trap
cflags-$(CONFIG_CPU_MIPS32_R5) += -march=mips32r5 -Wa,--trap -modd-spreg
cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg
cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap

View file

@ -0,0 +1,22 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: fix errors in unresolved weak symbols on arm
lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
arch/arm/kernel/module.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -146,6 +146,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
return -ENOEXEC;
}
+ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
+ ELF_ST_BIND(sym->st_info) == STB_WEAK)
+ continue;
+
loc = dstsec->sh_addr + rel->r_offset;
switch (ELF32_R_TYPE(rel->r_info)) {

View file

@ -0,0 +1,282 @@
From: Yousong Zhou <yszhou4tech@gmail.com>
Subject: MIPS: kexec: Accept command line parameters from userspace.
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
---
arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++-----
arch/mips/kernel/machine_kexec.h | 20 +++++
arch/mips/kernel/relocate_kernel.S | 21 +++--
3 files changed, 167 insertions(+), 27 deletions(-)
create mode 100644 arch/mips/kernel/machine_kexec.h
--- a/arch/mips/kernel/machine_kexec.c
+++ b/arch/mips/kernel/machine_kexec.c
@@ -9,14 +9,11 @@
#include <linux/delay.h>
#include <linux/libfdt.h>
+#include <asm/bootinfo.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
-
-extern const unsigned char relocate_new_kernel[];
-extern const size_t relocate_new_kernel_size;
-
-extern unsigned long kexec_start_address;
-extern unsigned long kexec_indirection_page;
+#include <linux/uaccess.h>
+#include "machine_kexec.h"
static unsigned long reboot_code_buffer;
@@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL
void (*_machine_kexec_shutdown)(void) = NULL;
void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
+static void machine_kexec_print_args(void)
+{
+ unsigned long argc = (int)kexec_args[0];
+ int i;
+
+ pr_info("kexec_args[0] (argc): %lu\n", argc);
+ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
+ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
+ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
+
+ for (i = 0; i < argc; i++) {
+ pr_info("kexec_argv[%d] = %p, %s\n",
+ i, kexec_argv[i], kexec_argv[i]);
+ }
+}
+
+static void machine_kexec_init_argv(struct kimage *image)
+{
+ void __user *buf = NULL;
+ size_t bufsz;
+ size_t size;
+ int i;
+
+ bufsz = 0;
+ for (i = 0; i < image->nr_segments; i++) {
+ struct kexec_segment *seg;
+
+ seg = &image->segment[i];
+ if (seg->bufsz < 6)
+ continue;
+
+ if (strncmp((char *) seg->buf, "kexec ", 6))
+ continue;
+
+ buf = seg->buf;
+ bufsz = seg->bufsz;
+ break;
+ }
+
+ if (!buf)
+ return;
+
+ size = KEXEC_COMMAND_LINE_SIZE;
+ size = min(size, bufsz);
+ if (size < bufsz)
+ pr_warn("kexec command line truncated to %zd bytes\n", size);
+
+ /* Copy to kernel space */
+ if (copy_from_user(kexec_argv_buf, buf, size))
+ pr_warn("kexec command line copy to kernel space failed\n");
+
+ kexec_argv_buf[size - 1] = 0;
+}
+
+static void machine_kexec_parse_argv(struct kimage *image)
+{
+ char *reboot_code_buffer;
+ int reloc_delta;
+ char *ptr;
+ int argc;
+ int i;
+
+ ptr = kexec_argv_buf;
+ argc = 0;
+
+ /*
+ * convert command line string to array of parameters
+ * (as bootloader does).
+ */
+ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
+ if (*ptr == ' ') {
+ *ptr++ = '\0';
+ continue;
+ }
+
+ kexec_argv[argc++] = ptr;
+ ptr = strchr(ptr, ' ');
+ }
+
+ if (!argc)
+ return;
+
+ kexec_args[0] = argc;
+ kexec_args[1] = (unsigned long)kexec_argv;
+ kexec_args[2] = 0;
+ kexec_args[3] = 0;
+
+ reboot_code_buffer = page_address(image->control_code_page);
+ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
+
+ kexec_args[1] += reloc_delta;
+ for (i = 0; i < argc; i++)
+ kexec_argv[i] += reloc_delta;
+}
+
static void kexec_image_info(const struct kimage *kimage)
{
unsigned long i;
@@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim
#endif
kexec_image_info(kimage);
+ /*
+ * Whenever arguments passed from kexec-tools, Init the arguments as
+ * the original ones to try avoiding booting failure.
+ */
+
+ kexec_args[0] = fw_arg0;
+ kexec_args[1] = fw_arg1;
+ kexec_args[2] = fw_arg2;
+ kexec_args[3] = fw_arg3;
+
+ machine_kexec_init_argv(kimage);
+ machine_kexec_parse_argv(kimage);
if (_machine_kexec_prepare)
return _machine_kexec_prepare(kimage);
@@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r
void kexec_nonboot_cpu_jump(void)
{
local_flush_icache_range((unsigned long)relocated_kexec_smp_wait,
- reboot_code_buffer + relocate_new_kernel_size);
+ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
relocated_kexec_smp_wait(NULL);
}
@@ -199,7 +303,7 @@ void kexec_reboot(void)
* machine_kexec() CPU.
*/
local_flush_icache_range(reboot_code_buffer,
- reboot_code_buffer + relocate_new_kernel_size);
+ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
do_kexec = (void *)reboot_code_buffer;
do_kexec();
@@ -212,10 +316,12 @@ machine_kexec(struct kimage *image)
unsigned long *ptr;
reboot_code_buffer =
- (unsigned long)page_address(image->control_code_page);
+ (unsigned long)page_address(image->control_code_page);
+ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
kexec_start_address =
(unsigned long) phys_to_virt(image->start);
+ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
if (image->type == KEXEC_TYPE_DEFAULT) {
kexec_indirection_page =
@@ -223,9 +329,19 @@ machine_kexec(struct kimage *image)
} else {
kexec_indirection_page = (unsigned long)&image->head;
}
+ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
- memcpy((void*)reboot_code_buffer, relocate_new_kernel,
- relocate_new_kernel_size);
+ pr_info("Where is memcpy: %p\n", memcpy);
+ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
+ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
+ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
+ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
+ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
+ KEXEC_RELOCATE_NEW_KERNEL_SIZE);
+
+ pr_info("Before _print_args().\n");
+ machine_kexec_print_args();
+ pr_info("Before eval loop.\n");
/*
* The generic kexec code builds a page list with physical
@@ -256,7 +372,7 @@ machine_kexec(struct kimage *image)
#ifdef CONFIG_SMP
/* All secondary cpus now may jump to kexec_wait cycle */
relocated_kexec_smp_wait = reboot_code_buffer +
- (void *)(kexec_smp_wait - relocate_new_kernel);
+ (void *)(kexec_smp_wait - kexec_relocate_new_kernel);
smp_wmb();
atomic_set(&kexec_ready_to_reboot, 1);
#endif
--- /dev/null
+++ b/arch/mips/kernel/machine_kexec.h
@@ -0,0 +1,20 @@
+#ifndef _MACHINE_KEXEC_H
+#define _MACHINE_KEXEC_H
+
+#ifndef __ASSEMBLY__
+extern const unsigned char kexec_relocate_new_kernel[];
+extern unsigned long kexec_relocate_new_kernel_end;
+extern unsigned long kexec_start_address;
+extern unsigned long kexec_indirection_page;
+
+extern char kexec_argv_buf[];
+extern char *kexec_argv[];
+
+#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
+#endif /* !__ASSEMBLY__ */
+
+#define KEXEC_COMMAND_LINE_SIZE 256
+#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16)
+#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long))
+
+#endif
--- a/arch/mips/kernel/relocate_kernel.S
+++ b/arch/mips/kernel/relocate_kernel.S
@@ -10,10 +10,11 @@
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>
+#include "machine_kexec.h"
#include <kernel-entry-init.h>
-LEAF(relocate_new_kernel)
+LEAF(kexec_relocate_new_kernel)
PTR_L a0, arg0
PTR_L a1, arg1
PTR_L a2, arg2
@@ -98,7 +99,7 @@ done:
#endif
/* jump to kexec_start_address */
j s1
- END(relocate_new_kernel)
+ END(kexec_relocate_new_kernel)
#ifdef CONFIG_SMP
/*
@@ -177,8 +178,15 @@ EXPORT(kexec_indirection_page)
PTR_WD 0
.size kexec_indirection_page, PTRSIZE
-relocate_new_kernel_end:
+kexec_argv_buf:
+ EXPORT(kexec_argv_buf)
+ .skip KEXEC_COMMAND_LINE_SIZE
+ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
+
+kexec_argv:
+ EXPORT(kexec_argv)
+ .skip KEXEC_ARGV_SIZE
+ .size kexec_argv, KEXEC_ARGV_SIZE
-EXPORT(relocate_new_kernel_size)
- PTR_WD relocate_new_kernel_end - relocate_new_kernel
- .size relocate_new_kernel_size, PTRSIZE
+kexec_relocate_new_kernel_end:
+ EXPORT(kexec_relocate_new_kernel_end)

View file

@ -0,0 +1,84 @@
From bb0c3b0175240bf152fd7c644821a0cf9f77c37c Mon Sep 17 00:00:00 2001
From: Evgeniy Didin <Evgeniy.Didin@synopsys.com>
Date: Fri, 15 Mar 2019 18:53:38 +0300
Subject: [PATCH] arc add OWRTDTB section
This change allows OpenWRT to patch resulting kernel binary with
external .dtb.
That allows us to re-use exactky the same vmlinux on different boards
given its ARC core configurations match (at least cache line sizes etc).
""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external
.dtb right after it, keeping the string in place.
Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
Signed-off-by: Evgeniy Didin <Evgeniy.Didin@synopsys.com>
---
arch/arc/kernel/head.S | 10 ++++++++++
arch/arc/kernel/setup.c | 4 +++-
arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++
3 files changed, 26 insertions(+), 1 deletion(-)
--- a/arch/arc/kernel/head.S
+++ b/arch/arc/kernel/head.S
@@ -88,6 +88,16 @@
DSP_EARLY_INIT
.endm
+ ; Here "patch-dtb" will embed external .dtb
+ ; Note "patch-dtb" searches for ASCII "OWRTDTB:" string
+ ; and pastes .dtb right after it, hense the string precedes
+ ; __image_dtb symbol.
+ .section .owrt, "aw",@progbits
+ .ascii "OWRTDTB:"
+ENTRY(__image_dtb)
+ .fill 0x4000
+END(__image_dtb)
+
.section .init.text, "ax",@progbits
;----------------------------------------------------------------
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -450,6 +450,8 @@ static inline bool uboot_arg_invalid(uns
/* We always pass 0 as magic from U-boot */
#define UBOOT_MAGIC_VALUE 0
+extern struct boot_param_header __image_dtb;
+
void __init handle_uboot_args(void)
{
bool use_embedded_dtb = true;
@@ -488,7 +490,7 @@ void __init handle_uboot_args(void)
ignore_uboot_args:
if (use_embedded_dtb) {
- machine_desc = setup_machine_fdt(__dtb_start);
+ machine_desc = setup_machine_fdt(&__image_dtb);
if (!machine_desc)
panic("Embedded DT invalid\n");
}
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -27,6 +27,19 @@ SECTIONS
. = CONFIG_LINUX_LINK_BASE;
+ /*
+ * In OpenWRT we want to patch built binary embedding .dtb of choice.
+ * This is implemented with "patch-dtb" utility which searches for
+ * "OWRTDTB:" string in first 16k of image and if it is found
+ * copies .dtb right after mentioned string.
+ *
+ * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it.
+ */
+ .owrt : {
+ *(.owrt)
+ . = ALIGN(PAGE_SIZE);
+ }
+
_int_vec_base_lds = .;
.vector : {
*(.vector)

View file

@ -0,0 +1,24 @@
From: Alexey Brodkin <abrodkin@synopsys.com>
Subject: arc: enable unaligned access in kernel mode
This enables misaligned access handling even in kernel mode.
Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses
here and there and to cope with that without fixing stuff in the drivers
we're just gracefully handling it on ARC.
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
---
arch/arc/kernel/unaligned.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arc/kernel/unaligned.c
+++ b/arch/arc/kernel/unaligned.c
@@ -202,7 +202,7 @@ int misaligned_fixup(unsigned long addre
char buf[TASK_COMM_LEN];
/* handle user mode only and only if enabled by sysadmin */
- if (!user_mode(regs) || !unaligned_enabled)
+ if (!unaligned_enabled)
return 1;
if (no_unaligned_warning) {

View file

@ -0,0 +1,25 @@
From 66770a004afe10df11d3902e16eaa0c2c39436bb Mon Sep 17 00:00:00 2001
From: Pawel Dembicki <paweldembicki@gmail.com>
Date: Fri, 24 May 2019 17:56:19 +0200
Subject: [PATCH] powerpc: Enable kernel XZ compression option on PPC_85xx
Enable kernel XZ compression option on PPC_85xx. Tested with
simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor).
Suggested-by: Christian Lamparter <chunkeey@gmail.com>
Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
---
arch/powerpc/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -251,7 +251,7 @@ config PPC
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE
select HAVE_KERNEL_LZO if DEFAULT_UIMAGE
- select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x
+ select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x || PPC_85xx
select HAVE_KPROBES
select HAVE_KPROBES_ON_FTRACE
select HAVE_KRETPROBES

View file

@ -0,0 +1,74 @@
From: Shiji Yang <yangshiji66@outlook.com>
Date: Wed, 13 Mar 2024 20:28:37 +0800
Subject: [PATCH] mips: kernel: fix detect_memory_region() function
1. Do not use memcmp() on unallocated memory, as the new introduced
fortify dynamic object size check[1] will report unexpected result.
2. Use a fixed pattern instead of a random function pointer as the
magic value.
3. Flip magic value and double check it.
4. Enable this feature only for 32-bit CPUs. Currently, only ath79 and
ralink CPUs are using it.
[1] 439a1bcac648 ("fortify: Use __builtin_dynamic_object_size() when available")
Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
---
arch/mips/include/asm/bootinfo.h | 2 ++
arch/mips/kernel/setup.c | 17 ++++++++++++-----
2 files changed, 14 insertions(+), 5 deletions(-)
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -93,7 +93,9 @@ const char *get_system_type(void);
extern unsigned long mips_machtype;
+#ifndef CONFIG_64BIT
extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max);
+#endif
extern void prom_init(void);
extern void prom_free_prom_memory(void);
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -90,21 +90,27 @@ static struct resource bss_resource = {
unsigned long __kaslr_offset __ro_after_init;
EXPORT_SYMBOL(__kaslr_offset);
-static void *detect_magic __initdata = detect_memory_region;
-
#ifdef CONFIG_MIPS_AUTO_PFN_OFFSET
unsigned long ARCH_PFN_OFFSET;
EXPORT_SYMBOL(ARCH_PFN_OFFSET);
#endif
+#ifndef CONFIG_64BIT
+static u32 detect_magic __initdata;
+#define MIPS_MEM_TEST_PATTERN 0xaa5555aa
+
void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max)
{
- void *dm = &detect_magic;
+ void *dm = (void *)KSEG1ADDR(&detect_magic);
phys_addr_t size;
for (size = sz_min; size < sz_max; size <<= 1) {
- if (!memcmp(dm, dm + size, sizeof(detect_magic)))
- break;
+ __raw_writel(MIPS_MEM_TEST_PATTERN, dm);
+ if (__raw_readl(dm) == __raw_readl(dm + size)) {
+ __raw_writel(~MIPS_MEM_TEST_PATTERN, dm);
+ if (__raw_readl(dm) == __raw_readl(dm + size))
+ break;
+ }
}
pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n",
@@ -115,6 +121,7 @@ void __init detect_memory_region(phys_ad
memblock_add(start, size);
}
+#endif /* CONFIG_64BIT */
/*
* Manage initrd

View file

@ -0,0 +1,26 @@
From ecb8f9a7d69698ce20fc6f4d107718d56fa861df Mon Sep 17 00:00:00 2001
From: Tony Ambardar <Tony.Ambardar@gmail.com>
Date: Sat, 9 Mar 2024 16:44:53 -0800
Subject: [PATCH] selftests/bpf: Improve portability of unprivileged tests
The addition of general support for unprivileged tests in test_loader.c
breaks building test_verifier on non-glibc (e.g. musl) systems, due to the
inclusion of glibc extension '<error.h>' in 'unpriv_helpers.c'. However,
the header is actually not needed, so remove it to restore building.
Fixes: 1d56ade032a4 ("selftests/bpf: Unprivileged tests for test_loader.c")
Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com>
---
tools/testing/selftests/bpf/unpriv_helpers.c | 1 -
1 file changed, 1 deletion(-)
--- a/tools/testing/selftests/bpf/unpriv_helpers.c
+++ b/tools/testing/selftests/bpf/unpriv_helpers.c
@@ -2,7 +2,6 @@
#include <stdbool.h>
#include <stdlib.h>
-#include <error.h>
#include <stdio.h>
#include "unpriv_helpers.h"

View file

@ -0,0 +1,328 @@
From 39717277d5c87bdb183cf2f258957b44ba99b4df Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 11:47:35 +0200
Subject: [PATCH] mtd: mtdsplit support
---
drivers/mtd/Kconfig | 19 ++++
drivers/mtd/Makefile | 2 +
drivers/mtd/mtdpart.c | 169 ++++++++++++++++++++++++++++-----
include/linux/mtd/mtd.h | 25 +++++
include/linux/mtd/partitions.h | 7 ++
5 files changed, 197 insertions(+), 25 deletions(-)
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -12,6 +12,25 @@ menuconfig MTD
if MTD
+menu "OpenWrt specific MTD options"
+
+config MTD_ROOTFS_ROOT_DEV
+ bool "Automatically set 'rootfs' partition to be root filesystem"
+ default y
+
+config MTD_SPLIT_FIRMWARE
+ bool "Automatically split firmware partition for kernel+rootfs"
+ default y
+
+config MTD_SPLIT_FIRMWARE_NAME
+ string "Firmware partition name"
+ depends on MTD_SPLIT_FIRMWARE
+ default "firmware"
+
+source "drivers/mtd/mtdsplit/Kconfig"
+
+endmenu
+
config MTD_TESTS
tristate "MTD tests support (DANGEROUS)"
depends on m
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc
obj-y += parsers/
+obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
+
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -15,11 +15,13 @@
#include <linux/kmod.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/magic.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include "mtdcore.h"
+#include "mtdsplit/mtdsplit.h"
/*
* MTD methods which simply translate the effective address and pass through
@@ -242,6 +244,147 @@ static int mtd_add_partition_attrs(struc
return ret;
}
+static DEFINE_SPINLOCK(part_parser_lock);
+static LIST_HEAD(part_parsers);
+
+static struct mtd_part_parser *mtd_part_parser_get(const char *name)
+{
+ struct mtd_part_parser *p, *ret = NULL;
+
+ spin_lock(&part_parser_lock);
+
+ list_for_each_entry(p, &part_parsers, list)
+ if (!strcmp(p->name, name) && try_module_get(p->owner)) {
+ ret = p;
+ break;
+ }
+
+ spin_unlock(&part_parser_lock);
+
+ return ret;
+}
+
+static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
+{
+ module_put(p->owner);
+}
+
+static struct mtd_part_parser *
+get_partition_parser_by_type(enum mtd_parser_type type,
+ struct mtd_part_parser *start)
+{
+ struct mtd_part_parser *p, *ret = NULL;
+
+ spin_lock(&part_parser_lock);
+
+ p = list_prepare_entry(start, &part_parsers, list);
+ if (start)
+ mtd_part_parser_put(start);
+
+ list_for_each_entry_continue(p, &part_parsers, list) {
+ if (p->type == type && try_module_get(p->owner)) {
+ ret = p;
+ break;
+ }
+ }
+
+ spin_unlock(&part_parser_lock);
+
+ return ret;
+}
+
+static int parse_mtd_partitions_by_type(struct mtd_info *master,
+ enum mtd_parser_type type,
+ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ struct mtd_part_parser *prev = NULL;
+ int ret = 0;
+
+ while (1) {
+ struct mtd_part_parser *parser;
+
+ parser = get_partition_parser_by_type(type, prev);
+ if (!parser)
+ break;
+
+ ret = (*parser->parse_fn)(master, pparts, data);
+
+ if (ret > 0) {
+ mtd_part_parser_put(parser);
+ printk(KERN_NOTICE
+ "%d %s partitions found on MTD device %s\n",
+ ret, parser->name, master->name);
+ break;
+ }
+
+ prev = parser;
+ }
+
+ return ret;
+}
+
+static int
+run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
+{
+ struct mtd_partition *parts;
+ int nr_parts;
+ int i;
+
+ nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
+ NULL);
+ if (nr_parts <= 0)
+ return nr_parts;
+
+ if (WARN_ON(!parts))
+ return 0;
+
+ for (i = 0; i < nr_parts; i++) {
+ /* adjust partition offsets */
+ parts[i].offset += child->part.offset;
+
+ mtd_add_partition(child->parent,
+ parts[i].name,
+ parts[i].offset,
+ parts[i].size);
+ }
+
+ kfree(parts);
+
+ return nr_parts;
+}
+
+#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
+#else
+#define SPLIT_FIRMWARE_NAME "unused"
+#endif
+
+static void split_firmware(struct mtd_info *master, struct mtd_info *part)
+{
+ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
+}
+
+static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
+{
+ static int rootfs_found = 0;
+
+ if (rootfs_found)
+ return;
+
+ if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) ||
+ !strcmp(part->name, "rootfs")) {
+ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
+
+ rootfs_found = 1;
+ }
+
+ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
+ !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
+ !of_find_property(mtd_get_of_node(part), "compatible", NULL))
+ split_firmware(master, part);
+}
+
int mtd_add_partition(struct mtd_info *parent, const char *name,
long long offset, long long length)
{
@@ -280,6 +423,7 @@ int mtd_add_partition(struct mtd_info *p
if (ret)
goto err_remove_part;
+ mtd_partition_split(parent, child);
mtd_add_partition_attrs(child);
return 0;
@@ -423,6 +567,7 @@ int add_mtd_partitions(struct mtd_info *
goto err_del_partitions;
}
+ mtd_partition_split(master, child);
mtd_add_partition_attrs(child);
/* Look for subpartitions */
@@ -439,31 +584,6 @@ err_del_partitions:
return ret;
}
-static DEFINE_SPINLOCK(part_parser_lock);
-static LIST_HEAD(part_parsers);
-
-static struct mtd_part_parser *mtd_part_parser_get(const char *name)
-{
- struct mtd_part_parser *p, *ret = NULL;
-
- spin_lock(&part_parser_lock);
-
- list_for_each_entry(p, &part_parsers, list)
- if (!strcmp(p->name, name) && try_module_get(p->owner)) {
- ret = p;
- break;
- }
-
- spin_unlock(&part_parser_lock);
-
- return ret;
-}
-
-static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
-{
- module_put(p->owner);
-}
-
/*
* Many partition parsers just expected the core to kfree() all their data in
* one chunk. Do that by default.
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(s
req->len += mtd->erasesize - mod;
}
+static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
+{
+ if (mtd_mod_by_eb(sz, mtd) == 0)
+ return sz;
+
+ /* Round up to next erase block */
+ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
+}
+
+static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
+{
+ if (mtd_mod_by_eb(sz, mtd) == 0)
+ return sz;
+
+ /* Round down to the start of the current erase block */
+ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
+}
+
static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
{
if (mtd->writesize_shift)
@@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_devic
extern struct mtd_info *get_mtd_device_nm(const char *name);
extern void put_mtd_device(struct mtd_info *mtd);
+static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
+{
+ if (!mtd_is_partition(mtd))
+ return 0;
+
+ return mtd->part.offset;
+}
struct mtd_notifier {
void (*add)(struct mtd_info *mtd);
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -75,6 +75,12 @@ struct mtd_part_parser_data {
* Functions dealing with the various ways of partitioning the space
*/
+enum mtd_parser_type {
+ MTD_PARSER_TYPE_DEVICE = 0,
+ MTD_PARSER_TYPE_ROOTFS,
+ MTD_PARSER_TYPE_FIRMWARE,
+};
+
struct mtd_part_parser {
struct list_head list;
struct module *owner;
@@ -83,6 +89,7 @@ struct mtd_part_parser {
int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
struct mtd_part_parser_data *);
void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
+ enum mtd_parser_type type;
};
/* Container for passing around a set of parsed partitions */

View file

@ -0,0 +1,48 @@
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Tue, 31 Oct 2023 15:51:01 +0100
Subject: [PATCH] mtd: don't register NVMEM devices for partitions with custom
drivers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This fixes issue exposed by upstream commit f4cf4e5db331 ("Revert
"nvmem: add new config option"").
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
drivers/mtd/mtdcore.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -548,6 +548,29 @@ static int mtd_nvmem_add(struct mtd_info
struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {};
+ /*
+ * Do NOT register NVMEM device for any partition that is meant to be
+ * handled by a U-Boot env driver. That would result in associating two
+ * different NVMEM devices with the same OF node.
+ *
+ * An example of unwanted behaviour of above (forwardtrace):
+ * of_get_mac_addr_nvmem()
+ * of_nvmem_cell_get()
+ * __nvmem_device_get()
+ *
+ * We can't have __nvmem_device_get() return "mtdX" NVMEM device instead
+ * of U-Boot env NVMEM device. That would result in failing to find
+ * NVMEM cell.
+ *
+ * This issue seems to affect U-Boot env case only and will go away with
+ * switch to NVMEM layouts.
+ */
+ if (of_device_is_compatible(node, "u-boot,env") ||
+ of_device_is_compatible(node, "u-boot,env-redundant-bool") ||
+ of_device_is_compatible(node, "u-boot,env-redundant-count") ||
+ of_device_is_compatible(node, "brcm,env"))
+ return 0;
+
config.id = NVMEM_DEVID_NONE;
config.dev = &mtd->dev;
config.name = dev_name(&mtd->dev);

View file

@ -0,0 +1,41 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable)
[john@phrozen.org: used by ixp and others]
lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/mtd/redboot.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
--- a/drivers/mtd/parsers/redboot.c
+++ b/drivers/mtd/parsers/redboot.c
@@ -278,14 +278,21 @@ nogood:
#endif
names += strlen(names) + 1;
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
- i++;
- parts[i].offset = parts[i - 1].size + parts[i - 1].offset;
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
- parts[i].name = nullname;
- }
+ if (!strcmp(parts[i].name, "rootfs")) {
+ parts[i].size = fl->next->img->flash_base;
+ parts[i].size &= ~(master->erasesize - 1);
+ parts[i].size -= parts[i].offset;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ nrparts--;
+ } else {
+ i++;
+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
+ parts[i].name = nullname;
#endif
+ }
+ }
tmp_fl = fl;
fl = fl->next;
kfree(tmp_fl);

View file

@ -0,0 +1,229 @@
From: Florian Fainelli <f.fainelli@gmail.com>
Subject: Add myloader partition table parser
[john@phozen.org: shoud be upstreamable]
lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
[adjust for kernel 5.4, add myloader.c to patch]
Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -67,6 +67,22 @@ config MTD_CMDLINE_PARTS
If unsure, say 'N'.
+config MTD_MYLOADER_PARTS
+ tristate "MyLoader partition parsing"
+ depends on ADM5120 || ATH79
+ help
+ MyLoader is a bootloader which allows the user to define partitions
+ in flash devices, by putting a table in the second erase block
+ on the device, similar to a partition table. This table gives the
+ offsets and lengths of the user defined partitions.
+
+ If you need code which can detect and parse these tables, and
+ register MTD 'partitions' corresponding to each image detected,
+ enable this option.
+
+ You will still need the parsing functions to be called by the driver
+ for your particular device. It won't happen automatically.
+
config MTD_OF_PARTS
tristate "OpenFirmware (device tree) partitioning parser"
default y
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm4
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
obj-$(CONFIG_MTD_BRCM_U_BOOT) += brcm_u-boot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
ofpart-y += ofpart_core.o
ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
--- /dev/null
+++ b/drivers/mtd/parsers/myloader.c
@@ -0,0 +1,181 @@
+/*
+ * Parse MyLoader-style flash partition tables and produce a Linux partition
+ * array to match.
+ *
+ * Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file was based on drivers/mtd/redboot.c
+ * Author: Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/myloader.h>
+
+#define BLOCK_LEN_MIN 0x10000
+#define PART_NAME_LEN 32
+
+struct part_data {
+ struct mylo_partition_table tab;
+ char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
+};
+
+static int myloader_parse_partitions(struct mtd_info *master,
+ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ struct part_data *buf;
+ struct mylo_partition_table *tab;
+ struct mylo_partition *part;
+ struct mtd_partition *mtd_parts;
+ struct mtd_partition *mtd_part;
+ int num_parts;
+ int ret, i;
+ size_t retlen;
+ char *names;
+ unsigned long offset;
+ unsigned long blocklen;
+
+ buf = vmalloc(sizeof(*buf));
+ if (!buf) {
+ return -ENOMEM;
+ goto out;
+ }
+ tab = &buf->tab;
+
+ blocklen = master->erasesize;
+ if (blocklen < BLOCK_LEN_MIN)
+ blocklen = BLOCK_LEN_MIN;
+
+ offset = blocklen;
+
+ /* Find the partition table */
+ for (i = 0; i < 4; i++, offset += blocklen) {
+ printk(KERN_DEBUG "%s: searching for MyLoader partition table"
+ " at offset 0x%lx\n", master->name, offset);
+
+ ret = mtd_read(master, offset, sizeof(*buf), &retlen,
+ (void *)buf);
+ if (ret)
+ goto out_free_buf;
+
+ if (retlen != sizeof(*buf)) {
+ ret = -EIO;
+ goto out_free_buf;
+ }
+
+ /* Check for Partition Table magic number */
+ if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
+ break;
+
+ }
+
+ if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
+ printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
+ master->name);
+ ret = 0;
+ goto out_free_buf;
+ }
+
+ /* The MyLoader and the Partition Table is always present */
+ num_parts = 2;
+
+ /* Detect number of used partitions */
+ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
+ part = &tab->partitions[i];
+
+ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
+ continue;
+
+ num_parts++;
+ }
+
+ mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
+ num_parts * PART_NAME_LEN), GFP_KERNEL);
+
+ if (!mtd_parts) {
+ ret = -ENOMEM;
+ goto out_free_buf;
+ }
+
+ mtd_part = mtd_parts;
+ names = (char *)&mtd_parts[num_parts];
+
+ strncpy(names, "myloader", PART_NAME_LEN);
+ mtd_part->name = names;
+ mtd_part->offset = 0;
+ mtd_part->size = offset;
+ mtd_part->mask_flags = MTD_WRITEABLE;
+ mtd_part++;
+ names += PART_NAME_LEN;
+
+ strncpy(names, "partition_table", PART_NAME_LEN);
+ mtd_part->name = names;
+ mtd_part->offset = offset;
+ mtd_part->size = blocklen;
+ mtd_part->mask_flags = MTD_WRITEABLE;
+ mtd_part++;
+ names += PART_NAME_LEN;
+
+ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
+ part = &tab->partitions[i];
+
+ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
+ continue;
+
+ if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
+ strncpy(names, buf->names[i], PART_NAME_LEN);
+ else
+ snprintf(names, PART_NAME_LEN, "partition%d", i);
+
+ mtd_part->offset = le32_to_cpu(part->addr);
+ mtd_part->size = le32_to_cpu(part->size);
+ mtd_part->name = names;
+ mtd_part++;
+ names += PART_NAME_LEN;
+ }
+
+ *pparts = mtd_parts;
+ ret = num_parts;
+
+ out_free_buf:
+ vfree(buf);
+ out:
+ return ret;
+}
+
+static struct mtd_part_parser myloader_mtd_parser = {
+ .owner = THIS_MODULE,
+ .parse_fn = myloader_parse_partitions,
+ .name = "MyLoader",
+};
+
+static int __init myloader_mtd_parser_init(void)
+{
+ register_mtd_parser(&myloader_mtd_parser);
+
+ return 0;
+}
+
+static void __exit myloader_mtd_parser_exit(void)
+{
+ deregister_mtd_parser(&myloader_mtd_parser);
+}
+
+module_init(myloader_mtd_parser_init);
+module_exit(myloader_mtd_parser_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
+MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,68 @@
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating offsets
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
--- a/drivers/mtd/parsers/parser_trx.c
+++ b/drivers/mtd/parsers/parser_trx.c
@@ -25,6 +25,33 @@ struct trx_header {
uint32_t offset[3];
} __packed;
+/*
+ * Calculate real end offset (address) for a given amount of data. It checks
+ * all blocks skipping bad ones.
+ */
+static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes)
+{
+ size_t real_offset = 0;
+
+ if (mtd_block_isbad(mtd, real_offset))
+ pr_warn("Base offset shouldn't be at bad block");
+
+ while (bytes >= mtd->erasesize) {
+ bytes -= mtd->erasesize;
+ real_offset += mtd->erasesize;
+ while (mtd_block_isbad(mtd, real_offset)) {
+ real_offset += mtd->erasesize;
+
+ if (real_offset >= mtd->size)
+ return real_offset - mtd->erasesize;
+ }
+ }
+
+ real_offset += bytes;
+
+ return real_offset;
+}
+
static const char *parser_trx_data_part_name(struct mtd_info *master,
size_t offset)
{
@@ -86,21 +113,21 @@ static int parser_trx_parse(struct mtd_i
if (trx.offset[2]) {
part = &parts[curr_part++];
part->name = "loader";
- part->offset = trx.offset[i];
+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
i++;
}
if (trx.offset[i]) {
part = &parts[curr_part++];
part->name = "linux";
- part->offset = trx.offset[i];
+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
i++;
}
if (trx.offset[i]) {
part = &parts[curr_part++];
- part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
- part->offset = trx.offset[i];
+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
+ part->name = parser_trx_data_part_name(mtd, part->offset);
i++;
}

View file

@ -0,0 +1,37 @@
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Subject: mtd: bcm47xxpart: detect T_Meter partition
It can be found on many Netgear devices. It consists of many 0x30 blocks
starting with 4D 54.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
drivers/mtd/bcm47xxpart.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/mtd/parsers/bcm47xxpart.c
+++ b/drivers/mtd/parsers/bcm47xxpart.c
@@ -35,6 +35,7 @@
#define NVRAM_HEADER 0x48534C46 /* FLSH */
#define POT_MAGIC1 0x54544f50 /* POTT */
#define POT_MAGIC2 0x504f /* OP */
+#define T_METER_MAGIC 0x4D540000 /* MT */
#define ML_MAGIC1 0x39685a42
#define ML_MAGIC2 0x26594131
#define TRX_MAGIC 0x30524448
@@ -178,6 +179,15 @@ static int bcm47xxpart_parse(struct mtd_
MTD_WRITEABLE);
continue;
}
+
+ /* T_Meter */
+ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
+ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
+ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
+ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
+ MTD_WRITEABLE);
+ continue;
+ }
/* TRX */
if (buf[0x000 / 4] == TRX_MAGIC) {

View file

@ -0,0 +1,38 @@
From 4437e01fb6bca63fccdba5d6c44888b0935885c2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org>
Date: Tue, 24 Mar 2020 11:45:07 +0100
Subject: [PATCH] generic: routerboot partition build bits (5.4)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch adds routerbootpart kernel build bits
Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
---
drivers/mtd/parsers/Kconfig | 9 +++++++++
drivers/mtd/parsers/Makefile | 1 +
2 files changed, 10 insertions(+)
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -236,3 +236,12 @@ config MTD_SERCOMM_PARTS
partition map. This partition table contains real partition
offsets, which may differ from device to device depending on the
number and location of bad blocks on NAND.
+
+config MTD_ROUTERBOOT_PARTS
+ tristate "RouterBoot flash partition parser"
+ depends on MTD && OF
+ help
+ MikroTik RouterBoot is implemented as a multi segment system on the
+ flash, some of which are fixed and some of which are located at
+ variable offsets. This parser handles both cases via properly
+ formatted DTS.
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpa
obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o
+obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o

View file

@ -0,0 +1,120 @@
From 3245921a87154bdfbe7a55d743ea62dd559a8fb0 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:13:09 +0100
Subject: [PATCH 1/9] dt-bindings: block: add basic bindings for block devices
Add bindings for block devices which are used to allow referencing
nvmem bits on them.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
.../bindings/block/block-device.yaml | 22 ++++++++
.../devicetree/bindings/block/partition.yaml | 51 +++++++++++++++++++
.../devicetree/bindings/block/partitions.yaml | 20 ++++++++
3 files changed, 93 insertions(+)
create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml
create mode 100644 Documentation/devicetree/bindings/block/partition.yaml
create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml
--- /dev/null
+++ b/Documentation/devicetree/bindings/block/block-device.yaml
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/block/block-device.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: block storage device
+
+description: |
+ This binding is generic and describes a block-oriented storage device.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+properties:
+ partitions:
+ $ref: /schemas/block/partitions.yaml
+
+ nvmem-layout:
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
+
+unevaluatedProperties: false
--- /dev/null
+++ b/Documentation/devicetree/bindings/block/partition.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/block/partition.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Partition on a block device
+
+description: |
+ This binding describes a partition on a block device.
+ Partitions may be matched by a combination of partition number, name,
+ and UUID.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+properties:
+ $nodename:
+ pattern: '^block-partition-.+$'
+
+ partnum:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Matches partition by number if present.
+
+ partname:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Matches partition by PARTNAME if present.
+
+ partuuid:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Matches partition by PARTUUID if present.
+
+ nvmem-layout:
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
+ description:
+ This container may reference an NVMEM layout parser.
+
+anyOf:
+ - required:
+ - partnum
+
+ - required:
+ - partname
+
+ - required:
+ - partuuid
+
+unevaluatedProperties: false
--- /dev/null
+++ b/Documentation/devicetree/bindings/block/partitions.yaml
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/block/partitions.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Partitions on block devices
+
+description: |
+ This binding is generic and describes the content of the partitions container
+ node.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+patternProperties:
+ "^block-partition-.+$":
+ $ref: partition.yaml
+
+unevaluatedProperties: false

View file

@ -0,0 +1,145 @@
From e07ace307ce598847074a096f408bec0e3a392ed Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:14:34 +0100
Subject: [PATCH 3/9] block: add support for notifications
Add notifier block to notify other subsystems about the addition or
removal of block devices.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
block/Kconfig | 6 +++
block/Makefile | 1 +
block/blk-notify.c | 88 ++++++++++++++++++++++++++++++++++++++++++
include/linux/blkdev.h | 8 ++++
4 files changed, 103 insertions(+)
create mode 100644 block/blk-notify.c
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -208,6 +208,12 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
by falling back to the kernel crypto API when inline
encryption hardware is not present.
+config BLOCK_NOTIFIERS
+ bool "Enable support for notifications in block layer"
+ help
+ Enable this option to provide notifiers for other subsystems
+ upon addition or removal of block devices.
+
source "block/partitions/Kconfig"
config BLK_MQ_PCI
--- a/block/Makefile
+++ b/block/Makefile
@@ -40,3 +40,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += b
blk-crypto-sysfs.o
obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
+obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o
--- /dev/null
+++ b/block/blk-notify.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Notifiers for addition and removal of block devices
+ *
+ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
+ */
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+
+#include "blk.h"
+
+struct blk_device_list {
+ struct device *dev;
+ struct list_head list;
+};
+
+static RAW_NOTIFIER_HEAD(blk_notifier_list);
+static DEFINE_MUTEX(blk_notifier_lock);
+static LIST_HEAD(blk_devices);
+
+void blk_register_notify(struct notifier_block *nb)
+{
+ struct blk_device_list *existing_blkdev;
+
+ mutex_lock(&blk_notifier_lock);
+ raw_notifier_chain_register(&blk_notifier_list, nb);
+
+ list_for_each_entry(existing_blkdev, &blk_devices, list)
+ nb->notifier_call(nb, BLK_DEVICE_ADD, existing_blkdev->dev);
+
+ mutex_unlock(&blk_notifier_lock);
+}
+EXPORT_SYMBOL_GPL(blk_register_notify);
+
+void blk_unregister_notify(struct notifier_block *nb)
+{
+ mutex_lock(&blk_notifier_lock);
+ raw_notifier_chain_unregister(&blk_notifier_list, nb);
+ mutex_unlock(&blk_notifier_lock);
+}
+EXPORT_SYMBOL_GPL(blk_unregister_notify);
+
+static int blk_call_notifier_add(struct device *dev)
+{
+ struct blk_device_list *new_blkdev;
+
+ new_blkdev = kmalloc(sizeof(*new_blkdev), GFP_KERNEL);
+ if (!new_blkdev)
+ return -ENOMEM;
+
+ new_blkdev->dev = dev;
+ mutex_lock(&blk_notifier_lock);
+ list_add_tail(&new_blkdev->list, &blk_devices);
+ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, dev);
+ mutex_unlock(&blk_notifier_lock);
+
+ return 0;
+}
+
+static void blk_call_notifier_remove(struct device *dev)
+{
+ struct blk_device_list *old_blkdev, *tmp;
+
+ mutex_lock(&blk_notifier_lock);
+ list_for_each_entry_safe(old_blkdev, tmp, &blk_devices, list) {
+ if (old_blkdev->dev != dev)
+ continue;
+
+ list_del(&old_blkdev->list);
+ kfree(old_blkdev);
+ }
+ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_REMOVE, dev);
+ mutex_unlock(&blk_notifier_lock);
+}
+
+static struct class_interface blk_notifications_bus_interface __refdata = {
+ .class = &block_class,
+ .add_dev = &blk_call_notifier_add,
+ .remove_dev = &blk_call_notifier_remove,
+};
+
+static int __init blk_notifications_init(void)
+{
+ return class_interface_register(&blk_notifications_bus_interface);
+}
+device_initcall(blk_notifications_init);
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1564,4 +1564,12 @@ struct io_comp_batch {
#define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { }
+
+#ifdef CONFIG_BLOCK_NOTIFIERS
+#define BLK_DEVICE_ADD 1
+#define BLK_DEVICE_REMOVE 2
+void blk_register_notify(struct notifier_block *nb);
+void blk_unregister_notify(struct notifier_block *nb);
+#endif
+
#endif /* _LINUX_BLKDEV_H */

View file

@ -0,0 +1,29 @@
From f4487fa1cb7e55b3c17a33f41b9c9d66f4f853b7 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:14:49 +0100
Subject: [PATCH 4/9] block: add new genhd flag GENHD_FL_NVMEM
Add new flag to destinguish block devices which may act as an NVMEM
provider.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
include/linux/blkdev.h | 2 ++
1 file changed, 2 insertions(+)
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -80,11 +80,13 @@ struct partition_meta_info {
* ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not
* scan for partitions from add_disk, and users can't add partitions manually.
*
+ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
*/
enum {
GENHD_FL_REMOVABLE = 1 << 0,
GENHD_FL_HIDDEN = 1 << 1,
GENHD_FL_NO_PART = 1 << 2,
+ GENHD_FL_NVMEM = 1 << 3,
};
enum {

View file

@ -0,0 +1,260 @@
From 9703951cdfe868b130e64d6122420396c2807be8 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:02 +0100
Subject: [PATCH 5/9] nvmem: implement block NVMEM provider
On embedded devices using an eMMC it is common that one or more partitions
on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
data. Allow referencing any block device or partition in Device Tree to
allow e.g. Ethernet and Wi-Fi drivers accessing them via the NVMEM layer.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/nvmem/Kconfig | 11 +++
drivers/nvmem/Makefile | 2 +
drivers/nvmem/block.c | 197 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 210 insertions(+)
create mode 100644 drivers/nvmem/block.c
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -40,6 +40,17 @@ config NVMEM_APPLE_EFUSES
This driver can also be built as a module. If so, the module will
be called nvmem-apple-efuses.
+config NVMEM_BLOCK
+ tristate "Block device NVMEM provider"
+ depends on BLOCK
+ depends on OF
+ depends on NVMEM
+ select BLOCK_NOTIFIERS
+ help
+ Allow block devices (or partitions) to act as NVMEM prodivers,
+ typically used with eMMC to store MAC addresses or Wi-Fi
+ calibration data on embedded devices.
+
config NVMEM_BCM_OCOTP
tristate "Broadcom On-Chip OTP Controller support"
depends on ARCH_BCM_IPROC || COMPILE_TEST
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -14,6 +14,8 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvme
nvmem-apple-efuses-y := apple-efuses.o
obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o
nvmem-bcm-ocotp-y := bcm-ocotp.o
+obj-$(CONFIG_NVMEM_BLOCK) += nvmem-block.o
+nvmem-block-y := block.o
obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
nvmem_brcm_nvram-y := brcm_nvram.o
obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o
--- /dev/null
+++ b/drivers/nvmem/block.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * block device NVMEM provider
+ *
+ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
+ *
+ * Useful on devices using a partition on an eMMC for MAC addresses or
+ * Wi-Fi calibration EEPROM data.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <linux/pagemap.h>
+#include <linux/property.h>
+
+/* List of all NVMEM devices */
+static LIST_HEAD(nvmem_devices);
+static DEFINE_MUTEX(devices_mutex);
+
+struct blk_nvmem {
+ struct nvmem_device *nvmem;
+ struct block_device *bdev;
+ struct list_head list;
+};
+
+static int blk_nvmem_reg_read(void *priv, unsigned int from,
+ void *val, size_t bytes)
+{
+ unsigned long offs = from & ~PAGE_MASK, to_read;
+ pgoff_t f_index = from >> PAGE_SHIFT;
+ struct address_space *mapping;
+ struct blk_nvmem *bnv = priv;
+ size_t bytes_left = bytes;
+ struct folio *folio;
+ void *p;
+ int ret;
+
+ if (!bnv->bdev)
+ return -ENODEV;
+
+ if (!bnv->bdev->bd_disk)
+ return -EINVAL;
+
+ if (!bnv->bdev->bd_disk->fops)
+ return -EIO;
+
+ if (!bnv->bdev->bd_disk->fops->open)
+ return -EIO;
+
+ ret = bnv->bdev->bd_disk->fops->open(bnv->bdev->bd_disk, BLK_OPEN_READ);
+ if (ret)
+ return ret;
+
+ mapping = bnv->bdev->bd_inode->i_mapping;
+
+ while (bytes_left) {
+ folio = read_mapping_folio(mapping, f_index++, NULL);
+ if (IS_ERR(folio)) {
+ ret = PTR_ERR(folio);
+ goto err_release_bdev;
+ }
+ to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs);
+ p = folio_address(folio) + offset_in_folio(folio, offs);
+ memcpy(val, p, to_read);
+ offs = 0;
+ bytes_left -= to_read;
+ val += to_read;
+ folio_put(folio);
+ }
+
+err_release_bdev:
+ bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk);
+
+ return ret;
+}
+
+static int blk_nvmem_register(struct device *dev)
+{
+ struct device_node *np = dev_of_node(dev);
+ struct block_device *bdev = dev_to_bdev(dev);
+ struct nvmem_config config = {};
+ struct blk_nvmem *bnv;
+
+ /* skip devices which do not have a device tree node */
+ if (!np)
+ return 0;
+
+ /* skip devices without an nvmem layout defined */
+ if (!of_get_child_by_name(np, "nvmem-layout"))
+ return 0;
+
+ /*
+ * skip devices which don't have GENHD_FL_NVMEM set
+ *
+ * This flag is used for mtdblock and ubiblock devices because
+ * both, MTD and UBI already implement their own NVMEM provider.
+ * To avoid registering multiple NVMEM providers for the same
+ * device node, don't register the block NVMEM provider for them.
+ */
+ if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM))
+ return 0;
+
+ /*
+ * skip block device too large to be represented as NVMEM devices
+ * which are using an 'int' as address
+ */
+ if (bdev_nr_bytes(bdev) > INT_MAX)
+ return -EFBIG;
+
+ bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL);
+ if (!bnv)
+ return -ENOMEM;
+
+ config.id = NVMEM_DEVID_NONE;
+ config.dev = &bdev->bd_device;
+ config.name = dev_name(&bdev->bd_device);
+ config.owner = THIS_MODULE;
+ config.priv = bnv;
+ config.reg_read = blk_nvmem_reg_read;
+ config.size = bdev_nr_bytes(bdev);
+ config.word_size = 1;
+ config.stride = 1;
+ config.read_only = true;
+ config.root_only = true;
+ config.ignore_wp = true;
+ config.of_node = to_of_node(dev->fwnode);
+
+ bnv->bdev = bdev;
+ bnv->nvmem = nvmem_register(&config);
+ if (IS_ERR(bnv->nvmem)) {
+ dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
+ "Failed to register NVMEM device\n");
+
+ kfree(bnv);
+ return PTR_ERR(bnv->nvmem);
+ }
+
+ mutex_lock(&devices_mutex);
+ list_add_tail(&bnv->list, &nvmem_devices);
+ mutex_unlock(&devices_mutex);
+
+ return 0;
+}
+
+static void blk_nvmem_unregister(struct device *dev)
+{
+ struct block_device *bdev = dev_to_bdev(dev);
+ struct blk_nvmem *bnv_c, *bnv = NULL;
+
+ mutex_lock(&devices_mutex);
+ list_for_each_entry(bnv_c, &nvmem_devices, list) {
+ if (bnv_c->bdev == bdev) {
+ bnv = bnv_c;
+ break;
+ }
+ }
+
+ if (!bnv) {
+ mutex_unlock(&devices_mutex);
+ return;
+ }
+
+ list_del(&bnv->list);
+ mutex_unlock(&devices_mutex);
+ nvmem_unregister(bnv->nvmem);
+ kfree(bnv);
+}
+
+static int blk_nvmem_handler(struct notifier_block *this, unsigned long code, void *obj)
+{
+ struct device *dev = (struct device *)obj;
+
+ switch (code) {
+ case BLK_DEVICE_ADD:
+ return blk_nvmem_register(dev);
+ case BLK_DEVICE_REMOVE:
+ blk_nvmem_unregister(dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct notifier_block blk_nvmem_notifier = {
+ .notifier_call = blk_nvmem_handler,
+};
+
+static int __init blk_nvmem_init(void)
+{
+ blk_register_notify(&blk_nvmem_notifier);
+
+ return 0;
+}
+
+static void __exit blk_nvmem_exit(void)
+{
+ blk_unregister_notify(&blk_nvmem_notifier);
+}
+
+module_init(blk_nvmem_init);
+module_exit(blk_nvmem_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
+MODULE_DESCRIPTION("block device NVMEM provider");

View file

@ -0,0 +1,74 @@
From f7ec19b34d1b7e934a58ceb102369bbd30b2631d Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:11 +0100
Subject: [PATCH 6/9] dt-bindings: mmc: mmc-card: add block device nodes
Add nodes representing the block devices exposed by an MMC device
including an example involving nvmem-cells.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
.../devicetree/bindings/mmc/mmc-card.yaml | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
@@ -26,6 +26,18 @@ properties:
Use this to indicate that the mmc-card has a broken hpi
implementation, and that hpi should not be used.
+ block:
+ $ref: /schemas/block/block-device.yaml#
+ description:
+ Represents the block storage provided by an SD card or the
+ main hardware partition of an eMMC.
+
+patternProperties:
+ '^boot[0-9]+':
+ $ref: /schemas/block/block-device.yaml#
+ description:
+ Represents a boot hardware partition on an eMMC.
+
required:
- compatible
- reg
@@ -42,6 +54,39 @@ examples:
compatible = "mmc-card";
reg = <0>;
broken-hpi;
+
+ block {
+ partitions {
+ cal_data: block-partition-rf {
+ partnum = <3>;
+ partname = "rf";
+
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ eeprom@0 {
+ reg = <0x0 0x1000>;
+ };
+ };
+ };
+ };
+ };
+
+ boot1 {
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ macaddr: macaddr@a {
+ compatible = "mac-base";
+ reg = <0xa 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+ };
+ };
};
};

View file

@ -0,0 +1,23 @@
From 043c4f88476cc0f29c9bf82a8a516f58d848e1cd Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:25 +0100
Subject: [PATCH 7/9] mmc: core: set card fwnode_handle
Set fwnode in case it isn't set yet and of_node is present.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mmc/core/bus.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -364,6 +364,8 @@ int mmc_add_card(struct mmc_card *card)
mmc_add_card_debugfs(card);
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
+ if (card->dev.of_node && !card->dev.fwnode)
+ card->dev.fwnode = &card->dev.of_node->fwnode;
device_enable_async_suspend(&card->dev);

View file

@ -0,0 +1,37 @@
From ef3e38fec26901b71975d7e810a2df6b8bd54a8e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:36 +0100
Subject: [PATCH 8/9] mmc: block: set fwnode of disk devices
Set fwnode of disk devices to 'block', 'boot0' and 'boot1' subnodes of
the mmc-card. This is done in preparation for having the eMMC act as
NVMEM provider.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mmc/core/block.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2463,6 +2463,7 @@ static struct mmc_blk_data *mmc_blk_allo
int area_type,
unsigned int part_type)
{
+ struct fwnode_handle *fwnode;
struct mmc_blk_data *md;
int devidx, ret;
char cap_str[10];
@@ -2559,6 +2560,12 @@ static struct mmc_blk_data *mmc_blk_allo
blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled);
+ fwnode = device_get_named_child_node(subname ? md->parent->parent :
+ md->parent,
+ subname ? subname : "block");
+ if (fwnode)
+ device_set_node(disk_to_dev(md->disk), fwnode);
+
string_get_size((u64)size, 512, STRING_UNITS_2,
cap_str, sizeof(cap_str));
pr_info("%s: %s %s %s%s\n",

View file

@ -0,0 +1,22 @@
From 7903b50441000365a6fe5badb39735889f562252 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:46 +0100
Subject: [PATCH 9/9] mmc: block: set GENHD_FL_NVMEM
Set flag to consider MMC block devices as NVMEM providers.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mmc/core/block.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2516,6 +2516,7 @@ static struct mmc_blk_data *mmc_blk_allo
md->disk->major = MMC_BLOCK_MAJOR;
md->disk->minors = perdev_minors;
md->disk->first_minor = devidx * perdev_minors;
+ md->disk->flags = GENHD_FL_NVMEM;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
md->parent = parent;

View file

@ -0,0 +1,25 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: kernel: disable cfi cmdset 0002 erase suspend
on some platforms, erase suspend leads to data corruption and lockups when write
ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh.
rather than play whack-a-mole with a hard to reproduce issue on a variety of devices,
simply disable erase suspend, as it will usually not produce any useful gain on
the small filesystems used on embedded hardware.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/mtd/chips/cfi_cmdset_0002.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -906,7 +906,7 @@ static int get_chip(struct map_info *map
return 0;
case FL_ERASING:
- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
+ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
!(mode == FL_READY || mode == FL_POINT ||
(mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
goto sleep;

View file

@ -0,0 +1,17 @@
From: George Kashperko <george@znau.edu.ua>
Subject: Issue map read after Write Buffer Load command to ensure chip is ready to receive data.
Signed-off-by: George Kashperko <george@znau.edu.ua>
---
drivers/mtd/chips/cfi_cmdset_0002.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -2050,6 +2050,7 @@ static int __xipram do_write_buffer(stru
/* Write Buffer Load */
map_write(map, CMD(0x25), cmd_adr);
+ (void) map_read(map, cmd_adr);
chip->state = FL_WRITING_TO_BUFFER;

View file

@ -0,0 +1,18 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: Disable software protection bits for Macronix flashes.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
drivers/mtd/spi-nor/spi-nor.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -114,6 +114,7 @@ static int macronix_nor_late_init(struct
{
if (!nor->params->set_4byte_addr_mode)
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
+ nor->flags |= SNOR_F_HAS_LOCK;
return 0;
}

View file

@ -0,0 +1,77 @@
From: Daniel Golle <daniel@makrotopia.org>
Subject: ubi: auto-create ubiblock device for rootfs
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -570,10 +570,47 @@ match_volume_desc(struct ubi_volume_info
return true;
}
+#define UBIFS_NODE_MAGIC 0x06101831
+static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
+{
+ int ret;
+ uint32_t magic_of, magic;
+ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
+ if (ret)
+ return 0;
+ magic = le32_to_cpu(magic_of);
+ return magic == UBIFS_NODE_MAGIC;
+}
+
+static void __init ubiblock_create_auto_rootfs(struct ubi_volume_info *vi)
+{
+ int ret, is_ubifs;
+ struct ubi_volume_desc *desc;
+
+ if (strcmp(vi->name, "rootfs") &&
+ strcmp(vi->name, "fit"))
+ return;
+
+ desc = ubi_open_volume(vi->ubi_num, vi->vol_id, UBI_READONLY);
+ if (IS_ERR(desc))
+ return;
+
+ is_ubifs = ubi_vol_is_ubifs(desc);
+ ubi_close_volume(desc);
+ if (is_ubifs)
+ return;
+
+ ret = ubiblock_create(vi);
+ if (ret)
+ pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
+ vi->name, ret);
+}
+
static void
ubiblock_create_from_param(struct ubi_volume_info *vi)
{
int i, ret = 0;
+ bool got_param = false;
struct ubiblock_param *p;
/*
@@ -586,6 +623,7 @@ ubiblock_create_from_param(struct ubi_vo
if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
continue;
+ got_param = true;
ret = ubiblock_create(vi);
if (ret) {
pr_err(
@@ -594,6 +632,10 @@ ubiblock_create_from_param(struct ubi_vo
}
break;
}
+
+ /* auto-attach "rootfs" volume if existing and non-ubifs */
+ if (!got_param && IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
+ ubiblock_create_auto_rootfs(vi);
}
static int ubiblock_notify(struct notifier_block *nb,

View file

@ -0,0 +1,54 @@
From: Daniel Golle <daniel@makrotopia.org>
Subject: try auto-mounting ubi0:rootfs in init/do_mounts.c
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
init/do_mounts.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -248,7 +248,30 @@ retry:
out:
put_page(page);
}
-
+
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+static int __init mount_ubi_rootfs(void)
+{
+ int flags = MS_SILENT;
+ int err, tried = 0;
+
+ while (tried < 2) {
+ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
+ root_mount_data);
+ switch (err) {
+ case -EACCES:
+ flags |= MS_RDONLY;
+ tried++;
+ break;
+ default:
+ return err;
+ }
+ }
+
+ return -EINVAL;
+}
+#endif
+
#ifdef CONFIG_ROOT_NFS
#define NFSROOT_TIMEOUT_MIN 5
@@ -385,6 +408,11 @@ static inline void mount_block_root(char
void __init mount_root(char *root_device_name)
{
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+ if (!mount_ubi_rootfs())
+ return;
+#endif
+
switch (ROOT_DEV) {
case Root_NFS:
mount_nfs_root();

View file

@ -0,0 +1,34 @@
From: Daniel Golle <daniel@makrotopia.org>
Subject: ubi: set ROOT_DEV to ubiblock "rootfs" if unset
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -41,6 +41,7 @@
#include <linux/scatterlist.h>
#include <linux/idr.h>
#include <asm/div64.h>
+#include <linux/root_dev.h>
#include "ubi-media.h"
#include "ubi.h"
@@ -428,6 +429,15 @@ int ubiblock_create(struct ubi_volume_in
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
dev->ubi_num, dev->vol_id, vi->name);
mutex_unlock(&devices_mutex);
+
+ if (!strcmp(vi->name, "rootfs") &&
+ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
+ ROOT_DEV == 0) {
+ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
+ dev->ubi_num, dev->vol_id, vi->name);
+ ROOT_DEV = MKDEV(gd->major, gd->first_minor);
+ }
+
return 0;
out_remove_minor:

View file

@ -0,0 +1,60 @@
From: Gabor Juhos <juhosg@openwrt.org>
Subject: mtd: add EOF marker support to the UBI layer
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++---
drivers/mtd/ubi/ubi.h | 1 +
2 files changed, 23 insertions(+), 3 deletions(-)
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -926,6 +926,13 @@ static bool vol_ignored(int vol_id)
#endif
}
+static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
+{
+ return ech->padding1[0] == 'E' &&
+ ech->padding1[1] == 'O' &&
+ ech->padding1[2] == 'F';
+}
+
/**
* scan_peb - scan and process UBI headers of a PEB.
* @ubi: UBI device description object
@@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *u
return 0;
}
- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
- if (err < 0)
- return err;
+ if (!ai->eof_found) {
+ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+ if (err < 0)
+ return err;
+
+ if (ec_hdr_has_eof(ech)) {
+ pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n",
+ pnum);
+ ai->eof_found = true;
+ }
+ }
+
+ if (ai->eof_found)
+ err = UBI_IO_FF_BITFLIPS;
+
switch (err) {
case 0:
break;
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -780,6 +780,7 @@ struct ubi_attach_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
+ bool eof_found;
struct kmem_cache *aeb_slab_cache;
struct ubi_ec_hdr *ech;
struct ubi_vid_io_buf *vidb;

View file

@ -0,0 +1,52 @@
From 5734c6669fba7ddb5ef491ccff7159d15dba0b59 Mon Sep 17 00:00:00 2001
From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
Date: Wed, 5 Sep 2018 01:32:51 +0200
Subject: [PATCH 496/497] dt-bindings: add bindings for mtd-concat devices
Document virtual mtd-concat device bindings.
Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
---
.../devicetree/bindings/mtd/mtd-concat.txt | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt
@@ -0,0 +1,36 @@
+Virtual MTD concat device
+
+Requires properties:
+- devices: list of phandles to mtd nodes that should be concatenated
+
+Example:
+
+&spi {
+ flash0: flash@0 {
+ ...
+ };
+ flash1: flash@1 {
+ ...
+ };
+};
+
+flash {
+ compatible = "mtd-concat";
+
+ devices = <&flash0 &flash1>;
+
+ partitions {
+ compatible = "fixed-partitions";
+
+ partition@0 {
+ label = "boot";
+ reg = <0x0000000 0x0040000>;
+ read-only;
+ };
+
+ partition@40000 {
+ label = "firmware";
+ reg = <0x0040000 0x1fc0000>;
+ };
+ }
+}

View file

@ -0,0 +1,216 @@
From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001
From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
Date: Sat, 25 Aug 2018 12:35:22 +0200
Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices
Some mtd drivers like physmap variants have support for concatenating
multiple mtd devices, but there is no generic way to define such a
concat device from within the device tree.
This is useful for some SoC boards that use multiple flash chips as
memory banks of a single mtd device, with partitions spanning chip
borders.
This commit adds a driver for creating virtual mtd-concat devices. They
must have a compatible = "mtd-concat" line, and define a list of devices
to concat in the 'devices' property, for example:
flash {
compatible = "mtd-concat";
devices = <&flash0 &flash1>;
partitions {
...
};
};
The driver is added to the very end of the mtd Makefile to increase the
likelyhood of all child devices already being loaded at the time of
probing, preventing unnecessary deferred probes.
Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
---
drivers/mtd/Kconfig | 2 +
drivers/mtd/Makefile | 3 +
drivers/mtd/composite/Kconfig | 12 +++
drivers/mtd/composite/Makefile | 6 ++
drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++
5 files changed, 151 insertions(+)
create mode 100644 drivers/mtd/composite/Kconfig
create mode 100644 drivers/mtd/composite/Makefile
create mode 100644 drivers/mtd/composite/virt_concat.c
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -241,4 +241,6 @@ source "drivers/mtd/ubi/Kconfig"
source "drivers/mtd/hyperbus/Kconfig"
+source "drivers/mtd/composite/Kconfig"
+
endif # MTD
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -33,3 +33,6 @@ obj-y += chips/ lpddr/ maps/ devices/ n
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
obj-$(CONFIG_MTD_UBI) += ubi/
obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/
+
+# Composite drivers must be loaded last
+obj-y += composite/
--- /dev/null
+++ b/drivers/mtd/composite/Kconfig
@@ -0,0 +1,12 @@
+menu "Composite MTD device drivers"
+ depends on MTD!=n
+
+config MTD_VIRT_CONCAT
+ tristate "Virtual concat MTD device"
+ help
+ This driver allows creation of a virtual MTD concat device, which
+ concatenates multiple underlying MTD devices to a single device.
+ This is required by some SoC boards where multiple memory banks are
+ used as one device with partitions spanning across device boundaries.
+
+endmenu
--- /dev/null
+++ b/drivers/mtd/composite/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# linux/drivers/mtd/composite/Makefile
+#
+
+obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o
--- /dev/null
+++ b/drivers/mtd/composite/virt_concat.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Virtual concat MTD device driver
+ *
+ * Copyright (C) 2018 Bernhard Frauendienst
+ * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mtd/concat.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+/*
+ * struct of_virt_concat - platform device driver data.
+ * @cmtd the final mtd_concat device
+ * @num_devices the number of devices in @devices
+ * @devices points to an array of devices already loaded
+ */
+struct of_virt_concat {
+ struct mtd_info *cmtd;
+ int num_devices;
+ struct mtd_info **devices;
+};
+
+static int virt_concat_remove(struct platform_device *pdev)
+{
+ struct of_virt_concat *info;
+ int i;
+
+ info = platform_get_drvdata(pdev);
+ if (!info)
+ return 0;
+
+ // unset data for when this is called after a probe error
+ platform_set_drvdata(pdev, NULL);
+
+ if (info->cmtd) {
+ mtd_device_unregister(info->cmtd);
+ mtd_concat_destroy(info->cmtd);
+ }
+
+ if (info->devices) {
+ for (i = 0; i < info->num_devices; i++)
+ put_mtd_device(info->devices[i]);
+ }
+
+ return 0;
+}
+
+static int virt_concat_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct of_phandle_iterator it;
+ struct of_virt_concat *info;
+ struct mtd_info *mtd;
+ int err = 0, count;
+
+ count = of_count_phandle_with_args(node, "devices", NULL);
+ if (count <= 0)
+ return -EINVAL;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->devices = devm_kcalloc(&pdev->dev, count,
+ sizeof(*(info->devices)), GFP_KERNEL);
+ if (!info->devices) {
+ err = -ENOMEM;
+ goto err_remove;
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ of_for_each_phandle(&it, err, node, "devices", NULL, 0) {
+ mtd = of_get_mtd_device_by_node(it.node);
+ if (IS_ERR(mtd)) {
+ of_node_put(it.node);
+ err = -EPROBE_DEFER;
+ goto err_remove;
+ }
+
+ info->devices[info->num_devices++] = mtd;
+ }
+
+ info->cmtd = mtd_concat_create(info->devices, info->num_devices,
+ dev_name(&pdev->dev));
+ if (!info->cmtd) {
+ err = -ENXIO;
+ goto err_remove;
+ }
+
+ info->cmtd->dev.parent = &pdev->dev;
+ mtd_set_of_node(info->cmtd, node);
+ mtd_device_register(info->cmtd, NULL, 0);
+
+ return 0;
+
+err_remove:
+ virt_concat_remove(pdev);
+
+ return err;
+}
+
+static const struct of_device_id virt_concat_of_match[] = {
+ { .compatible = "mtd-concat", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, virt_concat_of_match);
+
+static struct platform_driver virt_concat_driver = {
+ .probe = virt_concat_probe,
+ .remove = virt_concat_remove,
+ .driver = {
+ .name = "virt-mtdconcat",
+ .of_match_table = virt_concat_of_match,
+ },
+};
+
+module_platform_driver(virt_concat_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bernhard Frauendienst <kernel@nospam.obeliks.de>");
+MODULE_DESCRIPTION("Virtual concat MTD device driver");

View file

@ -0,0 +1,30 @@
From 245224608b5368c10407da07557e546743d3c489 Mon Sep 17 00:00:00 2001
From: Nick Hainke <vincent@systemli.org>
Date: Mon, 27 Dec 2021 09:33:13 +0100
Subject: [PATCH 2/2] mtd: spi-nor: disable 16-bit-sr for macronix
Macronix flash chips seem to consist of only one status register.
These chips will not work with the "16-bit Write Status (01h) Command".
Disable SNOR_F_HAS_16BIT_SR for all Macronix chips.
Tested with MX25L6405D.
Fixes: 39d1e3340c73 ("mtd: spi-nor: Fix clearing of QE bit on
lock()/unlock()")
Signed-off-by: David Bauer <mail@david-bauer.net>
Signed-off-by: Nick Hainke <vincent@systemli.org>
---
drivers/mtd/spi-nor/macronix.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -115,6 +115,7 @@ static int macronix_nor_late_init(struct
{
if (!nor->params->set_4byte_addr_mode)
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
+ nor->flags &= ~SNOR_F_HAS_16BIT_SR;
nor->flags |= SNOR_F_HAS_LOCK;
return 0;

View file

@ -0,0 +1,52 @@
From af7b91bcecce0eae24e90acd35d96ecee73e1407 Mon Sep 17 00:00:00 2001
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
Date: Wed, 13 Jul 2022 12:21:15 +0200
Subject: [PATCH] fs: add cdrom dependency
---
fs/hfs/Kconfig | 1 +
fs/hfsplus/Kconfig | 1 +
fs/isofs/Kconfig | 1 +
fs/udf/Kconfig | 1 +
4 files changed, 4 insertions(+)
--- a/fs/hfs/Kconfig
+++ b/fs/hfs/Kconfig
@@ -2,6 +2,7 @@
config HFS_FS
tristate "Apple Macintosh file system support"
depends on BLOCK
+ select CDROM
select BUFFER_HEAD
select NLS
select LEGACY_DIRECT_IO
--- a/fs/hfsplus/Kconfig
+++ b/fs/hfsplus/Kconfig
@@ -2,6 +2,7 @@
config HFSPLUS_FS
tristate "Apple Extended HFS file system support"
depends on BLOCK
+ select CDROM
select BUFFER_HEAD
select NLS
select NLS_UTF8
--- a/fs/isofs/Kconfig
+++ b/fs/isofs/Kconfig
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config ISO9660_FS
tristate "ISO 9660 CDROM file system support"
+ select CDROM
select BUFFER_HEAD
help
This is the standard file system used on CD-ROMs. It was previously
--- a/fs/udf/Kconfig
+++ b/fs/udf/Kconfig
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config UDF_FS
tristate "UDF file system support"
+ select CDROM
select BUFFER_HEAD
select CRC_ITU_T
select NLS

View file

@ -0,0 +1,756 @@
From 6173a065cb395d4a9528c4e49810af127db68141 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 16 Nov 2022 12:49:52 +0000
Subject: [PATCH 1/2] block: add uImage.FIT subimage block driver
Add a small block driver which exposes filesystem sub-images contained
in U-Boot uImage.FIT images as block devices.
The uImage.FIT image has to be stored directly on a block device or
partition, MTD device or partition, or UBI volume.
The driver is intended for systems using the U-Boot bootloader and
uses the root device hint left by the bootloader (or the user) in
the 'chosen' section of the device-tree.
Example:
/dts-v1/;
/ {
chosen {
rootdisk = <&mmc0_part3>;
};
};
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
MAINTAINERS | 6 +
drivers/block/Kconfig | 12 +
drivers/block/Makefile | 2 +
drivers/block/fitblk.c | 658 ++++++++++++++++++++++++++++++++++++
drivers/block/open | 4 +
include/uapi/linux/fitblk.h | 10 +
6 files changed, 692 insertions(+)
create mode 100644 drivers/block/fitblk.c
create mode 100644 drivers/block/open
create mode 100644 include/uapi/linux/fitblk.h
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22014,6 +22014,12 @@ F: Documentation/filesystems/ubifs-authe
F: Documentation/filesystems/ubifs.rst
F: fs/ubifs/
+U-BOOT UIMAGE.FIT PARSER
+M: Daniel Golle <daniel@makrotopia.org>
+L: linux-block@vger.kernel.org
+S: Maintained
+F: drivers/block/fitblk.c
+
UBLK USERSPACE BLOCK DRIVER
M: Ming Lei <ming.lei@redhat.com>
L: linux-block@vger.kernel.org
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -354,6 +354,18 @@ config VIRTIO_BLK
This is the virtual block driver for virtio. It can be used with
QEMU based VMMs (like KVM or Xen). Say Y or M.
+config UIMAGE_FIT_BLK
+ bool "uImage.FIT block driver"
+ help
+ This driver allows using filesystems contained in uImage.FIT images
+ by mapping them as block devices.
+
+ It can currently not be built as a module due to libfdt symbols not
+ being exported.
+
+ Say Y if you want to mount filesystems sub-images of a uImage.FIT
+ stored in a block device partition, mtdblock or ubiblock device.
+
config BLK_DEV_RBD
tristate "Rados block device (RBD)"
depends on INET && BLOCK
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -39,4 +39,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_b
obj-$(CONFIG_BLK_DEV_UBLK) += ublk_drv.o
+obj-$(CONFIG_UIMAGE_FIT_BLK) += fitblk.o
+
swim_mod-y := swim.o swim_asm.o
--- /dev/null
+++ b/drivers/block/fitblk.c
@@ -0,0 +1,659 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * uImage.FIT virtual block device driver.
+ *
+ * Copyright (C) 2023 Daniel Golle
+ * Copyright (C) 2007 Nick Piggin
+ * Copyright (C) 2007 Novell Inc.
+ *
+ * Initially derived from drivers/block/brd.c which is in parts derived from
+ * drivers/block/rd.c, and drivers/block/loop.c, copyright of their respective
+ * owners.
+ *
+ * uImage.FIT headers extracted from Das U-Boot
+ * (C) Copyright 2008 Semihalf
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/blk-mq.h>
+#include <linux/ctype.h>
+#include <linux/hdreg.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+#include <linux/pagemap.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/refcount.h>
+#include <linux/task_work.h>
+#include <linux/types.h>
+#include <linux/libfdt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/root_dev.h>
+#include <uapi/linux/fitblk.h>
+
+#define FIT_DEVICE_PREFIX "fit"
+
+/* maximum number of pages used for the uImage.FIT index structure */
+#define FIT_MAX_PAGES 1024
+
+/* minimum free sectors to map as read-write "remainder" volume */
+#define MIN_FREE_SECT 16
+
+/* maximum number of mapped loadables */
+#define MAX_FIT_LOADABLES 16
+
+/* constants for uImage.FIT structrure traversal */
+#define FIT_IMAGES_PATH "/images"
+#define FIT_CONFS_PATH "/configurations"
+
+/* hash/signature/key node */
+#define FIT_HASH_NODENAME "hash"
+#define FIT_ALGO_PROP "algo"
+#define FIT_VALUE_PROP "value"
+#define FIT_IGNORE_PROP "uboot-ignore"
+#define FIT_SIG_NODENAME "signature"
+#define FIT_KEY_REQUIRED "required"
+#define FIT_KEY_HINT "key-name-hint"
+
+/* cipher node */
+#define FIT_CIPHER_NODENAME "cipher"
+#define FIT_ALGO_PROP "algo"
+
+/* image node */
+#define FIT_DATA_PROP "data"
+#define FIT_DATA_POSITION_PROP "data-position"
+#define FIT_DATA_OFFSET_PROP "data-offset"
+#define FIT_DATA_SIZE_PROP "data-size"
+#define FIT_TIMESTAMP_PROP "timestamp"
+#define FIT_DESC_PROP "description"
+#define FIT_ARCH_PROP "arch"
+#define FIT_TYPE_PROP "type"
+#define FIT_OS_PROP "os"
+#define FIT_COMP_PROP "compression"
+#define FIT_ENTRY_PROP "entry"
+#define FIT_LOAD_PROP "load"
+
+/* configuration node */
+#define FIT_KERNEL_PROP "kernel"
+#define FIT_FILESYSTEM_PROP "filesystem"
+#define FIT_RAMDISK_PROP "ramdisk"
+#define FIT_FDT_PROP "fdt"
+#define FIT_LOADABLE_PROP "loadables"
+#define FIT_DEFAULT_PROP "default"
+#define FIT_SETUP_PROP "setup"
+#define FIT_FPGA_PROP "fpga"
+#define FIT_FIRMWARE_PROP "firmware"
+#define FIT_STANDALONE_PROP "standalone"
+
+/* fitblk driver data */
+static const char *_fitblk_claim_ptr = "I belong to fitblk";
+static const char *ubootver;
+struct device_node *rootdisk;
+static struct platform_device *pdev;
+static LIST_HEAD(fitblk_devices);
+static DEFINE_MUTEX(devices_mutex);
+refcount_t num_devs;
+
+struct fitblk {
+ struct platform_device *pdev;
+ struct block_device *lower_bdev;
+ sector_t start_sect;
+ struct gendisk *disk;
+ struct work_struct remove_work;
+ struct list_head list;
+ bool dead;
+};
+
+static int fitblk_open(struct gendisk *disk, fmode_t mode)
+{
+ struct fitblk *fitblk = disk->private_data;
+
+ if (fitblk->dead)
+ return -ENOENT;
+
+ return 0;
+}
+
+static void fitblk_release(struct gendisk *disk)
+{
+ return;
+}
+
+static void fitblk_submit_bio(struct bio *orig_bio)
+{
+ struct bio *bio = orig_bio;
+ struct fitblk *fitblk = bio->bi_bdev->bd_disk->private_data;
+
+ if (fitblk->dead)
+ return;
+
+ /* mangle bio and re-submit */
+ while (bio) {
+ bio->bi_iter.bi_sector += fitblk->start_sect;
+ bio->bi_bdev = fitblk->lower_bdev;
+ bio = bio->bi_next;
+ }
+ submit_bio(orig_bio);
+}
+
+static void fitblk_remove(struct fitblk *fitblk)
+{
+ blk_mark_disk_dead(fitblk->disk);
+ mutex_lock(&devices_mutex);
+ fitblk->dead = true;
+ list_del(&fitblk->list);
+ mutex_unlock(&devices_mutex);
+
+ schedule_work(&fitblk->remove_work);
+}
+
+static int fitblk_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct fitblk *fitblk = bdev->bd_disk->private_data;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (fitblk->dead)
+ return -ENOENT;
+
+ switch (cmd) {
+ case FITBLK_RELEASE:
+ fitblk_remove(fitblk);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct block_device_operations fitblk_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = fitblk_ioctl,
+ .open = fitblk_open,
+ .release = fitblk_release,
+ .submit_bio = fitblk_submit_bio,
+};
+
+static void fitblk_purge(struct work_struct *work)
+{
+ struct fitblk *fitblk = container_of(work, struct fitblk, remove_work);
+
+ //del_gendisk(fitblk->disk); // causes crash, not doing it doesn't matter
+ refcount_dec(&num_devs);
+ platform_device_del(fitblk->pdev);
+ platform_device_put(fitblk->pdev);
+
+ if (refcount_dec_if_one(&num_devs)) {
+ sysfs_remove_link(&pdev->dev.kobj, "lower_dev");
+ blkdev_put(fitblk->lower_bdev, &_fitblk_claim_ptr);
+ }
+
+ kfree(fitblk);
+}
+
+static int add_fit_subimage_device(struct block_device *lower_bdev,
+ unsigned int slot, sector_t start_sect,
+ sector_t nr_sect, bool readonly)
+{
+ struct fitblk *fitblk;
+ struct gendisk *disk;
+ int err;
+
+ mutex_lock(&devices_mutex);
+ if (!refcount_inc_not_zero(&num_devs))
+ return -EBADF;
+
+ fitblk = kzalloc(sizeof(struct fitblk), GFP_KERNEL);
+ if (!fitblk) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ fitblk->lower_bdev = lower_bdev;
+ fitblk->start_sect = start_sect;
+ INIT_WORK(&fitblk->remove_work, fitblk_purge);
+
+ disk = blk_alloc_disk(NUMA_NO_NODE);
+ if (!disk) {
+ err = -ENOMEM;
+ goto out_free_fitblk;
+ }
+
+ disk->first_minor = 0;
+ disk->flags = lower_bdev->bd_disk->flags | GENHD_FL_NO_PART;
+ disk->fops = &fitblk_fops;
+ disk->private_data = fitblk;
+ if (readonly) {
+ set_disk_ro(disk, 1);
+ snprintf(disk->disk_name, sizeof(disk->disk_name), FIT_DEVICE_PREFIX "%u", slot);
+ } else {
+ strcpy(disk->disk_name, FIT_DEVICE_PREFIX "rw");
+ }
+
+ set_capacity(disk, nr_sect);
+
+ disk->queue->queue_flags = lower_bdev->bd_disk->queue->queue_flags;
+ memcpy(&disk->queue->limits, &lower_bdev->bd_disk->queue->limits,
+ sizeof(struct queue_limits));
+
+ fitblk->disk = disk;
+ fitblk->pdev = platform_device_alloc(disk->disk_name, PLATFORM_DEVID_NONE);
+ if (!fitblk->pdev) {
+ err = -ENOMEM;
+ goto out_cleanup_disk;
+ }
+
+ fitblk->pdev->dev.parent = &pdev->dev;
+ err = platform_device_add(fitblk->pdev);
+ if (err)
+ goto out_put_pdev;
+
+ err = device_add_disk(&fitblk->pdev->dev, disk, NULL);
+ if (err)
+ goto out_del_pdev;
+
+ if (!ROOT_DEV)
+ ROOT_DEV = disk->part0->bd_dev;
+
+ list_add_tail(&fitblk->list, &fitblk_devices);
+
+ mutex_unlock(&devices_mutex);
+
+ return 0;
+
+out_del_pdev:
+ platform_device_del(fitblk->pdev);
+out_put_pdev:
+ platform_device_put(fitblk->pdev);
+out_cleanup_disk:
+ put_disk(disk);
+out_free_fitblk:
+ kfree(fitblk);
+out_unlock:
+ refcount_dec(&num_devs);
+ mutex_unlock(&devices_mutex);
+ return err;
+}
+
+static void fitblk_mark_dead(struct block_device *bdev, bool surprise)
+{
+ struct list_head *n, *tmp;
+ struct fitblk *fitblk;
+
+ mutex_lock(&devices_mutex);
+ list_for_each_safe(n, tmp, &fitblk_devices) {
+ fitblk = list_entry(n, struct fitblk, list);
+ if (fitblk->lower_bdev != bdev)
+ continue;
+
+ fitblk->dead = true;
+ list_del(&fitblk->list);
+ /* removal needs to be deferred to avoid deadlock */
+ schedule_work(&fitblk->remove_work);
+ }
+ mutex_unlock(&devices_mutex);
+}
+
+static const struct blk_holder_ops fitblk_hops = {
+ .mark_dead = fitblk_mark_dead,
+};
+
+static int parse_fit_on_dev(struct device *dev)
+{
+ struct block_device *bdev;
+ struct address_space *mapping;
+ struct folio *folio;
+ pgoff_t f_index = 0;
+ size_t bytes_left, bytes_to_copy;
+ void *pre_fit, *fit, *fit_c;
+ u64 dsize, dsectors, imgmaxsect = 0;
+ u32 size, image_pos, image_len;
+ const __be32 *image_offset_be, *image_len_be, *image_pos_be;
+ int ret = 0, node, images, config;
+ const char *image_name, *image_type, *image_description,
+ *config_default, *config_description, *config_loadables;
+ u32 image_name_len, image_type_len, image_description_len,
+ bootconf_len, config_default_len, config_description_len,
+ config_loadables_len;
+ sector_t start_sect, nr_sects;
+ struct device_node *np = NULL;
+ const char *bootconf_c;
+ const char *loadable;
+ char *bootconf = NULL, *bootconf_term;
+ bool found;
+ int loadables_rem_len, loadable_len;
+ u16 loadcnt;
+ unsigned int slot = 0;
+
+ /* Exclusive open the block device to receive holder notifications */
+ bdev = blkdev_get_by_dev(dev->devt, BLK_OPEN_READ, &_fitblk_claim_ptr, &fitblk_hops);
+ if (!bdev)
+ return -ENODEV;
+
+ if (IS_ERR(bdev))
+ return PTR_ERR(bdev);
+
+ mapping = bdev->bd_inode->i_mapping;
+
+ /* map first page */
+ folio = read_mapping_folio(mapping, f_index++, NULL);
+ if (IS_ERR(folio)) {
+ ret = PTR_ERR(folio);
+ goto out_blkdev;
+ }
+ pre_fit = folio_address(folio) + offset_in_folio(folio, 0);
+
+ /* uImage.FIT is based on flattened device tree structure */
+ if (fdt_check_header(pre_fit)) {
+ ret = -EINVAL;
+ folio_put(folio);
+ goto out_blkdev;
+ }
+
+ size = fdt_totalsize(pre_fit);
+
+ if (size > PAGE_SIZE * FIT_MAX_PAGES) {
+ ret = -EOPNOTSUPP;
+ folio_put(folio);
+ goto out_blkdev;
+ }
+
+ /* acquire disk size */
+ dsectors = bdev_nr_sectors(bdev);
+ dsize = dsectors << SECTOR_SHIFT;
+
+ /* abort if FIT structure is larger than disk or partition size */
+ if (size >= dsize) {
+ ret = -EFBIG;
+ folio_put(folio);
+ goto out_blkdev;
+ }
+
+ fit = kmalloc(size, GFP_KERNEL);
+ if (!fit) {
+ ret = -ENOMEM;
+ folio_put(folio);
+ goto out_blkdev;
+ }
+
+ bytes_left = size;
+ fit_c = fit;
+ while (bytes_left > 0) {
+ bytes_to_copy = min_t(size_t, bytes_left,
+ folio_size(folio) - offset_in_folio(folio, 0));
+ memcpy(fit_c, pre_fit, bytes_to_copy);
+ fit_c += bytes_to_copy;
+ bytes_left -= bytes_to_copy;
+ if (bytes_left) {
+ folio_put(folio);
+ folio = read_mapping_folio(mapping, f_index++, NULL);
+ if (IS_ERR(folio)) {
+ ret = PTR_ERR(folio);
+ goto out_blkdev;
+ };
+ pre_fit = folio_address(folio) + offset_in_folio(folio, 0);
+ }
+ }
+ folio_put(folio);
+
+ /* set boot config node name U-Boot may have added to the device tree */
+ np = of_find_node_by_path("/chosen");
+ if (np) {
+ bootconf_c = of_get_property(np, "u-boot,bootconf", &bootconf_len);
+ if (bootconf_c && bootconf_len)
+ bootconf = kmemdup_nul(bootconf_c, bootconf_len, GFP_KERNEL);
+ }
+
+ if (bootconf) {
+ bootconf_term = strchr(bootconf, '#');
+ if (bootconf_term)
+ *bootconf_term = '\0';
+ }
+
+ /* find configuration path in uImage.FIT */
+ config = fdt_path_offset(fit, FIT_CONFS_PATH);
+ if (config < 0) {
+ pr_err("FIT: Cannot find %s node: %d\n",
+ FIT_CONFS_PATH, config);
+ ret = -ENOENT;
+ goto out_bootconf;
+ }
+
+ /* get default configuration node name */
+ config_default =
+ fdt_getprop(fit, config, FIT_DEFAULT_PROP, &config_default_len);
+
+ /* make sure we got either default or selected boot config node name */
+ if (!config_default && !bootconf) {
+ pr_err("FIT: Cannot find default configuration\n");
+ ret = -ENOENT;
+ goto out_bootconf;
+ }
+
+ /* find selected boot config node, fallback on default config node */
+ node = fdt_subnode_offset(fit, config, bootconf ?: config_default);
+ if (node < 0) {
+ pr_err("FIT: Cannot find %s node: %d\n",
+ bootconf ?: config_default, node);
+ ret = -ENOENT;
+ goto out_bootconf;
+ }
+
+ pr_info("FIT: Detected U-Boot %s\n", ubootver);
+
+ /* get selected configuration data */
+ config_description =
+ fdt_getprop(fit, node, FIT_DESC_PROP, &config_description_len);
+ config_loadables = fdt_getprop(fit, node, FIT_LOADABLE_PROP,
+ &config_loadables_len);
+
+ pr_info("FIT: %s configuration: \"%.*s\"%s%.*s%s\n",
+ bootconf ? "Selected" : "Default",
+ bootconf ? bootconf_len : config_default_len,
+ bootconf ?: config_default,
+ config_description ? " (" : "",
+ config_description ? config_description_len : 0,
+ config_description ?: "",
+ config_description ? ")" : "");
+
+ if (!config_loadables || !config_loadables_len) {
+ pr_err("FIT: No loadables configured in \"%s\"\n",
+ bootconf ?: config_default);
+ ret = -ENOENT;
+ goto out_bootconf;
+ }
+
+ /* get images path in uImage.FIT */
+ images = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images < 0) {
+ pr_err("FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH, images);
+ ret = -EINVAL;
+ goto out_bootconf;
+ }
+
+ /* iterate over images in uImage.FIT */
+ fdt_for_each_subnode(node, fit, images) {
+ image_name = fdt_get_name(fit, node, &image_name_len);
+ image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len);
+ image_offset_be = fdt_getprop(fit, node, FIT_DATA_OFFSET_PROP, NULL);
+ image_pos_be = fdt_getprop(fit, node, FIT_DATA_POSITION_PROP, NULL);
+ image_len_be = fdt_getprop(fit, node, FIT_DATA_SIZE_PROP, NULL);
+
+ if (!image_name || !image_type || !image_len_be ||
+ !image_name_len || !image_type_len)
+ continue;
+
+ image_len = be32_to_cpu(*image_len_be);
+ if (!image_len)
+ continue;
+
+ if (image_offset_be)
+ image_pos = be32_to_cpu(*image_offset_be) + size;
+ else if (image_pos_be)
+ image_pos = be32_to_cpu(*image_pos_be);
+ else
+ continue;
+
+ image_description = fdt_getprop(fit, node, FIT_DESC_PROP,
+ &image_description_len);
+
+ pr_info("FIT: %16s sub-image 0x%08x..0x%08x \"%.*s\"%s%.*s%s\n",
+ image_type, image_pos, image_pos + image_len - 1,
+ image_name_len, image_name, image_description ? " (" : "",
+ image_description ? image_description_len : 0,
+ image_description ?: "", image_description ? ") " : "");
+
+ /* only 'filesystem' images should be mapped as partitions */
+ if (strncmp(image_type, FIT_FILESYSTEM_PROP, image_type_len))
+ continue;
+
+ /* check if sub-image is part of configured loadables */
+ found = false;
+ loadable = config_loadables;
+ loadables_rem_len = config_loadables_len;
+ for (loadcnt = 0; loadables_rem_len > 1 &&
+ loadcnt < MAX_FIT_LOADABLES; ++loadcnt) {
+ loadable_len =
+ strnlen(loadable, loadables_rem_len - 1) + 1;
+ loadables_rem_len -= loadable_len;
+ if (!strncmp(image_name, loadable, loadable_len)) {
+ found = true;
+ break;
+ }
+ loadable += loadable_len;
+ }
+ if (!found)
+ continue;
+
+ if (image_pos % (1 << PAGE_SHIFT)) {
+ dev_err(dev, "FIT: image %.*s start not aligned to page boundaries, skipping\n",
+ image_name_len, image_name);
+ continue;
+ }
+
+ if (image_len % (1 << PAGE_SHIFT)) {
+ dev_err(dev, "FIT: sub-image %.*s end not aligned to page boundaries, skipping\n",
+ image_name_len, image_name);
+ continue;
+ }
+
+ start_sect = image_pos >> SECTOR_SHIFT;
+ nr_sects = image_len >> SECTOR_SHIFT;
+ imgmaxsect = max_t(sector_t, imgmaxsect, start_sect + nr_sects);
+
+ if (start_sect + nr_sects > dsectors) {
+ dev_err(dev, "FIT: sub-image %.*s disk access beyond EOD\n",
+ image_name_len, image_name);
+ continue;
+ }
+
+ if (!slot) {
+ ret = sysfs_create_link_nowarn(&pdev->dev.kobj, bdev_kobj(bdev), "lower_dev");
+ if (ret && ret != -EEXIST)
+ goto out_bootconf;
+
+ ret = 0;
+ }
+
+ add_fit_subimage_device(bdev, slot++, start_sect, nr_sects, true);
+ }
+
+ if (!found || !slot)
+ goto out_bootconf;
+
+ dev_info(dev, "mapped %u uImage.FIT filesystem sub-image%s as /dev/fit%s%u%s\n",
+ slot, (slot > 1)?"s":"", (slot > 1)?"[0...":"", slot - 1,
+ (slot > 1)?"]":"");
+
+ /* in case uImage.FIT is stored in a partition, map the remaining space */
+ if (!bdev->bd_read_only && bdev_is_partition(bdev) &&
+ (imgmaxsect + MIN_FREE_SECT) < dsectors) {
+ add_fit_subimage_device(bdev, slot++, imgmaxsect,
+ dsectors - imgmaxsect, false);
+ dev_info(dev, "mapped remaing space as /dev/fitrw\n");
+ }
+
+out_bootconf:
+ kfree(bootconf);
+ kfree(fit);
+out_blkdev:
+ if (!found || ret)
+ blkdev_put(bdev, &_fitblk_claim_ptr);
+
+ return ret;
+}
+
+static int fitblk_match_of_node(struct device *dev, const void *np)
+{
+ int ret;
+
+ ret = device_match_of_node(dev, np);
+ if (ret)
+ return ret;
+
+ /*
+ * To match ubiblock and mtdblock devices by their parent ubi
+ * or mtd device, also consider block device parent
+ */
+ if (!dev->parent)
+ return 0;
+
+ return device_match_of_node(dev->parent, np);
+}
+
+static int fitblk_probe(struct platform_device *pdev)
+{
+ struct device *dev;
+
+ dev = class_find_device(&block_class, NULL, rootdisk, fitblk_match_of_node);
+ if (!dev)
+ return -EPROBE_DEFER;
+
+ return parse_fit_on_dev(dev);
+}
+
+static struct platform_driver fitblk_driver = {
+ .probe = fitblk_probe,
+ .driver = {
+ .name = "fitblk",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init fitblk_init(void)
+{
+ /* detect U-Boot firmware */
+ ubootver = of_get_property(of_chosen, "u-boot,version", NULL);
+ if (!ubootver)
+ return 0;
+
+ /* parse 'rootdisk' property phandle */
+ rootdisk = of_parse_phandle(of_chosen, "rootdisk", 0);
+ if (!rootdisk)
+ return 0;
+
+ if (platform_driver_register(&fitblk_driver))
+ return -ENODEV;
+
+ refcount_set(&num_devs, 1);
+ pdev = platform_device_register_simple("fitblk", -1, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return 0;
+}
+device_initcall(fitblk_init);
--- /dev/null
+++ b/include/uapi/linux/fitblk.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_FITBLK_H
+#define _UAPI_LINUX_FITBLK_H
+
+/*
+ * IOCTL commands --- we will commandeer 0x46 ('F')
+ */
+#define FITBLK_RELEASE 0x4600
+
+#endif /* _UAPI_LINUX_FITBLK_H */

View file

@ -0,0 +1,25 @@
From 5ede3f8aed9a1a579bf7304142600d1f3500add9 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Mon, 12 Jun 2023 03:58:42 +0100
Subject: [PATCH 2/2] init: bypass device lookup for /dev/fit* rootfs
Allow 'rootwait' as /dev/fit* can show up late if the underlaying
device is probed late.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
init/do_mounts.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -463,7 +463,8 @@ static dev_t __init parse_root_device(ch
int error;
dev_t dev;
- if (!strncmp(root_device_name, "mtd", 3) ||
+ if (!strncmp(root_device_name, "fit", 3) ||
+ !strncmp(root_device_name, "mtd", 3) ||
!strncmp(root_device_name, "ubi", 3))
return Root_Generic;
if (strcmp(root_device_name, "/dev/nfs") == 0)

View file

@ -0,0 +1,65 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: fs: jffs2: EOF marker
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
fs/jffs2/build.c | 10 ++++++++++
fs/jffs2/scan.c | 21 +++++++++++++++++++--
2 files changed, 29 insertions(+), 2 deletions(-)
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct
dbg_fsbuild("scanned flash completely\n");
jffs2_dbg_dump_block_lists_nolock(c);
+ if (c->flags & (1 << 7)) {
+ printk("%s(): unlocking the mtd device... ", __func__);
+ mtd_unlock(c->mtd, 0, c->mtd->size);
+ printk("done.\n");
+
+ printk("%s(): erasing all blocks after the end marker... ", __func__);
+ jffs2_erase_pending_blocks(c, -1);
+ printk("done.\n");
+ }
+
dbg_fsbuild("pass 1 starting\n");
c->flags |= JFFS2_SB_FLAG_BUILDING;
/* Now scan the directory tree, increasing nlink according to every dirent found. */
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
/* reset summary info for next eraseblock scan */
jffs2_sum_reset_collected(s);
- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
- buf_size, s);
+ if (c->flags & (1 << 7)) {
+ if (mtd_block_isbad(c->mtd, jeb->offset))
+ ret = BLK_STATE_BADBLOCK;
+ else
+ ret = BLK_STATE_ALLFF;
+ } else
+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+ buf_size, s);
if (ret < 0)
goto out;
@@ -567,6 +573,17 @@ full_scan:
return err;
}
+ if ((buf[0] == 0xde) &&
+ (buf[1] == 0xad) &&
+ (buf[2] == 0xc0) &&
+ (buf[3] == 0xde)) {
+ /* end of filesystem. erase everything after this point */
+ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
+ c->flags |= (1 << 7);
+
+ return BLK_STATE_ALLFF;
+ }
+
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
ofs = 0;
max_ofs = EMPTY_SCAN_SIZE(c->sector_size);

View file

@ -0,0 +1,90 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: netfilter: add support for flushing conntrack via /proc
lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/netfilter/nf_conntrack_standalone.c | 59 ++++++++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -9,6 +9,7 @@
#include <linux/percpu.h>
#include <linux/netdevice.h>
#include <linux/security.h>
+#include <linux/inet.h>
#include <net/net_namespace.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
@@ -461,6 +462,58 @@ static int ct_cpu_seq_show(struct seq_fi
return 0;
}
+struct kill_request {
+ u16 family;
+ union nf_inet_addr addr;
+};
+
+static int kill_matching(struct nf_conn *i, void *data)
+{
+ struct kill_request *kr = data;
+ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple;
+
+ if (!kr->family)
+ return 1;
+
+ if (t1->src.l3num != kr->family)
+ return 0;
+
+ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) ||
+ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) ||
+ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) ||
+ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3));
+}
+
+static int ct_file_write(struct file *file, char *buf, size_t count)
+{
+ struct seq_file *seq = file->private_data;
+ struct nf_ct_iter_data iter_data;
+ struct kill_request kr = { };
+
+ if (count == 0)
+ return 0;
+
+ if (count >= INET6_ADDRSTRLEN)
+ count = INET6_ADDRSTRLEN - 1;
+
+ if (strnchr(buf, count, ':')) {
+ kr.family = AF_INET6;
+ if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL))
+ return -EINVAL;
+ } else if (strnchr(buf, count, '.')) {
+ kr.family = AF_INET;
+ if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL))
+ return -EINVAL;
+ }
+
+ iter_data.net = seq_file_net(seq);
+ iter_data.data = &kr;
+ nf_ct_iterate_cleanup_net(kill_matching, &iter_data);
+
+ return 0;
+}
+
static const struct seq_operations ct_cpu_seq_ops = {
.start = ct_cpu_seq_start,
.next = ct_cpu_seq_next,
@@ -474,8 +527,9 @@ static int nf_conntrack_standalone_init_
kuid_t root_uid;
kgid_t root_gid;
- pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops,
- sizeof(struct ct_iter_state));
+ pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net,
+ &ct_seq_ops, &ct_file_write,
+ sizeof(struct ct_iter_state), NULL);
if (!pde)
goto out_nf_conntrack;

View file

@ -0,0 +1,110 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/uapi/linux/netfilter_ipv4/ip_tables.h | 1 +
net/ipv4/netfilter/ip_tables.c | 37 +++++++++++++++++++++++++++
2 files changed, 38 insertions(+)
--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
+++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
@@ -89,6 +89,7 @@ struct ipt_ip {
#define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
#define IPT_F_GOTO 0x02 /* Set if jump is a goto */
#define IPT_F_MASK 0x03 /* All possible flag bits mask. */
+#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */
/* Values for "inv" field in struct ipt_ip. */
#define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -48,6 +48,9 @@ ip_packet_match(const struct iphdr *ip,
{
unsigned long ret;
+ if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
+ return true;
+
if (NF_INVF(ipinfo, IPT_INV_SRCIP,
(ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
NF_INVF(ipinfo, IPT_INV_DSTIP,
@@ -78,6 +81,29 @@ ip_packet_match(const struct iphdr *ip,
return true;
}
+static void
+ip_checkdefault(struct ipt_ip *ip)
+{
+ static const char iface_mask[IFNAMSIZ] = {};
+
+ if (ip->invflags || ip->flags & IPT_F_FRAG)
+ return;
+
+ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
+ return;
+
+ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
+ return;
+
+ if (ip->smsk.s_addr || ip->dmsk.s_addr)
+ return;
+
+ if (ip->proto)
+ return;
+
+ ip->flags |= IPT_F_NO_DEF_MATCH;
+}
+
static bool
ip_checkentry(const struct ipt_ip *ip)
{
@@ -523,6 +549,8 @@ find_check_entry(struct ipt_entry *e, st
struct xt_mtchk_param mtpar;
struct xt_entry_match *ematch;
+ ip_checkdefault(&e->ip);
+
if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
return -ENOMEM;
@@ -817,6 +845,7 @@ copy_entries_to_user(unsigned int total_
const struct xt_table_info *private = table->private;
int ret = 0;
const void *loc_cpu_entry;
+ u8 flags;
counters = alloc_counters(table);
if (IS_ERR(counters))
@@ -844,6 +873,14 @@ copy_entries_to_user(unsigned int total_
goto free_counters;
}
+ flags = e->ip.flags & IPT_F_MASK;
+ if (copy_to_user(userptr + off
+ + offsetof(struct ipt_entry, ip.flags),
+ &flags, sizeof(flags)) != 0) {
+ ret = -EFAULT;
+ goto free_counters;
+ }
+
for (i = sizeof(struct ipt_entry);
i < e->target_offset;
i += m->u.match_size) {
@@ -1225,12 +1262,15 @@ compat_copy_entry_to_user(struct ipt_ent
compat_uint_t origsize;
const struct xt_entry_match *ematch;
int ret = 0;
+ u8 flags = e->ip.flags & IPT_F_MASK;
origsize = *size;
ce = *dstptr;
if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 ||
copy_to_user(&ce->counters, &counters[i],
- sizeof(counters[i])) != 0)
+ sizeof(counters[i])) != 0 ||
+ copy_to_user(&ce->ip.flags, &flags,
+ sizeof(flags)) != 0)
return -EFAULT;
*dstptr += sizeof(struct compat_ipt_entry);

View file

@ -0,0 +1,106 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: netfilter: match bypass default table
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/ipv4/netfilter/ip_tables.c | 79 +++++++++++++++++++++++++++++++-----------
1 file changed, 58 insertions(+), 21 deletions(-)
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -244,6 +244,33 @@ struct ipt_entry *ipt_next_entry(const s
return (void *)entry + entry->next_offset;
}
+static bool
+ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
+{
+ struct xt_entry_target *t;
+ struct xt_standard_target *st;
+
+ if (e->target_offset != sizeof(struct ipt_entry))
+ return false;
+
+ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
+ return false;
+
+ t = ipt_get_target(e);
+ if (t->u.kernel.target->target)
+ return false;
+
+ st = (struct xt_standard_target *) t;
+ if (st->verdict == XT_RETURN)
+ return false;
+
+ if (st->verdict >= 0)
+ return false;
+
+ *verdict = (unsigned)(-st->verdict) - 1;
+ return true;
+}
+
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int
ipt_do_table(void *priv,
@@ -265,27 +292,28 @@ ipt_do_table(void *priv,
unsigned int addend;
/* Initialization */
+ WARN_ON(!(table->valid_hooks & (1 << hook)));
+ local_bh_disable();
+ private = READ_ONCE(table->private); /* Address dependency. */
+ cpu = smp_processor_id();
+ table_base = private->entries;
+
+ e = get_entry(table_base, private->hook_entry[hook]);
+ if (ipt_handle_default_rule(e, &verdict)) {
+ struct xt_counters *counter;
+
+ counter = xt_get_this_cpu_counter(&e->counters);
+ ADD_COUNTER(*counter, skb->len, 1);
+ local_bh_enable();
+ return verdict;
+ }
+
stackidx = 0;
ip = ip_hdr(skb);
indev = state->in ? state->in->name : nulldevname;
outdev = state->out ? state->out->name : nulldevname;
- /* We handle fragments by dealing with the first fragment as
- * if it was a normal packet. All other fragments are treated
- * normally, except that they will NEVER match rules that ask
- * things we don't know, ie. tcp syn flag or ports). If the
- * rule is also a fragment-specific rule, non-fragments won't
- * match it. */
- acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
- acpar.thoff = ip_hdrlen(skb);
- acpar.hotdrop = false;
- acpar.state = state;
- WARN_ON(!(table->valid_hooks & (1 << hook)));
- local_bh_disable();
addend = xt_write_recseq_begin();
- private = READ_ONCE(table->private); /* Address dependency. */
- cpu = smp_processor_id();
- table_base = private->entries;
jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
/* Switch to alternate jumpstack if we're being invoked via TEE.
@@ -298,7 +326,16 @@ ipt_do_table(void *priv,
if (static_key_false(&xt_tee_enabled))
jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
- e = get_entry(table_base, private->hook_entry[hook]);
+ /* We handle fragments by dealing with the first fragment as
+ * if it was a normal packet. All other fragments are treated
+ * normally, except that they will NEVER match rules that ask
+ * things we don't know, ie. tcp syn flag or ports). If the
+ * rule is also a fragment-specific rule, non-fragments won't
+ * match it. */
+ acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+ acpar.thoff = ip_hdrlen(skb);
+ acpar.hotdrop = false;
+ acpar.state = state;
do {
const struct xt_entry_target *t;

View file

@ -0,0 +1,22 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: netfilter: reduce match memory access
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/ipv4/netfilter/ip_tables.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -51,9 +51,9 @@ ip_packet_match(const struct iphdr *ip,
if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
return true;
- if (NF_INVF(ipinfo, IPT_INV_SRCIP,
+ if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr &&
(ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
- NF_INVF(ipinfo, IPT_INV_DSTIP,
+ NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr &&
(ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr))
return false;

View file

@ -0,0 +1,86 @@
From: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Date: Mon, 21 Aug 2017 11:14:14 +0300
Subject: [PATCH] net_sched/codel: do not defer queue length update
When codel wants to drop last packet in ->dequeue() it cannot call
qdisc_tree_reduce_backlog() right away - it will notify parent qdisc
about zero qlen and HTB/HFSC will deactivate class. The same class will
be deactivated second time by caller of ->dequeue(). Currently codel and
fq_codel defer update. This triggers warning in HFSC when it's qlen != 0
but there is no active classes.
This patch update parent queue length immediately: just temporary increase
qlen around qdisc_tree_reduce_backlog() to prevent first class deactivation
if we have skb to return.
This might open another problem in HFSC - now operation peek could fail and
deactivate parent class.
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=109581
---
--- a/net/sched/sch_codel.c
+++ b/net/sched/sch_codel.c
@@ -95,11 +95,17 @@ static struct sk_buff *codel_qdisc_deque
&q->stats, qdisc_pkt_len, codel_get_enqueue_time,
drop_func, dequeue_func);
- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
- * or HTB crashes. Defer it for next round.
+ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate
+ * parent class, dequeue in parent qdisc will do the same if we
+ * return skb. Temporary increment qlen if we have skb.
*/
- if (q->stats.drop_count && sch->q.qlen) {
- qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
+ if (q->stats.drop_count) {
+ if (skb)
+ sch->q.qlen++;
+ qdisc_tree_reduce_backlog(sch, q->stats.drop_count,
+ q->stats.drop_len);
+ if (skb)
+ sch->q.qlen--;
q->stats.drop_count = 0;
q->stats.drop_len = 0;
}
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -304,6 +304,21 @@ begin:
&flow->cvars, &q->cstats, qdisc_pkt_len,
codel_get_enqueue_time, drop_func, dequeue_func);
+ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate
+ * parent class, dequeue in parent qdisc will do the same if we
+ * return skb. Temporary increment qlen if we have skb.
+ */
+ if (q->cstats.drop_count) {
+ if (skb)
+ sch->q.qlen++;
+ qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
+ q->cstats.drop_len);
+ if (skb)
+ sch->q.qlen--;
+ q->cstats.drop_count = 0;
+ q->cstats.drop_len = 0;
+ }
+
if (!skb) {
/* force a pass through old_flows to prevent starvation */
if ((head == &q->new_flows) && !list_empty(&q->old_flows))
@@ -314,15 +329,6 @@ begin:
}
qdisc_bstats_update(sch, skb);
flow->deficit -= qdisc_pkt_len(skb);
- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
- * or HTB crashes. Defer it for next round.
- */
- if (q->cstats.drop_count && sch->q.qlen) {
- qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
- q->cstats.drop_len);
- q->cstats.drop_count = 0;
- q->cstats.drop_len = 0;
- }
return skb;
}

View file

@ -0,0 +1,138 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: net: add an optimization for dealing with raw sockets
lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/uapi/linux/if_packet.h | 3 +++
net/packet/af_packet.c | 34 +++++++++++++++++++++++++++-------
net/packet/internal.h | 1 +
3 files changed, 31 insertions(+), 7 deletions(-)
--- a/include/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -33,6 +33,8 @@ struct sockaddr_ll {
#define PACKET_KERNEL 7 /* To kernel space */
/* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
#define PACKET_FASTROUTE 6 /* Fastrouted frame */
+#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */
+
/* Packet socket options */
@@ -60,6 +62,7 @@ struct sockaddr_ll {
#define PACKET_FANOUT_DATA 22
#define PACKET_IGNORE_OUTGOING 23
#define PACKET_VNET_HDR_SZ 24
+#define PACKET_RECV_TYPE 25
#define PACKET_FANOUT_HASH 0
#define PACKET_FANOUT_LB 1
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1864,6 +1864,7 @@ static int packet_rcv_spkt(struct sk_buf
{
struct sock *sk;
struct sockaddr_pkt *spkt;
+ struct packet_sock *po;
/*
* When we registered the protocol we saved the socket in the data
@@ -1871,6 +1872,7 @@ static int packet_rcv_spkt(struct sk_buf
*/
sk = pt->af_packet_priv;
+ po = pkt_sk(sk);
/*
* Yank back the headers [hope the device set this
@@ -1883,7 +1885,7 @@ static int packet_rcv_spkt(struct sk_buf
* so that this procedure is noop.
*/
- if (skb->pkt_type == PACKET_LOOPBACK)
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
goto out;
if (!net_eq(dev_net(dev), sock_net(sk)))
@@ -2129,12 +2131,12 @@ static int packet_rcv(struct sk_buff *sk
unsigned int snaplen, res;
bool is_drop_n_account = false;
- if (skb->pkt_type == PACKET_LOOPBACK)
- goto drop;
-
sk = pt->af_packet_priv;
po = pkt_sk(sk);
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
+ goto drop;
+
if (!net_eq(dev_net(dev), sock_net(sk)))
goto drop;
@@ -2261,12 +2263,12 @@ static int tpacket_rcv(struct sk_buff *s
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
- if (skb->pkt_type == PACKET_LOOPBACK)
- goto drop;
-
sk = pt->af_packet_priv;
po = pkt_sk(sk);
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
+ goto drop;
+
if (!net_eq(dev_net(dev), sock_net(sk)))
goto drop;
@@ -3385,6 +3387,7 @@ static int packet_create(struct net *net
mutex_init(&po->pg_vec_lock);
po->rollover = NULL;
po->prot_hook.func = packet_rcv;
+ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
if (sock->type == SOCK_PACKET)
po->prot_hook.func = packet_rcv_spkt;
@@ -4034,6 +4037,16 @@ packet_setsockopt(struct socket *sock, i
packet_sock_flag_set(po, PACKET_SOCK_QDISC_BYPASS, val);
return 0;
}
+ case PACKET_RECV_TYPE:
+ {
+ unsigned int val;
+ if (optlen != sizeof(val))
+ return -EINVAL;
+ if (copy_from_sockptr(&val, optval, sizeof(val)))
+ return -EFAULT;
+ po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
+ return 0;
+ }
default:
return -ENOPROTOOPT;
}
@@ -4093,6 +4106,13 @@ static int packet_getsockopt(struct sock
case PACKET_VNET_HDR_SZ:
val = READ_ONCE(po->vnet_hdr_sz);
break;
+ case PACKET_RECV_TYPE:
+ if (len > sizeof(unsigned int))
+ len = sizeof(unsigned int);
+ val = po->pkt_type;
+
+ data = &val;
+ break;
case PACKET_VERSION:
val = po->tp_version;
break;
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -131,6 +131,7 @@ struct packet_sock {
struct net_device __rcu *cached_dev;
struct packet_type prot_hook ____cacheline_aligned_in_smp;
atomic_t tp_drops ____cacheline_aligned_in_smp;
+ unsigned int pkt_type;
};
#define pkt_sk(ptr) container_of_const(ptr, struct packet_sock, sk)

View file

@ -0,0 +1,20 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: kernel: add a few patches for avoiding unnecessary skb reallocations - significantly improves ethernet<->wireless performance
lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/linux/skbuff.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3062,7 +3062,7 @@ static inline int pskb_network_may_pull(
* NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
*/
#ifndef NET_SKB_PAD
-#define NET_SKB_PAD max(32, L1_CACHE_BYTES)
+#define NET_SKB_PAD max(64, L1_CACHE_BYTES)
#endif
int ___pskb_trim(struct sk_buff *skb, unsigned int len);

View file

@ -0,0 +1,511 @@
From: Steven Barth <steven@midlink.org>
Subject: Add support for MAP-E FMRs (mesh mode)
MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication
between MAP CEs (mesh mode) without the need to forward such data to a
border relay. This is similar to how 6rd works but for IPv4 over IPv6.
Signed-off-by: Steven Barth <cyrus@openwrt.org>
---
include/net/ip6_tunnel.h | 13 ++
include/uapi/linux/if_tunnel.h | 13 ++
net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++--
3 files changed, 291 insertions(+), 11 deletions(-)
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -18,6 +18,18 @@
/* determine capability on a per-packet basis */
#define IP6_TNL_F_CAP_PER_PACKET 0x40000
+/* IPv6 tunnel FMR */
+struct __ip6_tnl_fmr {
+ struct __ip6_tnl_fmr *next; /* next fmr in list */
+ struct in6_addr ip6_prefix;
+ struct in_addr ip4_prefix;
+
+ __u8 ip6_prefix_len;
+ __u8 ip4_prefix_len;
+ __u8 ea_len;
+ __u8 offset;
+};
+
struct __ip6_tnl_parm {
char name[IFNAMSIZ]; /* name of tunnel device */
int link; /* ifindex of underlying L2 interface */
@@ -29,6 +41,7 @@ struct __ip6_tnl_parm {
__u32 flags; /* tunnel flags */
struct in6_addr laddr; /* local tunnel end-point address */
struct in6_addr raddr; /* remote tunnel end-point address */
+ struct __ip6_tnl_fmr *fmrs; /* FMRs */
__be16 i_flags;
__be16 o_flags;
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -77,10 +77,23 @@ enum {
IFLA_IPTUN_ENCAP_DPORT,
IFLA_IPTUN_COLLECT_METADATA,
IFLA_IPTUN_FWMARK,
+ IFLA_IPTUN_FMRS,
__IFLA_IPTUN_MAX,
};
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
+enum {
+ IFLA_IPTUN_FMR_UNSPEC,
+ IFLA_IPTUN_FMR_IP6_PREFIX,
+ IFLA_IPTUN_FMR_IP4_PREFIX,
+ IFLA_IPTUN_FMR_IP6_PREFIX_LEN,
+ IFLA_IPTUN_FMR_IP4_PREFIX_LEN,
+ IFLA_IPTUN_FMR_EA_LEN,
+ IFLA_IPTUN_FMR_OFFSET,
+ __IFLA_IPTUN_FMR_MAX,
+};
+#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1)
+
enum tunnel_encap_types {
TUNNEL_ENCAP_NONE,
TUNNEL_ENCAP_FOU,
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -11,6 +11,9 @@
* linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
*
* RFC 2473
+ *
+ * Changes:
+ * Steven Barth <cyrus@openwrt.org>: MAP-E FMR support
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -67,9 +70,9 @@ static bool log_ecn_error = true;
module_param(log_ecn_error, bool, 0644);
MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
+static u32 HASH(const struct in6_addr *addr)
{
- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
+ u32 hash = ipv6_addr_hash(addr);
return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
}
@@ -114,17 +117,33 @@ static struct ip6_tnl *
ip6_tnl_lookup(struct net *net, int link,
const struct in6_addr *remote, const struct in6_addr *local)
{
- unsigned int hash = HASH(remote, local);
+ unsigned int hash = HASH(local);
struct ip6_tnl *t, *cand = NULL;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
struct in6_addr any;
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (!ipv6_addr_equal(local, &t->parms.laddr) ||
- !ipv6_addr_equal(remote, &t->parms.raddr) ||
!(t->dev->flags & IFF_UP))
continue;
+ if (!ipv6_addr_equal(remote, &t->parms.raddr)) {
+ struct __ip6_tnl_fmr *fmr;
+ bool found = false;
+
+ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
+ if (!ipv6_prefix_equal(remote, &fmr->ip6_prefix,
+ fmr->ip6_prefix_len))
+ continue;
+
+ found = true;
+ break;
+ }
+
+ if (!found)
+ continue;
+ }
+
if (link == t->parms.link)
return t;
else
@@ -132,7 +151,7 @@ ip6_tnl_lookup(struct net *net, int link
}
memset(&any, 0, sizeof(any));
- hash = HASH(&any, local);
+ hash = HASH(local);
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (!ipv6_addr_equal(local, &t->parms.laddr) ||
!ipv6_addr_any(&t->parms.raddr) ||
@@ -145,7 +164,7 @@ ip6_tnl_lookup(struct net *net, int link
cand = t;
}
- hash = HASH(remote, &any);
+ hash = HASH(&any);
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
!ipv6_addr_any(&t->parms.laddr) ||
@@ -194,7 +213,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
prio = 1;
- h = HASH(remote, local);
+ h = HASH(local);
}
return &ip6n->tnls[prio][h];
}
@@ -376,6 +395,12 @@ ip6_tnl_dev_uninit(struct net_device *de
struct net *net = t->net;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ while (t->parms.fmrs) {
+ struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
+ kfree(t->parms.fmrs);
+ t->parms.fmrs = next;
+ }
+
if (dev == ip6n->fb_tnl_dev)
RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
else
@@ -788,6 +813,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
}
EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
+/**
+ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR
+ * @dest: destination IPv6 address buffer
+ * @skb: received socket buffer
+ * @fmr: MAP FMR
+ * @xmit: Calculate for xmit or rcv
+ **/
+static void ip4ip6_fmr_calc(struct in6_addr *dest,
+ const struct iphdr *iph, const uint8_t *end,
+ const struct __ip6_tnl_fmr *fmr, bool xmit)
+{
+ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len);
+ u8 *portp = NULL;
+ bool use_dest_addr;
+ const struct iphdr *dsth = iph;
+
+ if ((u8*)dsth >= end)
+ return;
+
+ /* find significant IP header */
+ if (iph->protocol == IPPROTO_ICMP) {
+ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
+ if (ih && ((u8*)&ih[1]) <= end && (
+ ih->type == ICMP_DEST_UNREACH ||
+ ih->type == ICMP_SOURCE_QUENCH ||
+ ih->type == ICMP_TIME_EXCEEDED ||
+ ih->type == ICMP_PARAMETERPROB ||
+ ih->type == ICMP_REDIRECT))
+ dsth = (const struct iphdr*)&ih[1];
+ }
+
+ /* in xmit-path use dest port by default and source port only if
+ this is an ICMP reply to something else; vice versa in rcv-path */
+ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph);
+
+ /* get dst port */
+ if (((u8*)&dsth[1]) <= end && (
+ dsth->protocol == IPPROTO_UDP ||
+ dsth->protocol == IPPROTO_TCP ||
+ dsth->protocol == IPPROTO_SCTP ||
+ dsth->protocol == IPPROTO_DCCP)) {
+ /* for UDP, TCP, SCTP and DCCP source and dest port
+ follow IPv4 header directly */
+ portp = ((u8*)dsth) + dsth->ihl * 4;
+
+ if (use_dest_addr)
+ portp += sizeof(u16);
+ } else if (iph->protocol == IPPROTO_ICMP) {
+ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
+
+ /* use icmp identifier as port */
+ if (((u8*)&ih) <= end && (
+ (use_dest_addr && (
+ ih->type == ICMP_ECHOREPLY ||
+ ih->type == ICMP_TIMESTAMPREPLY ||
+ ih->type == ICMP_INFO_REPLY ||
+ ih->type == ICMP_ADDRESSREPLY)) ||
+ (!use_dest_addr && (
+ ih->type == ICMP_ECHO ||
+ ih->type == ICMP_TIMESTAMP ||
+ ih->type == ICMP_INFO_REQUEST ||
+ ih->type == ICMP_ADDRESS)
+ )))
+ portp = (u8*)&ih->un.echo.id;
+ }
+
+ if ((portp && &portp[2] <= end) || psidlen == 0) {
+ int frombyte = fmr->ip6_prefix_len / 8;
+ int fromrem = fmr->ip6_prefix_len % 8;
+ int bytes = sizeof(struct in6_addr) - frombyte;
+ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr;
+ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len);
+ u64 t = 0;
+
+ /* extract PSID from port and add it to eabits */
+ u16 psidbits = 0;
+ if (psidlen > 0) {
+ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]);
+ psidbits >>= 16 - psidlen - fmr->offset;
+ psidbits = (u16)(psidbits << (16 - psidlen));
+ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen));
+ }
+
+ /* rewrite destination address */
+ *dest = fmr->ip6_prefix;
+ memcpy(&dest->s6_addr[10], addr, sizeof(*addr));
+ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen));
+
+ if (bytes > sizeof(u64))
+ bytes = sizeof(u64);
+
+ /* insert eabits */
+ memcpy(&t, &dest->s6_addr[frombyte], bytes);
+ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1)
+ << (64 - fmr->ea_len - fromrem));
+ t = cpu_to_be64(t | (eabits >> fromrem));
+ memcpy(&dest->s6_addr[frombyte], &t, bytes);
+ }
+}
+
+
static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
const struct tnl_ptk_info *tpi,
struct metadata_dst *tun_dst,
@@ -855,6 +981,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+ if (tpi->proto == htons(ETH_P_IP) && tunnel->parms.fmrs &&
+ !ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) {
+ /* Packet didn't come from BR, so lookup FMR */
+ struct __ip6_tnl_fmr *fmr;
+ struct in6_addr expected = tunnel->parms.raddr;
+ for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next)
+ if (ipv6_prefix_equal(&ipv6h->saddr,
+ &fmr->ip6_prefix, fmr->ip6_prefix_len))
+ break;
+
+ /* Check that IPv6 matches IPv4 source to prevent spoofing */
+ if (fmr)
+ ip4ip6_fmr_calc(&expected, ip_hdr(skb),
+ skb_tail_pointer(skb), fmr, false);
+
+ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) {
+ rcu_read_unlock();
+ goto drop;
+ }
+ }
+
__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
@@ -1002,6 +1149,7 @@ static void init_tel_txopt(struct ipv6_t
opt->ops.opt_nflen = 8;
}
+
/**
* ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
* @t: the outgoing tunnel device
@@ -1292,6 +1440,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
u8 protocol)
{
struct ip6_tnl *t = netdev_priv(dev);
+ struct __ip6_tnl_fmr *fmr;
struct ipv6hdr *ipv6h;
const struct iphdr *iph;
int encap_limit = -1;
@@ -1391,6 +1540,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield);
+ /* try to find matching FMR */
+ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
+ unsigned mshift = 32 - fmr->ip4_prefix_len;
+ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift ==
+ ntohl(ip_hdr(skb)->daddr) >> mshift)
+ break;
+ }
+
+ /* change dstaddr according to FMR */
+ if (fmr)
+ ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true);
+
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
return -1;
@@ -1543,6 +1704,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
t->parms.link = p->link;
t->parms.proto = p->proto;
t->parms.fwmark = p->fwmark;
+
+ while (t->parms.fmrs) {
+ struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
+ kfree(t->parms.fmrs);
+ t->parms.fmrs = next;
+ }
+ t->parms.fmrs = p->fmrs;
+
dst_cache_reset(&t->dst_cache);
ip6_tnl_link_config(t);
}
@@ -1577,6 +1746,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
p->flowinfo = u->flowinfo;
p->link = u->link;
p->proto = u->proto;
+ p->fmrs = NULL;
memcpy(p->name, u->name, sizeof(u->name));
}
@@ -1964,6 +2134,15 @@ static int ip6_tnl_validate(struct nlatt
return 0;
}
+static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = {
+ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) },
+ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) },
+ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 },
+ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 },
+ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 },
+ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 }
+};
+
static void ip6_tnl_netlink_parms(struct nlattr *data[],
struct __ip6_tnl_parm *parms)
{
@@ -2001,6 +2180,46 @@ static void ip6_tnl_netlink_parms(struct
if (data[IFLA_IPTUN_FWMARK])
parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
+
+ if (data[IFLA_IPTUN_FMRS]) {
+ unsigned rem;
+ struct nlattr *fmr;
+ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) {
+ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c;
+ struct __ip6_tnl_fmr *nfmr;
+
+ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX,
+ fmr, ip6_tnl_fmr_policy, NULL);
+
+ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL)))
+ continue;
+
+ nfmr->offset = 6;
+
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX]))
+ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX],
+ sizeof(nfmr->ip6_prefix));
+
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX]))
+ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX],
+ sizeof(nfmr->ip4_prefix));
+
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN]))
+ nfmr->ip6_prefix_len = nla_get_u8(c);
+
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN]))
+ nfmr->ip4_prefix_len = nla_get_u8(c);
+
+ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN]))
+ nfmr->ea_len = nla_get_u8(c);
+
+ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET]))
+ nfmr->offset = nla_get_u8(c);
+
+ nfmr->next = parms->fmrs;
+ parms->fmrs = nfmr;
+ }
+ }
}
static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
@@ -2084,6 +2303,12 @@ static void ip6_tnl_dellink(struct net_d
static size_t ip6_tnl_get_size(const struct net_device *dev)
{
+ const struct ip6_tnl *t = netdev_priv(dev);
+ struct __ip6_tnl_fmr *c;
+ int fmrs = 0;
+ for (c = t->parms.fmrs; c; c = c->next)
+ ++fmrs;
+
return
/* IFLA_IPTUN_LINK */
nla_total_size(4) +
@@ -2113,6 +2338,24 @@ static size_t ip6_tnl_get_size(const str
nla_total_size(0) +
/* IFLA_IPTUN_FWMARK */
nla_total_size(4) +
+ /* IFLA_IPTUN_FMRS */
+ nla_total_size(0) +
+ (
+ /* nest */
+ nla_total_size(0) +
+ /* IFLA_IPTUN_FMR_IP6_PREFIX */
+ nla_total_size(sizeof(struct in6_addr)) +
+ /* IFLA_IPTUN_FMR_IP4_PREFIX */
+ nla_total_size(sizeof(struct in_addr)) +
+ /* IFLA_IPTUN_FMR_EA_LEN */
+ nla_total_size(1) +
+ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */
+ nla_total_size(1) +
+ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */
+ nla_total_size(1) +
+ /* IFLA_IPTUN_FMR_OFFSET */
+ nla_total_size(1)
+ ) * fmrs +
0;
}
@@ -2120,6 +2363,9 @@ static int ip6_tnl_fill_info(struct sk_b
{
struct ip6_tnl *tunnel = netdev_priv(dev);
struct __ip6_tnl_parm *parm = &tunnel->parms;
+ struct __ip6_tnl_fmr *c;
+ int fmrcnt = 0;
+ struct nlattr *fmrs;
if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
@@ -2129,9 +2375,27 @@ static int ip6_tnl_fill_info(struct sk_b
nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
- nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark))
+ nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) ||
+ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS)))
goto nla_put_failure;
+ for (c = parm->fmrs; c; c = c->next) {
+ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt);
+ if (!fmr ||
+ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX,
+ sizeof(c->ip6_prefix), &c->ip6_prefix) ||
+ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX,
+ sizeof(c->ip4_prefix), &c->ip4_prefix) ||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) ||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) ||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) ||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset))
+ goto nla_put_failure;
+
+ nla_nest_end(skb, fmr);
+ }
+ nla_nest_end(skb, fmrs);
+
if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) ||
nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) ||
nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) ||
@@ -2171,6 +2435,7 @@ static const struct nla_policy ip6_tnl_p
[IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
[IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
[IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
+ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED },
};
static struct rtnl_link_ops ip6_link_ops __read_mostly = {

View file

@ -0,0 +1,263 @@
From: Jonas Gorski <jogo@openwrt.org>
Subject: ipv6: allow rejecting with "source address failed policy"
RFC6204 L-14 requires rejecting traffic from invalid addresses with
ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
egress policy) on the LAN side, so add an appropriate rule for that.
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
include/net/netns/ipv6.h | 1 +
include/uapi/linux/fib_rules.h | 4 +++
include/uapi/linux/rtnetlink.h | 1 +
net/ipv4/fib_semantics.c | 4 +++
net/ipv4/fib_trie.c | 1 +
net/ipv4/ipmr.c | 1 +
net/ipv6/fib6_rules.c | 4 +++
net/ipv6/ip6mr.c | 2 ++
net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++-
9 files changed, 75 insertions(+), 1 deletion(-)
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -86,6 +86,7 @@ struct netns_ipv6 {
unsigned int fib6_routes_require_src;
#endif
struct rt6_info *ip6_prohibit_entry;
+ struct rt6_info *ip6_policy_failed_entry;
struct rt6_info *ip6_blk_hole_entry;
struct fib6_table *fib6_local_tbl;
struct fib_rules_ops *fib6_rules_ops;
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -82,6 +82,10 @@ enum {
FR_ACT_BLACKHOLE, /* Drop without notification */
FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
FR_ACT_PROHIBIT, /* Drop with EACCES */
+ FR_ACT_RES9,
+ FR_ACT_RES10,
+ FR_ACT_RES11,
+ FR_ACT_POLICY_FAILED, /* Drop with EACCES */
__FR_ACT_MAX,
};
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -265,6 +265,7 @@ enum {
RTN_THROW, /* Not in this table */
RTN_NAT, /* Translate this address */
RTN_XRESOLVE, /* Use external resolver */
+ RTN_POLICY_FAILED, /* Failed ingress/egress policy */
__RTN_MAX
};
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -145,6 +145,10 @@ const struct fib_prop fib_props[RTN_MAX
.error = -EINVAL,
.scope = RT_SCOPE_NOWHERE,
},
+ [RTN_POLICY_FAILED] = {
+ .error = -EACCES,
+ .scope = RT_SCOPE_UNIVERSE,
+ },
};
static void rt_fibinfo_free(struct rtable __rcu **rtp)
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2783,6 +2783,7 @@ static const char *const rtn_type_names[
[RTN_THROW] = "THROW",
[RTN_NAT] = "NAT",
[RTN_XRESOLVE] = "XRESOLVE",
+ [RTN_POLICY_FAILED] = "POLICY_FAILED",
};
static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -180,6 +180,7 @@ static int ipmr_rule_action(struct fib_r
case FR_ACT_UNREACHABLE:
return -ENETUNREACH;
case FR_ACT_PROHIBIT:
+ case FR_ACT_POLICY_FAILED:
return -EACCES;
case FR_ACT_BLACKHOLE:
default:
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -221,6 +221,10 @@ static int __fib6_rule_action(struct fib
err = -EACCES;
rt = net->ipv6.ip6_prohibit_entry;
goto discard_pkt;
+ case FR_ACT_POLICY_FAILED:
+ err = -EACCES;
+ rt = net->ipv6.ip6_policy_failed_entry;
+ goto discard_pkt;
}
tb_id = fib_rule_get_table(rule, arg);
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -170,6 +170,8 @@ static int ip6mr_rule_action(struct fib_
return -ENETUNREACH;
case FR_ACT_PROHIBIT:
return -EACCES;
+ case FR_ACT_POLICY_FAILED:
+ return -EACCES;
case FR_ACT_BLACKHOLE:
default:
return -EINVAL;
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -97,6 +97,8 @@ static int ip6_pkt_discard(struct sk_bu
static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+static int ip6_pkt_policy_failed(struct sk_buff *skb);
+static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb);
static void ip6_link_failure(struct sk_buff *skb);
static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb, u32 mtu,
@@ -317,6 +319,18 @@ static const struct rt6_info ip6_prohibi
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
};
+static const struct rt6_info ip6_policy_failed_entry_template = {
+ .dst = {
+ .__rcuref = RCUREF_INIT(1),
+ .__use = 1,
+ .obsolete = DST_OBSOLETE_FORCE_CHK,
+ .error = -EACCES,
+ .input = ip6_pkt_policy_failed,
+ .output = ip6_pkt_policy_failed_out,
+ },
+ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
+};
+
static const struct rt6_info ip6_blk_hole_entry_template = {
.dst = {
.__rcuref = RCUREF_INIT(1),
@@ -1037,6 +1051,7 @@ static const int fib6_prop[RTN_MAX + 1]
[RTN_BLACKHOLE] = -EINVAL,
[RTN_UNREACHABLE] = -EHOSTUNREACH,
[RTN_PROHIBIT] = -EACCES,
+ [RTN_POLICY_FAILED] = -EACCES,
[RTN_THROW] = -EAGAIN,
[RTN_NAT] = -EINVAL,
[RTN_XRESOLVE] = -EINVAL,
@@ -1072,6 +1087,10 @@ static void ip6_rt_init_dst_reject(struc
rt->dst.output = ip6_pkt_prohibit_out;
rt->dst.input = ip6_pkt_prohibit;
break;
+ case RTN_POLICY_FAILED:
+ rt->dst.output = ip6_pkt_policy_failed_out;
+ rt->dst.input = ip6_pkt_policy_failed;
+ break;
case RTN_THROW:
case RTN_UNREACHABLE:
default:
@@ -4539,6 +4558,17 @@ static int ip6_pkt_prohibit_out(struct n
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
}
+static int ip6_pkt_policy_failed(struct sk_buff *skb)
+{
+ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
+}
+
+static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb)
+{
+ skb->dev = skb_dst(skb)->dev;
+ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
+}
+
/*
* Allocate a dst for local (unicast / anycast) address.
*/
@@ -5030,7 +5060,8 @@ static int rtm_to_fib6_config(struct sk_
if (rtm->rtm_type == RTN_UNREACHABLE ||
rtm->rtm_type == RTN_BLACKHOLE ||
rtm->rtm_type == RTN_PROHIBIT ||
- rtm->rtm_type == RTN_THROW)
+ rtm->rtm_type == RTN_THROW ||
+ rtm->rtm_type == RTN_POLICY_FAILED)
cfg->fc_flags |= RTF_REJECT;
if (rtm->rtm_type == RTN_LOCAL)
@@ -6277,6 +6308,8 @@ static int ip6_route_dev_notify(struct n
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.ip6_prohibit_entry->dst.dev = dev;
net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
+ net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
+ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
#endif
@@ -6288,6 +6321,7 @@ static int ip6_route_dev_notify(struct n
in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
+ in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev);
in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
#endif
}
@@ -6488,6 +6522,8 @@ static int __net_init ip6_route_net_init
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.fib6_has_custom_rules = false;
+
+
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
sizeof(*net->ipv6.ip6_prohibit_entry),
GFP_KERNEL);
@@ -6498,11 +6534,21 @@ static int __net_init ip6_route_net_init
ip6_template_metrics, true);
INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached);
+ net->ipv6.ip6_policy_failed_entry =
+ kmemdup(&ip6_policy_failed_entry_template,
+ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
+ if (!net->ipv6.ip6_policy_failed_entry)
+ goto out_ip6_prohibit_entry;
+ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
+ ip6_template_metrics, true);
+ INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->dst.rt_uncached);
+
net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
sizeof(*net->ipv6.ip6_blk_hole_entry),
GFP_KERNEL);
if (!net->ipv6.ip6_blk_hole_entry)
- goto out_ip6_prohibit_entry;
+ goto out_ip6_policy_failed_entry;
net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
ip6_template_metrics, true);
@@ -6529,6 +6575,8 @@ out:
return ret;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+out_ip6_policy_failed_entry:
+ kfree(net->ipv6.ip6_policy_failed_entry);
out_ip6_prohibit_entry:
kfree(net->ipv6.ip6_prohibit_entry);
out_ip6_null_entry:
@@ -6548,6 +6596,7 @@ static void __net_exit ip6_route_net_exi
kfree(net->ipv6.ip6_null_entry);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
kfree(net->ipv6.ip6_prohibit_entry);
+ kfree(net->ipv6.ip6_policy_failed_entry);
kfree(net->ipv6.ip6_blk_hole_entry);
#endif
dst_entries_destroy(&net->ipv6.ip6_dst_ops);
@@ -6631,6 +6680,9 @@ void __init ip6_route_init_special_entri
init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
+ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
+ in6_dev_get(init_net.loopback_dev);
#endif
}

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